Skip to content

Give background sub-agents the same tool permissions as foreground#150

Merged
pufit merged 1 commit into
mainfrom
pufit/background-agent-permissions
Jun 24, 2026
Merged

Give background sub-agents the same tool permissions as foreground#150
pufit merged 1 commit into
mainfrom
pufit/background-agent-permissions

Conversation

@pufit

@pufit pufit commented Jun 24, 2026

Copy link
Copy Markdown
Member

Problem

Sub-agents spawned via the Agent tool with run_in_background: true get permission-denied for their nested Write/Edit/Bash calls, so background build/write agents silently fail and must be run in the foreground.

Root cause (empirically verified)

A background sub-agent is detached and non-blocking, so the CLI has no way to surface an approval prompt for its nested tool calls. Nerve grants permissions entirely through the can_use_tool callback (no permission_mode, no static allowed_tools), and that callback is never invoked for a background sub-agent's nested calls — the CLI denies upstream.

Tested against claude_agent_sdk 0.2.104:

Scenario Nested write can_use_tool reached?
Foreground sub-agent ✅ succeeds ✅ yes (with agent_id)
Background sub-agent (before) denied never called

Key finding: a PreToolUse hook does fire for those nested background-subagent calls (it's a programmatic callback, not a user-facing prompt), where can_use_tool cannot reach. Returning permissionDecision: "allow" from a hook grants the permission.

Fix

A catch-all PreToolUse hook in AgentEngine._build_hooks that pre-approves all non-interactive tools, giving background sub-agents the same auto-approval foreground agents already get:

  • Interactive tools (AskUserQuestion, ExitPlanMode, EnterPlanMode) → left untouched, so they still defer to can_use_tool and the web pause-for-input flow is unchanged.
  • Read → left untouched, so the existing image-validator's deny still wins.
  • Chosen over a static allowed_tools allowlist because the hook also covers dynamically-discovered MCP tools (the original reason the engine avoided an allowlist).

Gated by a new config flag agent.background_agent_permissions (default true; set false to restore the previous CLI-default behavior).

Verification

  • End-to-end test wiring the real _build_hooks() into a live background sub-agent: flag on → nested write succeeds, flag off → denied (prior behavior preserved).
  • 3 unit tests added (TestBuildHooksBackgroundPermissions); full suite green (123 passed).

Security note

This extends Nerve's existing "auto-approve all non-interactive tools" posture (already true for foreground via can_use_tool) to background sub-agents — no new risk class relative to foreground. A future ALLOW/CONFIRM/DENY tool-policy classifier would need wiring into both can_use_tool and this hook.

Generated by Nerve

Background sub-agents (the Agent tool with run_in_background) had their
nested Write/Edit/Bash denied: a detached, non-blocking task can't surface
an approval prompt, so the CLI denies tools needing one and can_use_tool is
never invoked for them.

Add a catch-all PreToolUse hook that pre-approves all non-interactive tools
(a hook fires for nested background-subagent calls where can_use_tool can't
reach). Interactive tools and Read still defer to can_use_tool / the image
validator, so web pause-for-input and image validation are unchanged. Gated
by agent.background_agent_permissions (default true).
@pufit pufit merged commit 1454339 into main Jun 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant