From 20ba20ff2c76d21f7f6370c37144135806734370 Mon Sep 17 00:00:00 2001 From: eutialia Date: Thu, 3 Sep 2026 22:13:22 -0700 Subject: [PATCH] fix(workspaces): let headless claude runs write in their own Workspace --allowedTools covers Bash only, so Write/Edit fell through to the permission prompt claude -p has nobody to answer. Headless Issues that write a report, append to a watchlist, or update a map lost their output and reported every Write/Edit call denied by the sandbox. pi passes --approve and agy passes --dangerously-skip-permissions under Docker; claude was the only adapter that could not persist. acceptEdits grants file writes and leaves Bash gated, so the allowlist keeps its meaning instead of being replaced by a blanket bypass. Verified against Claude Code 2.1.237: auto and dontAsk are both no-ops headless, they still escalate to an unanswerable prompt, so acceptEdits is the only mode that works. Write-class Bash stays denied, so git commit in an Issue body still fails. Narrow Bash(git add:*) / Bash(git commit:*) prefixes are a separate follow-up. --- src/workspaces/adapters/ai-config.spec.ts | 3 +++ src/workspaces/adapters/claude.ts | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/workspaces/adapters/ai-config.spec.ts b/src/workspaces/adapters/ai-config.spec.ts index 6f5f48433..3e7fa615d 100644 --- a/src/workspaces/adapters/ai-config.spec.ts +++ b/src/workspaces/adapters/ai-config.spec.ts @@ -769,6 +769,9 @@ describe('composeHeadlessCommand (one-shot headless argv, prompt placed per-CLI) '{"enableAllProjectMcpServers":true}', '--allowedTools', 'Bash(alice:*),Bash(alice-workspace:*),Bash(alice-uta:*),Bash(traderhub:*)', + // Without this, Write/Edit fall through to a permission prompt headless has no way to answer. + '--permission-mode', + 'acceptEdits', '-p', '--output-format', 'stream-json', diff --git a/src/workspaces/adapters/claude.ts b/src/workspaces/adapters/claude.ts index 53897f64b..c8d8e3c92 100644 --- a/src/workspaces/adapters/claude.ts +++ b/src/workspaces/adapters/claude.ts @@ -89,6 +89,10 @@ const HEADLESS_ALLOWED_TOOLS = [ 'Bash(traderhub:*)', ].join(','); +// The allowlist above covers Bash only. Without this, Write/Edit fall through +// to a permission prompt `-p` cannot answer, so headless runs lose all file output. +const HEADLESS_PERMISSION_MODE = 'acceptEdits'; + function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); } @@ -277,6 +281,7 @@ export const claudeAdapter: CliAdapter = { ...base, '--settings', AUTOTRUST_SETTINGS, '--allowedTools', HEADLESS_ALLOWED_TOOLS, + '--permission-mode', HEADLESS_PERMISSION_MODE, ...(ctx.sessionRuntime?.headlessArgs ?? []), ...(ctx.resume ? ['--resume', ctx.resume.sessionId] : []), '-p', '--output-format', 'stream-json', '--verbose',