Skip to content

coding-agent-kit becomes a standalone install (v0.2.0) - #1

Merged
FridrichMethod merged 8 commits into
mainfrom
feat/standalone
Oct 21, 2026
Merged

FridrichMethod merged 8 commits into
mainfrom
feat/standalone

Conversation

@FridrichMethod

@FridrichMethod FridrichMethod commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

The kit was extracted from dotfiles as a pure refactor and was still laid out like dotfiles' Stow packages, with hard-coded ~/.local/lib, ~/.secrets, ~/.codex, DOTFILES_COLOR and a --help pointer into ~/dotfiles. This makes it a wrapper anyone can install on top of an existing codex or claude, and gives dotfiles back its settings-sync engine.

Commits:

  • refactor: hand the AI config sync engine back to dotfiles: removes lib/config_sync.py, the four *-sync launchers, setup-sync, the tomlkit pin and their suites. The kit now needs only the Python 3.11+ standard library and Node.js 22+.
  • refactor: lay the kit out as bin, lib, completions and helpers: a pure git mv, with history and modes kept.
  • feat: self-locating launchers with an optional configuration file:
    • The launchers follow their own symlinks (a bounded readlink loop) to the kit root.
    • lib/coding-agent-kit/config.py reads one optional TOML file with four keys: codex, claude, codex_home and secrets_dir. It is checked for owner, group, other-write, ACLs and the directories on its path. Without a file, every default reproduces v0.1.0 byte for byte.
    • Adds --list-accounts and --show-config, and CODING_AGENT_KIT_COLOR.
  • feat: add install.sh, a standalone end-to-end test and a contract test:
    • install.sh refuses foreign paths, Stow links and folded directories.
    • tests/standalone-e2e.sh installs into temporary homes under /bin/sh, dash and bash.
    • tests/contract.sh pins the public paths, modes, CI job names and overlay files.
    • CI installs zsh and GNU Stow on Linux.
  • docs: describe coding-agent-kit as a standalone install: README, AGENTS, docs/configuration.md, and CHANGELOG 0.2.0 with an old-to-new path table.
  • fix: refuse claude-as account names that start with -: claude-as -x, -h or --version used to offer to enrol an account of that name. claude-as now refuses these names, as codex-as does, and prints codex-as's message for every invalid name. The exit status stays 1.
  • test: check directory ownership without group write: the first macOS CI run failed here. The case passed only where the runner's login group is a user private group; macOS users share staff.
  • test: make each bad-configuration case fail on its own error: found by a portability review. The "insecure secrets" case passed on the previous case's config error and never reached the 0700 check. A mutation that accepts 0755 now fails it.

Breaking changes (0.x minor): every launcher, library, completion and helper path moved; DOTFILES_COLOR is no longer read; the launchers no longer run ~/.local/lib/<tool>/; claude-as refuses account names starting with -. See CHANGELOG.md.

Testing:

  • Locally on Linux, in a lab with temporary homes:
    • every commit passes tests/run.sh --ci and pre-commit run --all-files;
    • gitleaks git is clean on the full history;
    • tests/run.ps1 runs under pwsh 7.6;
    • three rounds of adversarial review, with every confirmed finding fixed and pinned by a test;
    • a macOS/Bash 3.2/BSD portability review of the suites the first macOS run never reached: one confirmed finding (the second test commit), none macOS-specific.
  • CI on this PR: Linux, macOS system Bash 3.2 and native Windows pass at 38333d6.

The structured merge engine, its four *-sync launchers, setup-sync, the
tomlkit pin and their suites only ever served dotfiles' own settings
sync, and dotfiles now carries them again. Remove them here, along with
their hooks and the CI steps that provisioned the parser.

The kit now needs only the Python 3.11+ standard library and Node.js 22+.
The tree mirrored dotfiles' Stow packages (common/codex/.local/bin/...),
which only made sense while dotfiles stowed it directly. Move the
launchers to bin/, their Python modules to lib/<tool>/, the Bash and
zsh completions to completions/{bash,zsh}/ and the Claude Code helpers
to helpers/, keeping file modes and history, and point the tests and
hooks at the new paths. bin/.. has the same shape as a ~/.local prefix,
so the copy-installed test fixtures need no other change. Behaviour is
unchanged.
codex-as and claude-as no longer assume a dotfiles install. Each
launcher follows its own symlinks (a bounded readlink loop, no
readlink -f) to the kit root and runs lib/<tool>/launch.py there, so a
linked, copied or Stow-managed install all work, and an incomplete one
says so instead of failing with a traceback.

lib/coding-agent-kit/config.py reads one optional TOML file
(CODING_AGENT_KIT_CONFIG, else $XDG_CONFIG_HOME or ~/.config, then
coding-agent-kit/config.toml) for the codex and claude executables,
codex_home and secrets_dir. The file must be a regular file the user or
root owns that others cannot write; unknown keys only warn. Without a
file every default reproduces the old behaviour byte for byte, and it
is the only code that reads HOME.

New metadata queries --list-accounts (codex-as) and --show-config (both)
start nothing; the completions now ask the launchers for account names.
CODING_AGENT_KIT_COLOR replaces DOTFILES_COLOR, with NO_COLOR and
TERM=dumb still honoured, and --help names the configurable defaults and
points at the kit's own docs, or at GitHub for a lone copy.
install.sh links the launchers into PREFIX/bin (default ~/.local), the
Bash completions into the bash-completion user directory and the zsh
completions into PREFIX/share/zsh/site-functions, then prints the fpath
hint and the helper commands for Claude Code's settings.json. It treats
as its own only links whose text starts with the checkout's physical
path, the form it writes. Every other existing path, a relative link
such as Stow's included, is refused, and so is a destination reached
through a relative directory link (a Stow fold) or whose nearest
existing parent is not a writable directory; then nothing changes.
--uninstall removes only its own links, and nothing when it could not
remove them all.

tests/standalone-e2e.sh installs into temporary homes with no dotfiles,
under /bin/sh, dash and bash, and drives both launchers, their
completions and every configuration override through the installed
links against recording fakes, plus every refusal and uninstall case.
tests/contract.sh pins what consumers rely on: the public paths and
modes, the three CI job names and the overlay test files. CI installs
zsh and GNU Stow on Linux, and run.sh --ci now requires zsh instead of
skipping the zsh cases.
Rewrite README.md and AGENTS.md for a project anyone can install on top
of an existing Codex or Claude Code: requirements, install.sh, usage,
the Claude Code helpers, colour, tests, the public contract consumers
depend on, and release rules (tags are immutable; a patch tag reaches
dotfiles hosts within a day). docs/configuration.md documents the
optional config file, its permission rules and how to move codex_home
and secrets_dir before enrolling. The launcher docs name the
configurable paths and the new metadata queries, and CHANGELOG.md gets
the 0.2.0 entry with an old-to-new path table. tests/contract.sh now
pins docs/configuration.md too.
codex-as already refuses them, but claude-as took `claude-as -x`, `-h` or
`--version` as an account name and offered to enrol it. Every invalid name
now gets the codex-as message; the exit status stays 1.
Copilot AI balanced review requested due to automatic review settings October 21, 2026 04:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The last two cases of the directories-on-the-way test ran while ~/.config
and the configuration directory were still 0775 from the Ubuntu case and
without the user private group stand-in, so they passed only where the
runner's login group is private. On macOS, whose users share staff, the
loader rightly refused the group-writable directory. Make both 0755 first,
so only ownership decides.
The "insecure secrets" case kept the invalid configuration file of the case
before it, so every listing stopped at that error and the 0700 check on
the secrets directory was never reached. Remove that file first, and have
each case name what its one error line must say.
@FridrichMethod
FridrichMethod merged commit 38333d6 into main Oct 21, 2026
3 checks passed
@FridrichMethod
FridrichMethod deleted the feat/standalone branch October 21, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants