subagent: hand a subagent its parent's built-in tools, and no others
`build_config` spawned a subagent with `--dangerously-skip-permissions` and no `--tools` at all, so it got claude's entire built-in set — `SendMessage` and `ListAgents` (message peers, or the operator, as its parent), `Task*` including `TaskStop`, which takes an *agent* id and so reaches clean outside the run, `Cron*`, `RemoteTrigger` and `EnterWorktree`/`ExitWorktree`. None of that is part of "do this bounded task in this directory", and none of it is something the parent agent itself can do: the harness has always passed `--tools`. Pass the same one. The value comes from `hive_sh4re::permissions::builtin_tools_arg()` — literally the function the harness resolves its own session with — so the subagent's set is the parent's set, `HIVE_TOOL_GROUPS` and all. That inheritance is the requirement, not an implementation detail: a hardcoded subagent list would hand `WebFetch`/`WebSearch` to the subagent of an agent without the `web_tools` group, which is a privilege escalation, and would drift from the parent's list the first time anyone added a tool to either. `--tools` is the real gate: it holds under `--dangerously-skip-permissions`, unlike `--allowedTools`, which only auto-approves prompts. It does not filter MCP tools, so the `goal_reached`/`need_help` signal surface is deliberately unnamed in it and survives on `--strict-mcp-config` alone. `build_config`'s doc comment claimed `strict_mcp_config` was *the* safety property and that a subagent got "nothing implicit and nothing more". That was false for built-ins, and is what hid this gap for as long as it did; it now says which flag covers which half and that neither substitutes for the other. An empty `--tools` value parses as *unset* and grants more than omitting the flag, so an empty resolution can only be a bug — `build_config` asserts against it and a test pins the non-emptiness alongside the subset-of-parent property. Refs #4416
This commit is contained in:
parent
8b01dbeef1
commit
d6c8cd5a6f
4 changed files with 156 additions and 16 deletions
|
|
@ -218,13 +218,50 @@ agent that needs a stable or non-default port.
|
|||
Own systemd unit, defined alongside the other per-agent MCP daemons in
|
||||
`nix/agent-modules/mcp.nix`.
|
||||
|
||||
## MCP servers available to a subagent
|
||||
## The tool surface a subagent gets
|
||||
|
||||
Two flags, each covering one half, and neither covering the other:
|
||||
`--tools` governs claude's built-in tools, `--strict-mcp-config` governs
|
||||
the MCP ones. Dropping either brings that half back in full; in
|
||||
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
|
||||
[the harness's own allowlist](../turn-loop/mcp.md#tool-allowlist-hive_sh4repermissionsallowed_builtin_tools)
|
||||
for what that list contains and why.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
operator messaging, nested agents (including the stop verb, which takes
|
||||
an _agent_ id rather than a session), schedule and webhook creation, and
|
||||
worktree switching. Before this flag was passed, a subagent reached all of
|
||||
them — `--dangerously-skip-permissions` had removed the only thing that
|
||||
would have asked, and `--allowedTools` would not have helped: it approves
|
||||
prompts in advance rather than restricting anything.
|
||||
|
||||
One trap worth knowing before editing any of this: an empty `--tools`
|
||||
value parses as _unset_ and grants **more** than omitting the flag, so
|
||||
there is no way to spell "no built-in tools" — the daemon asserts rather
|
||||
than emitting one.
|
||||
|
||||
### MCP servers (`--strict-mcp-config`)
|
||||
|
||||
A subagent runs with `--strict-mcp-config` and, by default, exactly one
|
||||
MCP server: the two-tool `subagent_control` route above. It otherwise
|
||||
falls back to claude's own native tools (`Bash`, `WebFetch`, etc.), not
|
||||
the parent's `mcp__bash__*` / `mcp__hyperhive__*` surface. Nothing
|
||||
implicit reaches it: the built-in
|
||||
MCP server: the two-tool `subagent_control` route above — not the
|
||||
parent's `mcp__bash__*` / `mcp__hyperhive__*` surface. Those two signal
|
||||
tools are deliberately unnamed in `--tools`, which doesn't govern them;
|
||||
they survive on this flag alone. Nothing implicit reaches it: the built-in
|
||||
hyperhive surface (todos/messaging) isn't an `extraMcpServers` entry at
|
||||
all, and the automatically injected `bash`/`subagent` entries default to excluded
|
||||
too (a subagent can't spawn hive-bash tasks or its own nested subagents
|
||||
|
|
|
|||
Loading…
Reference in a new issue