Background sessions (claude agents / fleet) don't honor permissions.defaultMode: bypassPermissions
Summary
Background sessions spawned via claude agents (and other fleet/daemon-dispatched bg jobs) do not honor permissions.defaultMode: "bypassPermissions" from ~/.claude/settings.json. They start in default mode and prompt for every Bash/Edit/Write call, even though the user has configured the bypass default. This breaks long-standing yolo-mode workflows for users who rely on defaultMode: bypassPermissions and have now adopted the new claude agents mechanism.
Repro
- Set in
~/.claude/settings.json:
``json`
{
"permissions": {
"defaultMode": "bypassPermissions",
"disableAutoMode": "disable"
}
}
disableAutoMode
(The is included to rule out the auto-mode policy overriding defaultMode` — see "Auto mode overlap" below.)
- Run
claude daemon stop --any --keep-workersto clear any stale spare pool. - Run
claude agentsand create a new agent. - Ask the agent to run a Bash command (e.g.
env | grep PATH).
Expected: Bash runs without a prompt — defaultMode: bypassPermissions is honored.
Actual: The agent prompts for permission to run Bash, exactly as if defaultMode were default.
Diagnosis
I traced this through the CLI binary (/path/to/claude/versions/2.1.141, version 2.1.141 on Linux).
Step 1 — The daemon dispatches spares with no permission-mode flag. From ~/.claude/daemon/roster.json after creating a fresh agent:
"launch": {
"mode": "prompt",
"args": [
"--session-id", "<uuid>",
"--agent", "claude",
"--", "<prompt>"
]
}
No --permission-mode bypassPermissions (or --dangerously-skip-permissions).
Step 2 — The dispatcher passes launch.args through verbatim. From the binary's dh4() function:
function dh4(H, $, q, K, _) {
if ($ > 1 && q) return ["--resume", K, ..._];
if (H.launch.mode === "resume") return [...H.launch.fork ? ["--session-id", H.sessionId, "--fork-session"] : [], "--resume", H.launch.sessionId, ...H.launch.flagArgs];
return H.launch.args; // <-- "prompt" mode: returned verbatim, no synthesis from user defaultMode
}
For the mode: "prompt" path (new agent creation), H.launch.args is returned unmodified. The dispatcher never reads permissions.defaultMode from user settings and translates it into a startup flag.
Step 3 — bypassPermissions requires a startup flag. From the permission-modes docs:
You cannot enterbypassPermissionsfrom a session that was started without one of the enabling flags; restart with one to enable it: ``bash claude --permission-mode bypassPermissions``
So even though ~/.claude/settings.json says defaultMode: bypassPermissions, the spare session never sees a flag that allows it to enter that mode, so it falls back to default.
Why does interactive CLI work then? When claude is invoked directly in a terminal, the startup code reads defaultMode from settings and synthesizes the equivalent of the --permission-mode flag internally. This synthesis does not happen on the bg-spare dispatch code path.
Auto mode overlap (separate issue, related symptom)
Before applying disableAutoMode: "disable", the same setup landed in auto mode instead of default, because of this policy in the binary:
[auto-mode] hasAutoModeOptIn=true policy defaultMode=auto implies consent
When the user's account is opted into auto mode (Team-plan admin toggle), the auto-mode policy silently overrides permissions.defaultMode from settings.json for bg-spawned sessions and applies auto. Adding disableAutoMode: "disable" to user settings turns this off — but the session then falls back to default (this bug), not to bypassPermissions as the user configured.
So this is really two related problems:
- Auto-mode opt-in overrides user-configured
defaultModefor fleet/bg sessions without telling the user. - The fleet/bg dispatcher doesn't synthesize a startup flag from user
defaultMode, sobypassPermissionscan never activate even when the auto-mode override is disabled.
Suggested fix
In the dispatcher path that constructs launch.args for mode: "prompt" (and similar new-session modes), read permissions.defaultMode from the merged settings and, when it's bypassPermissions, prepend --permission-mode bypassPermissions to launch.args. Mirror the same synthesis the interactive CLI already does at startup.
A second fix should ensure auto-mode opt-in respects permissions.defaultMode from user settings rather than overriding it — opt-in means "auto mode is available," not "auto mode wins over my explicit defaultMode."
Related issues
- #37442 — Subagents don't inherit bypassPermissions from parent
- #29026 — Desktop app ignores defaultMode: bypassPermissions
- #12604 — VS Code extension: defaultMode: bypassPermissions not working
- #39311 — Desktop app: Auto/Bypass greyed out despite account toggles
- #38662, #38859, #34095, #32402, #27203 — adjacent permission-inheritance bugs
Environment
- Claude Code:
2.1.141 - OS: Linux 6.8.0-63-generic (Ubuntu)
- Account plan: Max
- Auto-mode account toggle: enabled (Anthropic-side opt-in)
[AI-assisted - Claude]
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗