Repository navigation
[3374 by Claude Opus 5.5] 0.9.0 release logic fix: on launcher-managed installs, Claude agent containers run without ~/.claude.json, and after the first Claude run later runs fail with 'Claude configuration file not found at: /home/node/.claude.json / A backup file exists at:... - #3375
integry merged 1 commit into
Conversation
…nch, so nothing there already covered it.
What the Claude CLI actually does (checked against the installed 2.1.293):
- It replaces `.claude.json` with a temp file plus rename, so a shared read-write bind mount of the host file isn't safe.
- Before each save it copies the config into `~/.claude/backups` and keeps only the 5 newest. Agent containers share that directory, so they could delete the host login's own backups, not just add stub files.
- I reproduced the problem with the real CLI. A HOME that has a backup but no `.claude.json` prints the exact "configuration file not found / A backup file exists" error. With a seeded `{}` config it gets past that and stops only at "Not logged in", which is expected because the sandbox has no credentials. The run also wrote an 84-byte backup stub, the same as on your install.
Changes
1. Launcher (`docker/launcher/orchestrator.mjs`): `agentCredentialArgs` now mounts the host `.claude.json` read-only into the worker and api at the same host path, and sets `CLAUDE_JSON_PATH`. The file is the one next to `HOST_CLAUDE_DIR`, or `HOST_CLAUDE_JSON` if set.
- The derived file is mounted only if it exists. `HOST_CLAUDE_JSON` is always mounted, because a launcher running in a container can't see host files.
- The mount uses `--mount`, so a missing file makes the run fail instead of Docker creating a directory at the config's path.
- `validateEnv` checks the override.
2. Agent containers: a new `packages/core/src/claude/docker/claudeConfigSeed.ts` is used by both Claude docker-args builders (`dockerArgsBuilder.ts` and the older `claudeHelpers.ts`).
- The seed source is `CLAUDE_JSON_PATH`, falling back to `os.homedir()` as before. It is mounted read-only outside HOME.
- Before the entrypoint runs, the wrapper (both the repo-setup and workflow variants, as root) copies it into a private `~/.claude.json`. If there's no host file it writes `{}`. It never overwrites an existing config and never writes back to the host.
- `~/.claude/backups` is now a tmpfs private to each container, so host backups are never read, added to or pruned. `propr check --validate-agents` image runs get the same tmpfs.
3. `propr check`: a new "Agent config: claude (.claude.json)" row reports one of three states: mounted (OK), missing (warning, with a hint to run `claude` or set `HOST_CLAUDE_JSON`), or a bad override (fail).
4. Tests:
- `test/orchestratorClaudeConfig.test.mjs`: launcher args with the file, without it, with the override, and with commas in the path.
- `test/claudeConfigSeed.test.ts`: path selection, docker args, and the seed script run in bash, including the "backup exists, config missing" regression with the backups left untouched.
- A `checkCommands` test for the new row.
5. Docs: a 0.9.0 Fixed changelog bullet; `HOST_CLAUDE_JSON` added to the configuration reference, the launcher examples and the settings catalog, and the settings docs regenerated.
Validation: all of these pass:
- orchestrator tests (147)
- the Claude, docker-args, wrapper and workflow suites (251, plus 69 with 6 skipped)
- `npm run test:unit` (747)
- `npm run lint --workspaces --if-present -- --max-warnings 0`
- root lint and typecheck, CLI and core typecheck
- `release:verify` for v0.9.0
No test ran inside a real Docker agent container or a real `propr start` install, and Claude only ran on its own here.
Behaviour changes to know about:
- Dev and compose setups also stop sharing a read-write `~/.claude.json`. Changes an agent makes to it are now thrown away when the container exits.
- If the host user deletes `~/.claude.json` after ProPR starts, Claude runs fail on the mount until ProPR is restarted.
- If `~/.claude/backups` doesn't exist on the host, Docker creates it, owned by root, as the tmpfs mount point.
There are no visual previews, since the only user-facing change is a text row in `propr check`.
|
/review |
|
✅ AI Code Review Complete requested by @integry Posted 1 review: |
🔍 AI Code Review — codex:gpt-6-astraOverall EvaluationThe PR addresses the reported failure by seeding a private writable Claude config and isolating each container’s backups. Ready to merge within the visible scope, conditional on the pending Validate Changes check. ✅ Private configuration — Both Claude Docker argument builders use the shared seed helper, and both wrapper implementations initialize the config before entrypoint execution. ✅ Backup isolation — Per-container tmpfs mounts prevent agent runs from pruning the host’s backup directory. ✅ Focused coverage — Added tests cover source selection, launcher mounts, missing-config fallback, and preservation of existing configurations. The supplied issue description is truncated; this review covers its visible requirements and the complete supplied diff. No commands were run. Merge blockersNo merge blockers. SuggestionsThese are optional follow-ups and are not sent to S1: 🟢 Exercise real container lifecycleThe new tests verify generated arguments and execute the seed script, but do not exercise Docker’s nested tmpfs mount and subsequent privilege drop. An integration test running two successive containers against a directory containing host backups would strengthen regression coverage. This is optional; the supplied code does not demonstrate a failure in that path. S2: 🟢 Clarify optional launcher configurationThe launcher examples now unconditionally set ScoreThe implementation is focused and internally consistent, with relevant regression coverage and no verified code blockers. Current checks report 38 passes, no failures, and one pending check; actual container execution was not independently verified during this review. Score: 9/10 🤖 Review Details
Copy and edit to choose records from this review: 🤖 Review by ProPR |
AI Implementation Summary
Closes #3374
Branch:
3374/claude-opus-5-5-0-9-0-release-logic-fix-o-20261029-0906-3ubCommits: ✅ Changes committed (f7ef8e9)
AI Processing Completed
Execution Details:
~/.claude.json, and after the first Claude run later runs fail with 'Claude configuration file not found at: /home/node/.claude.json / A backup file exists at:... #3374Summary:
I've fixed the issue. Upstream
mainwas the same commit as this branch, so nothing there already covered it.What the Claude CLI actually does (checked against the installed 2.1.293):
.claude.jsonwith a temp file plus rename, so a shared read-write bind mount of the host file isn't safe.~/.claude/backupsand keeps only the 5 newest. Agent containers share that directory, so they could delete the host login's own backups, not just add stub files..claude.jsonprints the exact "configuration file not found / A backup file exists" error. With a seeded{}config it gets past that and stops only at "Not logged in", which is expected because the sandbox has no credentials. The run also wrote an 84-byte backup stub, the same as on your install.Changes
docker/launcher/orchestrator.mjs):agentCredentialArgsnow mounts the host.claude.jsonread-only into the worker and api at the same host path, and setsCLAUDE_JSON_PATH. The file is the one next toHOST_CLAUDE_DIR, orHOST_CLAUDE_JSONif set.HOST_CLAUDE_JSONis always mounted, because a launcher running in a container can't see host files.--mount, so a missing file makes the run fail instead of Docker creating a directory at the config's path.validateEnvchecks the override.packages/core/src/claude/docker/claudeConfigSeed.tsis used by both Claude docker-args builders (dockerArgsBuilder.tsand the olderclaudeHelpers.ts).CLAUDE_JSON_PATH, falling back toos.homedir()as before. It is mounted read-only outside HOME.~/.claude.json. If there's no host file it writes{}. It never overwrites an existing config and never writes back to the host.~/.claude/backupsis now a tmpfs private to each container, so host backups are never read, added to or pruned.propr check --validate-agentsimage runs get the same tmpfs.propr check: a new "Agent config: claude (.claude.json)" row reports one of three states: mounted (OK), missing (warning, with a hint to runclaudeor setHOST_CLAUDE_JSON), or a bad override (fail).test/orchestratorClaudeConfig.test.mjs: launcher args with the file, without it, with the override, and with commas in the path.test/claudeConfigSeed.test.ts: path selection, docker args, and the seed script run in bash, including the "backup exists, config missing" regression with the backups left untouched.checkCommandstest for the new row.HOST_CLAUDE_JSONadded to the configuration reference, the launcher examples and the settings catalog, and the settings docs regenerated.Validation: all of these pass:
npm run test:unit(747)npm run lint --workspaces --if-present -- --max-warnings 0release:verifyfor v0.9.0No test ran inside a real Docker agent container or a real
propr startinstall, and Claude only ran on its own here.Behaviour changes to know about:
~/.claude.json. Changes an agent makes to it are now thrown away when the container exits.~/.claude.jsonafter ProPR starts, Claude runs fail on the mount until ProPR is restarted.~/.claude/backupsdoesn't exist on the host, Docker creates it, owned by root, as the tmpfs mount point.There are no visual previews, since the only user-facing change is a text row in
propr check.Detailed Logs:
a9dcccfb-45e9-4264-96b2-3aaa9802d1d2Log files stored at:
/usr/src/app/logs/executions/issue-3374-2026-10-29T09-24-54-078Z-conversation.json/usr/src/app/logs/executions/issue-3374-2026-10-29T09-24-54-078Z-output.txtLatest Conversation Messages
This PR was created automatically by ProPR after processing issue #3374.
💡 Need changes?
Comment on this PR to request refinements — the AI agent monitors comments and will update the implementation based on your feedback. Keep iterating until you're satisfied!