fix(dev): seed lab MCP approval into the worktree, not ~/.claude.json #71

Merged
dominik.polakovics merged 1 commit from fix/lab-afk-mcp-settings-local into main 2026-06-01 20:21:09 +02:00

Symptom

A lab AFK run still stalls at startup on New MCP server found in this project: nixos, even after #70 — reproduced live on the dev VM.

Root cause

#70 seeded enableAllProjectMcpServers into the worktree's project entry in ~/.claude.json. But claude (2.1.156) reads project MCP approval from the project-local .claude/settings.local.json, not the global config. That file is gitignored (via the global ~/.config/git/ignore), so a fresh worktree inherits the tracked .mcp.json but never the approval — and claude prompts with no one at the TTY to clear it.

The #70 commit message actually named the right file ("the gitignored .claude/settings.local.json that holds the human's MCP approval"); the code then wrote somewhere else. The ~/.claude.json flag is dead config for this purpose — present on the stuck worktree yet the prompt still showed.

Fix

SeedTrust now writes enableAllProjectMcpServers: true to <worktree>/.claude/settings.local.json (the file claude actually consults), creating/merging atomically. The folder-trust seed (hasTrustDialogAccepted) stays in ~/.claude.json — that part always worked (the worktree skips the trust dialog and goes straight to the MCP prompt). Being gitignored, the seeded file also stays out of the AFK agent's own commits.

Internals: split into seedFolderTrust + seedProjectMcpApproval over shared readJSONObject/marshalAtomic helpers.

Verification

  • go test ./... green; vet/build clean; pre-commit :: fw OK.
  • Controlled differential on claude 2.1.156: two identical project dirs with the same .mcp.json, neither with any ~/.claude.json entry — the one with .claude/settings.local.json reached the REPL silently; the one without showed the prompt. This is the check #70 lacked: its unit test passed, but the asserted config was one claude doesn't read.

Notes

  • A currently-stuck run won't retroactively unstick (claude already rendered the prompt); after deploy, new runs are seeded correctly.
  • No pre-commit guard can prove "claude honors our seeded config" without launching a live claude (auth + tmux + network), so that end-to-end validation stays manual.
## Symptom A lab AFK run still stalls at startup on `New MCP server found in this project: nixos`, even after #70 — reproduced live on the dev VM. ## Root cause #70 seeded `enableAllProjectMcpServers` into the worktree's project entry in `~/.claude.json`. But claude (2.1.156) reads project MCP approval from the **project-local** `.claude/settings.local.json`, *not* the global config. That file is gitignored (via the global `~/.config/git/ignore`), so a fresh worktree inherits the tracked `.mcp.json` but never the approval — and claude prompts with no one at the TTY to clear it. The #70 commit message actually named the right file ("the gitignored `.claude/settings.local.json` that holds the human's MCP approval"); the code then wrote somewhere else. The `~/.claude.json` flag is dead config for this purpose — present on the stuck worktree yet the prompt still showed. ## Fix `SeedTrust` now writes `enableAllProjectMcpServers: true` to `<worktree>/.claude/settings.local.json` (the file claude actually consults), creating/merging atomically. The folder-trust seed (`hasTrustDialogAccepted`) stays in `~/.claude.json` — that part always worked (the worktree skips the trust dialog and goes straight to the MCP prompt). Being gitignored, the seeded file also stays out of the AFK agent's own commits. Internals: split into `seedFolderTrust` + `seedProjectMcpApproval` over shared `readJSONObject`/`marshalAtomic` helpers. ## Verification - `go test ./...` green; `vet`/`build` clean; pre-commit `:: fw OK`. - **Controlled differential** on claude 2.1.156: two identical project dirs with the same `.mcp.json`, neither with any `~/.claude.json` entry — the one *with* `.claude/settings.local.json` reached the REPL silently; the one *without* showed the prompt. This is the check #70 lacked: its unit test passed, but the asserted config was one claude doesn't read. ## Notes - A currently-stuck run won't retroactively unstick (claude already rendered the prompt); after deploy, *new* runs are seeded correctly. - No pre-commit guard can prove "claude honors our seeded config" without launching a live claude (auth + tmux + network), so that end-to-end validation stays manual.
PR #70 wrote enableAllProjectMcpServers into the worktree's project entry in
~/.claude.json, but claude reads project MCP approval from the project-local
.claude/settings.local.json, not the global config. That file is gitignored, so
a fresh AFK worktree never has it and claude still stalled on the "New MCP server
found in this project" prompt — exactly the symptom #70 meant to remove.

Write enableAllProjectMcpServers to <worktree>/.claude/settings.local.json (the
file claude actually consults), keeping the working folder-trust seed in
~/.claude.json. Confirmed with a controlled differential on claude 2.1.156: a
project dir with that settings file reaches the REPL silently; an identical one
without it shows the prompt.

Refactor SeedTrust into seedFolderTrust + seedProjectMcpApproval over shared
readJSONObject/marshalAtomic helpers. Tests now use real temp dirs as the
worktree (SeedTrust writes inside dir) and assert MCP approval lands in
settings.local.json, with a guard that it is not written to the global config.
dominik.polakovics deleted branch fix/lab-afk-mcp-settings-local 2026-06-01 20:21:09 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/nixos!71
No description provided.