From 664aebe79f0570f904bc93964f40b2c3e18c4e51 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Fri, 17 Jul 2026 01:45:14 -0700 Subject: [PATCH] fix(miner): grant the claude-cli driver Read/Bash access, not just edits --permission-mode acceptEdits only auto-approves file EDIT tool calls -- it never granted Read or Bash, so a real headless attempt (which needs both to explore the repo and run tests before finishing) got every one of those calls denied with no TTY to resolve an interactive prompt, silently producing zero real work on every attempt. Adds --allowedTools Read Bash alongside the existing acceptEdits mode, confirmed via a live end-to-end reproduction (zero denials, a real fix and regression test committed) -- deliberately narrower than --permission-mode bypassPermissions, which would also disable edit confirmation and any other safety rail, not just this specific gap. Closes #6840 --- .../src/miner/cli-subprocess-driver.ts | 13 ++++++++++--- test/unit/cli-subprocess-driver.test.ts | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/loopover-engine/src/miner/cli-subprocess-driver.ts b/packages/loopover-engine/src/miner/cli-subprocess-driver.ts index b8c66ee659..6b6fcc77ad 100644 --- a/packages/loopover-engine/src/miner/cli-subprocess-driver.ts +++ b/packages/loopover-engine/src/miner/cli-subprocess-driver.ts @@ -92,15 +92,22 @@ const CODING_AGENT_ENV_ALLOWLIST = [ * - `--output-format json` produces a single parseable JSON result on stdout, matching `claudeErrorStatus`'s * own `JSON.parse(stdout.trim())` assumption (which was already written for this shape, just never * actually triggered because this flag was never passed). - * - `--permission-mode acceptEdits` is the same edit-permission scope the Agent-SDK driver already uses - * (#4267) -- file edits run unattended inside the scoped worktree, nothing broader. + * - `--permission-mode acceptEdits` alone (the CLI's own edit-permission scope, matching the label the + * Agent-SDK driver's `permissionMode` also uses, #4267) only auto-approves file EDIT tool calls -- it + * does NOT grant `Read` or `Bash`, so a real task (which needs both to explore the repo and run tests) + * got every one of those calls denied in a headless `--print` invocation with no TTY to resolve an + * interactive prompt, silently producing zero real work every time (#6840). `--allowedTools Read Bash` + * grants exactly the two additional tool classes the task actually needs, confirmed via a live + * end-to-end reproduction (zero denials, a real fix + test committed) -- deliberately narrower than + * `--permission-mode bypassPermissions`, which also disables edit-scope confirmation and any other + * safety rail the CLI has, not just the Read/Bash gap this task actually hits. * There is no turn-budget flag on the real CLI (verified via `claude --help`) and no acceptance-criteria * flag either -- the coding agent discovers `task.acceptanceCriteriaPath` itself via its own Read tool * inside the scoped working directory, exactly like the Agent-SDK driver already does (agent-sdk-driver.ts * never passes it as a distinct option either; only `task.instructions` is forwarded as the prompt there * too). The wall-clock `timeoutMs` (already implemented) is this provider's only real turn/cost ceiling. */ export function defaultClaudeCliArgs(task: CodingAgentDriverTask): string[] { - return ["--print", "--output-format", "json", "--permission-mode", "acceptEdits", task.instructions]; + return ["--print", "--output-format", "json", "--permission-mode", "acceptEdits", "--allowedTools", "Read", "Bash", "--", task.instructions]; } /** Real, verified `codex exec` non-interactive argv (confirmed against `codex exec --help`, #5135 diff --git a/test/unit/cli-subprocess-driver.test.ts b/test/unit/cli-subprocess-driver.test.ts index 5c8f77b0cc..126b529a01 100644 --- a/test/unit/cli-subprocess-driver.test.ts +++ b/test/unit/cli-subprocess-driver.test.ts @@ -41,10 +41,24 @@ describe("createCliSubprocessCodingAgentDriver (#4266)", () => { "json", "--permission-mode", "acceptEdits", + "--allowedTools", + "Read", + "Bash", + "--", "Fix the pagination bug.", ]); }); + it("#6840: grants Read and Bash in addition to acceptEdits -- acceptEdits alone denies every Read/Bash tool call, silently blocking all real work", async () => { + const { spawn, calls } = fakeSpawn({ stdout: "done", code: 0 }); + const driver = createCliSubprocessCodingAgentDriver({ command: "claude", spawn }); + await driver.run(TASK); + const args = calls[0]?.args ?? []; + const allowedToolsIndex = args.indexOf("--allowedTools"); + expect(allowedToolsIndex).toBeGreaterThan(-1); + expect(args.slice(allowedToolsIndex + 1, allowedToolsIndex + 3)).toEqual(["Read", "Bash"]); + }); + it("uses codex's own real default argv (the exec subcommand, not claude's flags)", async () => { const { spawn, calls } = fakeSpawn({ stdout: "done", code: 0 }); const driver = createCliSubprocessCodingAgentDriver({ command: "codex", spawn });