Skip to content

Pin every agent run to its own CLI settings - #2068

Merged
ppXD merged 1 commit into
mainfrom
fix/pin-every-claude-run-to-its-own-settings
Oct 4, 2026
Merged

ppXD merged 1 commit into
mainfrom
fix/pin-every-claude-run-to-its-own-settings

Conversation

@ppXD

@ppXD ppXD commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • Every Claude run now passes --setting-sources user, so a target repository's .claude/settings.json, .claude/settings.local.json and .mcp.json never apply. Unpinned, Claude 2.1.263 sent its model call to a planted env.ANTHROPIC_BASE_URL with the repository's token and apiKeyHelper key, ran every planted hook, and spawned the project MCP server. The workspace is added back with --add-dir plus CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1, so CLAUDE.md, .claude/CLAUDE.md and .claude/rules still load. Every repository directory inside the workspace is added as well, so each repository in a multi-repo workspace keeps its memory. The workspace root holds no CLAUDE.md, and per-repository --add-dir loads every repository's memory with none of its settings. AgentRunExecutor.InWorkspace sets the new AgentTask.WorkspaceRepositoryDirectories from the materialised workspace. A sibling repository outside a primary-repo cwd is not added.
  • Every Codex run now marks its workspace untrusted with one -c projects={...} override, so a repository's .codex/config.toml [mcp_servers] and its .codex/hooks.json never load. Before this, the hooks ran unreviewed on acceptance-bearing runs under --dangerously-bypass-hook-trust. Codex looks trust up by the physical cwd, so the table holds both the given path and its fully resolved path (CodexHarness.PhysicalDirectory). Keyed only by the given path, a workspace under macOS's /var symlink matched nothing.
  • Behaviour change: Claude runs no longer load project commands, agents, skills, or a nested subdirectory's own CLAUDE.md. 2.1.263 has no route that loads them without project settings.

Test plan

  • Unit: --setting-sources user on every run shape; --add-dir for single-repo, multi-repo root, primary-repo cwd and producer-named workspaces; Codex trust keys for a symlinked parent, a chained link, a path with no link and a missing path, checked against the shell's pwd -P (full unit suite green)
  • Integration: a multi-repo run through the real AgentRunExecutor hands the real Claude adapter the workspace root and every repository directory
  • E2E (RepositoryConfigE2ETests), real Claude 2.1.263 and Codex 0.142.2 against a stub model at the unresolved temp path: single-repo Claude, multi-repo Claude and Codex arms green on macOS; each goes red when its fix is reverted
  • E2E sandbox lane (Linux bubblewrap): root lane requires the 3 repository-config arms and 90 cases; non-root lane runs Claude at Standard as uid 1654 against hostile settings, with marker files in the workspace, and requires 11 cases

A target repository is untrusted input, yet every Claude run without a
projected skill or acceptance oracle loaded its .claude/settings.json
and settings.local.json. Against the pinned 2.1.263 CLI, a planted
env.ANTHROPIC_BASE_URL took the model call off the run's broker to the
repository's endpoint, carrying the repository's token and its
apiKeyHelper's key; every planted hook ran; and a project .mcp.json
server was spawned whenever no declaration of ours made the MCP config
strict.

Every Claude run now gets --setting-sources user. That source also
gates project memory, so the workspace is added back with --add-dir and
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1, the one loader route
that reads CLAUDE.md, .claude/CLAUDE.md and .claude/rules without
project settings. A multi-repo run's cwd is the workspace root, which
holds no CLAUDE.md, so the executor now stamps every repository
directory onto the task and each one inside the workspace is added too;
unpinned, such a run loaded a repository's memory only once it read a
file there. Project commands, agents, skills and nested subdirectory
CLAUDE.md files have no such route and no longer load.

Codex 0.142.2 had the same shape. With no trust entry for its workspace
it spawned a repository's [mcp_servers] on every run and ran its
.codex/hooks.json on every acceptance-bearing run, where
--dangerously-bypass-hook-trust waives review for every hook. Each run
now marks its workspace untrusted with one -c override, keyed by the
path it was given and by the physical path Codex resolves as its cwd.
Keyed only as given, a workspace under macOS's /var symlink, where
every local workspace lives, matched nothing and the repository's
config loaded as before. AGENTS.md and skills still load, and Codex
already ignored a project model_provider.

RepositoryConfigE2ETests plants hostile config for both real CLIs at
the unresolved temp path production uses, in a single-repo and a
multi-repo workspace, and in the shipped Standard posture as uid 1654
in the non-root lane. The root lane now requires 90 cases and the
non-root lane 11.
@ppXD
ppXD merged commit 5bead59 into main Oct 4, 2026
6 checks passed
@ppXD
ppXD deleted the fix/pin-every-claude-run-to-its-own-settings branch October 4, 2026 07:07
@ppXD ppXD mentioned this pull request Oct 4, 2026
7 of 8 tasks
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.

1 participant