batch-runner --cli: qwen and gemini workers are denied write/shell by default, and adding agy/codex/copilot/grok needs a permission decision
Code of Conduct
- I agree to follow the 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) writesreports/{{REPORT_NUM}}-….md - Step 4 (
:485) runsnode generate-pdf.mjs - Step 5 (
:509-514) writesbatch/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:
- qwen or gemini on a default config: no
allowedTools, no--yoloor--approval-mode. - One offer in
batch/batch-input.tsv. ./batch/batch-runner.sh --cli qwen- 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:
- 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. - 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 arbitrarynode, so this narrows the exposure rather than closing it. - Blanket flags mirroring claude's
--dangerously-skip-permissions. Simplest and works everywhere, and it is exactly whatclis.tsrules 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)
Source: santifer/career-ops