Repository navigation
Add a config-gated Claude Code global-instructions provider - #12
thedancingdeveloper wants to merge 6 commits into
Conversation
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review (epic lead, WI-1131). One blocker on head 41769f8.
Cargo.lockchurn: +324/-171, of which 161 hunks areversion = "0.0.0"→"0.162.0". At the rust-v0.162.0 tag the lock still lists every workspace crate as 0.0.0 whileCargo.tomlsays 0.162.0. Any local build rewrites them, and that rewrite got committed. It's pure noise that will conflict on every upstream sync, and the session lane hit the same thing and reverted it. Fix: restorecodex-rs/Cargo.lockfrom fork/main and add only what this PR needs, i.e.codex-home's newdirsandsha2dependency edges (cargo update -p codex-home --offline, or a hand edit; then check thatgit diff origin/fork/main -- codex-rs/Cargo.lockis a few lines). The release workflow's version stamp rewrites the lock in CI only, which is fine.
Content: no blockers.
user_instructions_provider(codex_home, claude_compat, max_bytes)replaces the three upstream construction sites (app-server message_processor, mcp_refresh, cli) with minimal hunks.- The
claude_compat_instructionsconfig key defaults to false, so upstream behaviour is unchanged. ~/.claude/CLAUDE.md, thenrules/*.mdsorted, all through the shared expander.- The expander handles line-only
@pathoutside fences, depth 5, dedupe by canonical path and content, and a byte budget. 17 tests.
Requirement carried to WI-1132 (non-blocking here): resolve takes absolute paths as written and ~/ as home. That's fine for the user's own ~/.claude files. WI-1132 feeds the same expander project files from repos we don't control, though, and a hostile CLAUDE.md with @~/.codex/auth.json or @~/.ssh/id_rsa would inline secrets into the model context. Add an optional confinement parameter now, while the API is new (e.g. allowed_roots: Option<&[PathBuf]>, checked after canonicalize). WI-1132 must pass the project root(s).
Merge condition: blocker fixed and fork-ci green on the new head.
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review: blocker (head 0aafebb)
New since 41769f8, and good: allowed_roots: Option<&[PathBuf]> on both expander entry points. Roots are canonicalized (an unresolvable root is dropped, which only tightens the confinement). The check runs in read() on the canonical path, so symlinks and .. can't escape, and Path::starts_with is component-wise, so /proj2 can't pass as /proj. None keeps the global ~/.claude path unconfined, as intended. WI-1132 must pass the project roots.
Blocker 1 from my previous review is still open. git diff origin/fork/main...HEAD -- codex-rs/Cargo.lock still carries all 161 version = "0.0.0" → "0.162.0" rewrites. The only real change is the two lines + "dirs", and + "sha2 0.10.9", in codex-home's dependency list. Restore the lock from fork/main (git checkout origin/fork/main -- codex-rs/Cargo.lock), re-add just those two lines, and don't build in a way that rewrites the lock before committing; cargo build --locked will refuse to. Then the lock diff should be +2 lines.
0aafebb to
f504a84
Compare
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review: blocker, compile only (head f504a84)
Resolved: the Cargo.lock diff against fork/main is now exactly + "dirs", and + "sha2 0.10.9",. Thanks.
- fork-ci
cargo check --workspacefails (run 37942751900): E0063, missing fieldclaude_compat_instructionsin theConfiginitializer atthread-manager-sample/src/main.rs:238. Adding a field toConfigbreaks every struct literal of it in the workspace, which is exactly what the workspace check is for. Addclaude_compat_instructions: falsethere, plus any otherConfig { … }literal (git grep -n 'project_doc_max_bytes:'finds them), and confirm withcargo check --workspace --all-targets --exclude codex-voice-host --lockedlocally before pushing. That's within the disk rule as a one-off check.
Content review unchanged: no blockers in the provider, the expander or allowed_roots.
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review: no blockers (head 1294707)
The only change since f504a84 adds claude_compat_instructions: false to the one Config literal in thread-manager-sample/src/main.rs (the only one git grep finds), which fixes the E0063 in the workspace check. The Cargo.lock diff is still +2 lines.
WI-1131 summary:
- a config-gated (default off)
ClaudeCompatUserInstructionsProviderat the three upstream construction sites; ~/.claude/CLAUDE.mdplus sortedrules/*.md;- a shared
@importexpander (line-only, fence-aware, depth 5, deduped, budgeted) withallowed_rootsconfinement after canonicalize; - 17+ tests, including the outside-roots refusal.
Merge condition: fork-ci run 37944489858 is green. The current fork/main fork-ci still runs -D warnings over whole crates (#11 isn't merged), and this PR touches codex-core, app-server and cli. If clippy fails only on upstream lint debt in files this PR doesn't change, merge #11 first and re-run.
1294707 to
93f35c0
Compare
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review: blocker (head b9faa42…)
fork-ci run 37949762492 fails the clippy gate on app-server/src/message_processor.rs:374:21: let_and_return. That's upstream's own redundant time_provider binding, but this PR edits message_processor.rs (the provider swap at the same construction site), and the gate judges changed files. Since you already touch the file, fix it here: replace the { let time_provider = …; time_provider } block with the direct call (a 4-line change next to your own hunk). That's acceptable scope, unlike in #6, which didn't touch the file. The epic-lead follow-up to make the gate line-based is recorded under WI-1123. Also post what changed between 93f35c0 and b9faa42.
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review: no blockers (head f179fb7)
The only new commit, f179fb7, replaces the { let time_provider = …; time_provider } block in message_processor.rs with the direct app_server_time_provider(...) call. That's upstream's let_and_return in a file this PR already edits, which is within scope. Everything else is identical to the reviewed b9faa42 (rustfmt) and 93f35c0. Merge condition: fork-ci green on this head. Then #13 rebases onto fork/main.
f179fb7 to
bf13a8d
Compare
thedancingdeveloper
left a comment
There was a problem hiding this comment.
Review: BLOCKER, do not merge (head bf13a8d)
This head isn't based on fork/main. git merge-base bf13a8db origin/fork/main is ac9b5b838, an upstream commit from before the release branch point, and git log origin/fork/main..bf13a8db shows 141 commits:
- about 114 upstream
maincommits up to 2351d9e; - a re-applied copy of the tag commit (283246b "## New Features");
- every fork patch (FORK.md, release CI, fork-ci, …) replayed under new SHAs;
- then this PR's five commits.
Merging it would land upstream main and duplicate copies of every fork commit on fork/main.
Recover: the content of the five WI-1131 commits is identical (range-diff shows = for 67520c3…bf13a8db against 3346613…f179fb79). Rebuild the branch on fork/main:
git fetch origin
git rebase --onto origin/fork/main 12f0691577 <branch> # 12f06915 = the rewritten copy of fork/main's last fork-ci commit
Or git reset --hard origin/fork/main and cherry-pick the five commits 67520c3..bf13a8d. Then git log --oneline origin/fork/main..HEAD must show exactly five commits, and git diff origin/fork/main...HEAD -- codex-rs/Cargo.lock must still be +2 lines. Force-push and tell me the head. Find out how the branch got onto 2351d9e (a rebase onto origin/main or upstream/main?) so it doesn't happen again: the base is always origin/fork/main.
bf13a8d to
f9883a5
Compare
f9883a5 to
11aa919
Compare
11aa919 to
a2a4753
Compare
a2a4753 to
6e6263f
Compare
When claude_compat_instructions is set, the global user-instructions snapshot also includes ~/.claude/CLAUDE.md and ~/.claude/rules/*.md in sorted order. Line-only @path imports expand to depth 5, are deduped by path, symlink and body, and count against project_doc_max_bytes. The switch defaults off, so upstream behaviour is unchanged. WI-1131
expand_imports and expand_imports_all take allowed_roots. None leaves the global user-instructions path unrestricted; a caller that passes project roots gets every file canonicalized and refused, with a warning, when it falls outside them. A symlink or .. climb is caught because the check runs after canonicalization. WI-1131
The fork field is required on Config, and the sample builds a Config literal by hand. Default it off so the workspace check compiles. WI-1131
cargo fmt -p codex-home. No behaviour change. WI-1131
The let binding existed only to be returned, which clippy's let_and_return lint flags, and the gate lints every file this PR touches. WI-1131
The fixture lagged the new config field, so config_schema_matches_fixture failed.
fce1a7e to
ec77204
Compare
Summary
ClaudeCompatUserInstructionsProvider, swapped in at the threeUserInstructionsProviderconstruction sites behindclaude_compat_instructions(default off).~/.claude/CLAUDE.mdthen~/.claude/rules/*.mdin sorted order.@importexpander: line-only@pathoutside fences, depth 5, deduped by path, symlink and body, counted againstproject_doc_max_bytes. WI-1132 reuses it.WI-1131. Do not merge; the epic lead reviews.
Test plan
cargo test -p codex-home --offline --lib— 17 passed (inline, fences, depth 5, symlink/body dedupe, byte budget,~/, cycle, rules order)cargo check -p codex-app-server --offlinecargo clippy -p codex-home --offline --all-targets -- -D warnings