Repository navigation
chore(git): ignore .Codex/, where Codex puts its worktrees - #601
Conversation
The project's rule puts every worktree at .claude/worktrees/<name>/, which .gitignore already covers. Codex uses .Codex/worktrees/ instead, and that path was tracked: reviewing PR #600 found a 60-entry checkout sitting there, one `git add -A` away from being committed. Verified with a probe file under .Codex/worktrees/: untracked before, matched by the rule after (`git check-ignore -v` names .gitignore:66). Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH
|
ZETETIC-REVIEW: APPROVE Reviewed 8ccdb27 from a detached worktree at Stakes (Move 7)Low. One repository-config file, five added lines, no source, no public surface, no security path, no test impact. Moves 1, 3 and 6 still run, since they run at every stakes level. Moves 2, 4 and 5 are informal here because there is no unit to audit. Move 0, ledger and seen-defect checkThe diff has exactly one path: a One scope statement in the body ("It does not move the worktree, which is the owner's call") reads like a deferral, so I checked whether it dismisses a defect this diff touches. It does not. Where Codex writes its worktrees is host-tool configuration outside the repository tree, unreachable from this diff and from every check it ran, and the author names the deferral rather than hiding it. Not a section 14 bypass. There is a related note below under Non-blocking. Verification, re-run independently rather than taken from the PR body
Moves 1, 3 and 6Layer boundary: no import and no module, so nothing applies. Wiring and contract drift: no symbol added, renamed or deleted, and no caller to update; no commented-out code, no untracked TODO, no debug statement. Security and hygiene: no secret, no PII, no binary, no generated file; conventional commit ( Adversarial pass, four apertures, all examinedOver-fit: the pattern is unanchored, so it matches a Missed cases: the intended path Robustness: an already-tracked file under Test adequacy: there is no automated test, and none is warranted. The rule's behaviour is a single No blocking finding at any aperture. Non-blocking
The deferral "it does not move the worktree" is a sound scope call, but the underlying condition, a worktree living outside the path the project rule names, is now invisible to VerdictAPPROVE. The diff does what it says, its own commit message is reproducible down to the line number, it widens nothing that is tracked, |
…sourced to what names it ADR-0693 records why the Codex plugin starts lean: the full surface is the largest fixed token cost a session pays, not a startup-time limit. The worktree row cites docs/agent-guidance.md for the Claude Code directory only; the Codex directory is observed behaviour that #601 gitignored. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH
…and Codex (#603) * docs(readme): predictions and calibration, one store for Claude Code and Codex The README described what Cortex remembers and never that it can record what it expected (#597, ADR-1076): a section under "Keep context useful" shows predict, resolve_prediction and calibration with their real return shapes and says what the Brier score means against the 0.25 of a constant 0.5 forecast. The host table gains the row, and the Codex paragraph says the plugin reads the same saved backend selection as the Claude launcher (#600). The unreleased changelog had two "### Added" headings; one now. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH * docs(readme): one column per host in the capability table Codex was folded into "local stdio hosts" although its plugin starts the server with --profile lean (ten named tools, no hooks) while a direct codex mcp add gets the full surface. The table now has a column for each, says which tools lean lacks (predictions, wiki writes, ingestion), where the shared backend selection lives (#600), and which worktree directory doctor checks per host. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH * docs(readme): the calibration band the code can return, and the release hedge for Codex BAND_EDGES steps by 0.2, so the illustrative reliability row shows [0.6, 0.8]. The Codex paragraph names CORTEX_BACKEND between the two variables it already named and says the shared backend selection reaches the plugin with the release after 4.22.0, since the plugin launches the published package. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH * docs(readme): the worktree row states the convention, not a doctor check The doctor check for worktree locations is PR #602, not merged. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH * docs(readme): the lean profile's real reason, and each worktree cell sourced to what names it ADR-0693 records why the Codex plugin starts lean: the full surface is the largest fixed token cost a session pays, not a startup-time limit. The worktree row cites docs/agent-guidance.md for the Claude Code directory only; the Codex directory is observed behaviour that #601 gitignored. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH --------- Co-authored-by: Claude Fable 5.1 <[email protected]>
… (ADR-1078) .gitignore's .Codex/ rule (#601) was unanchored, matching a .Codex directory at any depth instead of just the repo root. Anchor to /.Codex/. The condition that rule hid: a git worktree living outside .claude/worktrees/, the only location docs/agent-guidance.md:160-166 names, stays where the owner decided it stays, but is now reported rather than silenced. mcp_server/doctor.py gains an optional, non-blocking "worktree locations" check (surfaced through python -m mcp_server.doctor, check_setup, and /preflight) that lists any git worktree list --porcelain entry outside <main-worktree>/.claude/worktrees/. The allowed root is derived from the main worktree's own listing (always first, per git-worktree(1) section list) rather than git rev-parse --show-toplevel, which resolves to a linked worktree's own path and would false-positive on every sibling worktree run from inside one. Decision recorded as ADR-1078. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH
… (ADR-1078) (#602) * fix(gitignore): anchor .Codex/ to repo root, report outside worktrees (ADR-1078) .gitignore's .Codex/ rule (#601) was unanchored, matching a .Codex directory at any depth instead of just the repo root. Anchor to /.Codex/. The condition that rule hid: a git worktree living outside .claude/worktrees/, the only location docs/agent-guidance.md:160-166 names, stays where the owner decided it stays, but is now reported rather than silenced. mcp_server/doctor.py gains an optional, non-blocking "worktree locations" check (surfaced through python -m mcp_server.doctor, check_setup, and /preflight) that lists any git worktree list --porcelain entry outside <main-worktree>/.claude/worktrees/. The allowed root is derived from the main worktree's own listing (always first, per git-worktree(1) section list) rather than git rev-parse --show-toplevel, which resolves to a linked worktree's own path and would false-positive on every sibling worktree run from inside one. Decision recorded as ADR-1078. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH * fix(doctor): split _worktree_locations to clear the craftsmanship method-size gate CI's craftsmanship gate job was red on 217ec1f: _worktree_locations spanned 51 lines (end_lineno - lineno), over the 40-line method cap (scripts/craftsmanship_rules.py METHOD_LINE_LIMIT). Split the classification logic into _worktree_classification(entries) -> (ok, detail), leaving _worktree_locations as a short orchestrator that turns the tuple into a Check. Same behavior, same tests. python scripts/check_craftsmanship.py --base origin/main -> Craftsmanship gate: OK Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH * fix(doctor): honor host worktree roots and preserve Git paths (#602) * test(doctor): verify worktree signals and report unavailable inspection (#602) * fix(doctor): a project without git is not a failed inspection (#602) _worktree_locations() treated every failure mode of `git worktree list` (no repository, git missing, timeout) as the same "inspection unavailable" WARN. Cortex is an MCP server whose cwd is whatever project the host opened; a project with no Git repository is ordinary, not a failure to inspect, so every such session's preflight showed a WARN whose fix command (`git worktree list --porcelain -z`) can never succeed there. `run_with_hard_timeout` collapses every subprocess failure mode to `None`, so the two cases can't be told apart after the call. A new `_is_git_checkout()` stdlib probe runs first instead — the same upward walk for a `.git` entry that Git itself performs to discover a repository, no subprocess involved. No `.git` anywhere up the tree now reports `ok True, detail "not a git checkout"`; a `.git` present but Git missing from PATH or the listing timing out keeps the optional WARN. Renamed test_not_a_git_checkout_warns to test_not_a_git_checkout_passes (now asserts the ok True case) and added test_git_unavailable_in_a_checkout_warns for the WARN case with a real .git present. Updated the parametrised None case in test_unavailable_or_empty_listing_contract, whose message no longer claims "not a Git checkout" as a possible cause since that case now short-circuits before the subprocess call. ADR-1079's Consequences section records the distinction. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH --------- Co-authored-by: Claude Sonnet 5 <[email protected]>
Summary
The project's standing rule puts every git worktree at
.claude/worktrees/<name>/, a path.gitignorealready covers. Codex uses.Codex/worktrees/instead, and nothing ignored it: reviewing PR #600 found a sixty-entry checkout sitting at.Codex/worktrees/shared-host-decisions, tracked by nothing and onegit add -Aaway from being committed into the repository.This ignores
.Codex/. It does not move the worktree, which is the owner's call and unrelated to whether the path can be committed by accident.Type of change
Test plan
.Codex/worktrees/probe/file.txtin this worktree:git status --porcelain --untracked-files=alllists zero.Codexentries, andgit check-ignore -vnames.gitignore:66as the matching rule. Removed the probe afterwards.Audit notes
.claude/*block, with the observation that produced it, so the next reader knows which tool creates that path and why it is ignored rather than moved.Coding-standards compliance
Breaking changes
None. A path that was never tracked stops being offered as untracked.
Reviewer checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH