subagent: grant claude's Bash when the agent holds the execution group

A subagent inherited the parent's built-in tool list, which correctly has
no `Bash` -- the agent reaches a shell through the `bash` MCP server, not
the built-in. Subagents get no such server, so the intersection was empty
and they could not run a command at all: no commits, no pushes, no gates.

Add `subagent_builtin_tools_for`/`_arg`, which reuse the shared resolver
and append `Bash` only when `Execution` -- the group that gates the `bash`
MCP server -- is present. Only the subagent spawn path calls them, so the
harness's own `--tools`/`--allowedTools` are unchanged.

The capability transfers; the mechanism does not.

Refs #4422
This commit is contained in:
atlas 2026-09-15 18:47:27 +02:00
commit 5ce0a357b4
4 changed files with 122 additions and 32 deletions

View file

@ -227,19 +227,31 @@ particular `--tools` does **not** filter `mcp__*` tools.
### Built-in tools (`--tools`)
**A subagent gets exactly the built-ins its parent agent has** — the same
list, resolved by the same function
(`hive_sh4re::permissions::builtin_tools_arg`) from the same
`HIVE_TOOL_GROUPS`: `Edit`, `Glob`, `Grep`, `Read`, `Skill`,
`Write`, plus `WebFetch`/`WebSearch` for an agent granted the `web_tools`
tool group and not otherwise. See
**A subagent gets exactly the built-ins its parent agent has, plus one
deliberate exception** — the base resolution
(`hive_sh4re::permissions::subagent_builtin_tools_arg`, wrapping the
harness's own `builtin_tools_for`) from the same `HIVE_TOOL_GROUPS`:
`Edit`, `Glob`, `Grep`, `Read`, `Skill`, `Write`, plus `WebFetch`/
`WebSearch` for an agent granted the `web_tools` tool group and not
otherwise. See
[the harness's own allowlist](../turn-loop/mcp.md#tool-allowlist-hive_sh4repermissionsallowed_builtin_tools)
for what that list contains and why.
The exception: **a subagent gets Claude's built-in `Bash` iff its parent
holds the `execution` tool group** — the group that already grants the
parent shell execution, via the out-of-process `bash` MCP server
(`mcp__bash__run`/`status`/`kill`). A subagent has no MCP server of its
own by default (see [MCP servers](#mcp-servers---strict-mcp-config)
below), so there is no `mcp__bash__*` for it to inherit that capability
through; it gets Claude's own tool instead. The rule is the capability
transfers, not the mechanism — the parent itself never gains built-in
`Bash` no matter which groups it holds, only a subagent spawned by an
`execution`-holding parent does.
Inheriting rather than listing is the point: a hardcoded subagent list
would hand web egress to the subagent of an agent that isn't allowed web
egress, and would diverge from the parent's on the first tool anyone adds
to either.
would hand web egress (or `Bash`) to the subagent of an agent that isn't
allowed it, and would diverge from the parent's on the first tool anyone
adds to either.
Everything else in claude's built-in set is absent, in particular the
tools that let a session act outside the run it was started for: peer and