Summary
In non-interactive/headless mode (biorouter run --quiet --output-format json, no TTY), when a tool call triggers a "sensitive system operation" permission prompt — e.g. the developer/shell builtin writing to a protected path like /dev/null — the run has no way to receive approval and hangs for ~25–30 minutes, then aborts with a misleading error:
The run produces 0 tool calls, (no text response), Success=False, wasting ~30 min. Worse, the permission prompt text is written to stdout, so with --output-format json the emitted document is not valid JSON (it contains the prompt instead of the transcript).
Environment
- biorouter
1.88.3, macOS (Apple Silicon)
BIOROUTER_MODE: auto ("Fully-Automatic mode")
- Invocation:
biorouter run --name <n> --quiet --output-format json --provider <p> --model <m> --max-turns 50 -t "<prompt>"
developer builtin enabled; the model occasionally issues a shell command that redirects to /dev/null.
What the --output-format json file contained (instead of JSON)
🔒 Sensitive system operation in Fully-Automatic mode.
This tool call writes to /dev/null (a protected system directory).
Approve it to continue, or deny it. Ordinary file changes run without a prompt in this mode.
stderr: Error: not connected · Elapsed: 1822 s · Tool calls: 0.
Reproduction
Run headlessly with the developer builtin enabled and a prompt that leads the model to run a shell command redirecting to a protected path (e.g. ... 2>/dev/null or echo x > /dev/null):
biorouter run --quiet --output-format json \
--provider <p> --model <m> --max-turns 50 \
-t "<prompt that uses the shell tool and writes to /dev/null>"
Observed in ~5% of a 100-question automated batch (non-deterministic — the same /dev/null write was auto-handled and succeeded in other runs).
Impact
- Hang / wasted time: ~30 min per occurrence in an automated pipeline before it fails.
- Silent, DoS-like stall: no output, no progress — indistinguishable from a hang.
- Corrupted structured output: prompt text on stdout breaks any
--output-format json consumer.
- Misleading error:
not connected gives no hint that a permission gate is the cause.
Expected behavior (non-interactive mode)
- Fail fast (auto-deny) or honor a configured policy (
permission.yaml always_allow/ask_before/never_allow) instead of blocking indefinitely on a prompt that can never be answered when there is no TTY / --quiet is set.
- Never write prompt text to stdout when
--output-format json is set — keep stdout valid JSON; route prompts to stderr/TTY.
- Emit a clear, specific error ("operation requires approval; running non-interactively → denied") instead of
Error: not connected.
Possible inconsistency in the gate itself
In "Fully-Automatic mode," arbitrary file writes and shell/code_execution are auto-approved (via permission.yaml always_allow), yet a harmless write to /dev/null is hard-gated as a "sensitive system operation." The gating appears inverted from a safety standpoint — a benign discard sink blocks while genuinely powerful operations pass — and it is the direct cause of the hang. Worth reconsidering which operations are gated and ensuring permission.yaml can actually cover/scope the protected-path gate (right now always_allow does not).
Workaround
Disable the developer (and computercontroller) builtins for headless batch runs, so no shell command can trigger the protected-path gate.
Summary
In non-interactive/headless mode (
biorouter run --quiet --output-format json, no TTY), when a tool call triggers a "sensitive system operation" permission prompt — e.g. thedeveloper/shellbuiltin writing to a protected path like/dev/null— the run has no way to receive approval and hangs for ~25–30 minutes, then aborts with a misleading error:The run produces 0 tool calls,
(no text response),Success=False, wasting ~30 min. Worse, the permission prompt text is written to stdout, so with--output-format jsonthe emitted document is not valid JSON (it contains the prompt instead of the transcript).Environment
1.88.3, macOS (Apple Silicon)BIOROUTER_MODE: auto("Fully-Automatic mode")biorouter run --name <n> --quiet --output-format json --provider <p> --model <m> --max-turns 50 -t "<prompt>"developerbuiltin enabled; the model occasionally issues ashellcommand that redirects to/dev/null.What the
--output-format jsonfile contained (instead of JSON)stderr:
Error: not connected· Elapsed: 1822 s · Tool calls: 0.Reproduction
Run headlessly with the
developerbuiltin enabled and a prompt that leads the model to run a shell command redirecting to a protected path (e.g.... 2>/dev/nullorecho x > /dev/null):Observed in ~5% of a 100-question automated batch (non-deterministic — the same
/dev/nullwrite was auto-handled and succeeded in other runs).Impact
--output-format jsonconsumer.not connectedgives no hint that a permission gate is the cause.Expected behavior (non-interactive mode)
permission.yamlalways_allow/ask_before/never_allow) instead of blocking indefinitely on a prompt that can never be answered when there is no TTY /--quietis set.--output-format jsonis set — keep stdout valid JSON; route prompts to stderr/TTY.Error: not connected.Possible inconsistency in the gate itself
In "Fully-Automatic mode," arbitrary file writes and
shell/code_executionare auto-approved (viapermission.yamlalways_allow), yet a harmless write to/dev/nullis hard-gated as a "sensitive system operation." The gating appears inverted from a safety standpoint — a benign discard sink blocks while genuinely powerful operations pass — and it is the direct cause of the hang. Worth reconsidering which operations are gated and ensuringpermission.yamlcan actually cover/scope the protected-path gate (right nowalways_allowdoes not).Workaround
Disable the
developer(andcomputercontroller) builtins for headless batch runs, so no shell command can trigger the protected-path gate.