#4226·career-ops

batch-runner --cli: qwen and gemini workers are denied write/shell by default, and adding agy/codex/copilot/grok needs a permission decision

Author: FrameAutomataCreated Sep 15, 2026Updated Sep 15, 2026

Code of Conduct

Existing issues

  • I searched existing issues and this hasn't been reported yet

What happened?

Follow-up to #738. On main (6255cc2), batch/batch-runner.sh --cli qwen and --cli gemini launch workers that, on a default CLI config, are not allowed to do what a batch worker has to do. Found while scoping the optional follow-up from the #738 review (align --cli with the headless table in AGENTS.md), which runs into the same question for every CLI it would add.

Not reproduced end to end. I don't have qwen, gemini, agy, codex, copilot or grok installed. Everything below is read from each CLI's source or official docs, linked and pinned.

A batch worker has to write files and run a shell command (batch/batch-prompt.md):

  • Step 3 (:375-380) writes reports/{{REPORT_NUM}}-….md
  • Step 4 (:485) runs node generate-pdf.mjs
  • Step 5 (:509-514) writes batch/tracker-additions/{{ID}}.tsv

--cli claude can, because the runner passes --dangerously-skip-permissions. The non-claude branches (batch-runner.sh:986-1003) pass only the prompt and an optional --model:

--cli Invocation Write + shell, headless, default config Source
opencode opencode run allowed permissions docs: most permissions default to allow
qwen qwen -p denied config.ts:1921-1939: when !interactive, DEFAULT approval mode denies shell, edit and write_file unless explicitly allowed
gemini gemini -p denied write.toml:51-61: the ask_user rules for run_shell_command / write_file are interactive = true; with no match, policy-engine.ts:299-301 defaults to DENY when non-interactive

opencode works only because it allows everything by default, which is the same exposure as claude's --dangerously-skip-permissions.

The runner fails closed, so nothing is lost silently. A worker that exits 0 without writing a report hits the check at batch-runner.sh:1145: the offer is marked failed ("worker exited cleanly but wrote no report file for this report number") and counted against --max-retries (default 2). Each attempt still runs the model before it fails.

Steps to reproduce

Predicted from the sources above, not run:

  1. qwen or gemini on a default config: no allowedTools, no --yolo or --approval-mode.
  2. One offer in batch/batch-input.tsv.
  3. ./batch/batch-runner.sh --cli qwen
  4. The worker's write and shell calls are denied; the runner logs ❌ Failed (no report file on disk, attempt 1).

A user who has already allowed those tools in their own qwen or gemini settings would not see this.

Expected behavior

A --cli value the runner accepts can complete an offer, or the runner says up front what that CLI needs.

The same question blocks the #738 follow-up. The rest of the headless table:

CLI Headless default Ways to allow write + shell Source
agy soft-denied; the run continues and exits 0 --dangerously-skip-permissions (all tools), or scoped permissions.allow rules such as write_file(src/) / command(git), settings file only headless docs
codex exec read-only sandbox -s workspace-write CLI reference
copilot -p needs approval --allow-tool write, --allow-tool 'shell(node)', or --allow-all-tools About Copilot CLI
grok -p not documented --always-approve (all tools) headless scripting

web/src/lib/clis.ts:36-58 already sets the rule for the dashboard: a CLI that needs a blanket auto-approve flag to work "is a core architecture issue, not a line inside a CLI-support PR", and #2507 points toward fencing rather than granting. So neither obvious PR is right on its own. Adding the flags contradicts that rule; adding the CLIs without them lists runtimes that fail every offer.

Options:

  1. Document, don't grant. The runner passes no approval flags for non-claude CLIs. usage() and the header comment say write + shell must be allowed in the CLI's own settings, with the scoped rule for each CLI. agy, codex, copilot and grok join the list on that basis. Smallest change, and it keeps the runner out of the permission model.
  2. Scoped grants where the CLI has them. codex -s workspace-write; copilot --allow-tool write --allow-tool 'shell(node)'; qwen --allowed-tools (gemini's equivalent is deprecated in favour of its policy engine). agy and grok have no scoped CLI flag, so they stay on option 1. Caveat: shell(node) still lets a prompt-injected worker run arbitrary node, so this narrows the exposure rather than closing it.
  3. Blanket flags mirroring claude's --dangerously-skip-permissions. Simplest and works everywhere, and it is exactly what clis.ts rules out.

I'd lean to 1, plus codex's -s workspace-write from 2, since #2507 already verified that codex's sandbox holds. Happy to send whichever you pick as a PR.

CLI tool

Affects batch-runner.sh --cli qwen / --cli gemini; proposed agy, codex, copilot, grok

OS and Node.js version

Not OS-specific (read from source and docs, not run)