You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Authorship note: This issue was written by an AI assistant (Command Code) on behalf of a human user who hit the problem and explicitly asked that it be filed. The user directed the investigation and the framing; the AI wrote this text. No paths, account names, repository names, project names, or other identifying details are included, at the reporter's explicit request — so any template field below is left blank rather than partially filled.
Summary
A mod can add a tool to Command Code, but it cannot say who may use it. cmd.addTool registers into a single global tool registry with no scoping parameter, and the beforeToolCall hook — the only place a mod can block a call — receives no agent identity in its context. So a mod that intends a narrow, single-purpose tool for one sub-agent has no way to express that intent, and the tool silently ends up on the broadest surface available: the main loop.
The per-agent tools: frontmatter allowlist is the only lever, and it only ever narrows. Callers that declare no allowlist receive every registered tool by default.
What was observed
Setup: a mod registering one custom read-only tool, intended for a single sub-agent, declared in exactly one agent definition's tools: allowlist. Each caller was then spawned and asked to report its own available tools, and — where the tool was present — called it, which returned a real result:
Caller
Tool available?
Main loop
yes — called it successfully
Bundled general agent
yes — called it successfully
Bundled explore agent
no
A custom agent whose tools: omit it
no
The narrowing works where an allowlist exists. It does nothing where one does not. general is a bundled agent defined with the full tool set and holds a reserved name, so it cannot be shadowed with a locally-defined equivalent, and the main loop has no agent file at all. The mod author's assumption — that agents which do not list the tool simply do not get it — holds for exactly the agents that bothered to declare an allowlist, and fails for the two that matter most.
Why a mod cannot fix this itself
cmd.addTool accepts a schema, a run function, and flags such as readOnly. There is no agent or scope parameter, so registration is global.
beforeToolCall({toolCallId, toolName, input, state}, ctx) — ctx is {emit, signal, cwd, session}. There is no agent identity in it, so a mod cannot gate its own tool on "am I being called by agent X".
Agent identity does surface as subagentType, but only on the subagent_start / subagent_progressevents, which are observe-only (cmd.on). The blocking hook has no equivalent field.
A permissions.deny rule is global, so removing the tool from the main loop also removes it from the one agent that legitimately uses it. There is no per-agent exemption, and deny outranks every narrower allow.
The practical result is that minimal-privilege tool design is unreachable for mods. The author's intent degrades silently: the tool works, appears correctly in the one intended agent, and is additionally present everywhere else — including the context with the largest tool surface and the least scrutiny.
Expected behavior
Any one of these would close it:
A scope on registration — an optional agents/scope field on addTool (by agent name, wildcard, or "main loop only").
Agent identity in the beforeToolCall context — subagentType, or an explicit "main loop" marker when there is none — so a mod can enforce its own scoping.
Agent-targeted deny / allow rules, so a tool can be withheld from the main loop while remaining available to a named agent.
If none of the above is intended: document plainly that mod-registered tools are global and cannot be scoped, so authors stop designing around a capability that does not exist.
Related
Sub-agent tool calls bypass PreToolUse hooks and mod beforeToolCall hooks — only permission rules apply #852 — sub-agent tool calls bypass PreToolUse hooks and mod beforeToolCall. Cited as related; not independently re-verified for this report. It compounds this one: if beforeToolCall does not run for sub-agent calls, then even option (2) above would leave no working seam. Both reports turn on the same underlying question — which execution contexts a mod's hooks and a mod's tools are actually scoped to.
The caller/tool-availability table was reproduced by spawning each caller, having it report its own available tools, and invoking the tool where present. Rows marked yes executed the call and returned a real result.
The absence of a scoping parameter on addTool, and of agent identity in the mod hook context, is read from the shipped mods and hooks reference documentation, not from the implementation.
Summary
A mod can add a tool to Command Code, but it cannot say who may use it.
cmd.addToolregisters into a single global tool registry with no scoping parameter, and thebeforeToolCallhook — the only place a mod can block a call — receives no agent identity in its context. So a mod that intends a narrow, single-purpose tool for one sub-agent has no way to express that intent, and the tool silently ends up on the broadest surface available: the main loop.The per-agent
tools:frontmatter allowlist is the only lever, and it only ever narrows. Callers that declare no allowlist receive every registered tool by default.What was observed
Setup: a mod registering one custom read-only tool, intended for a single sub-agent, declared in exactly one agent definition's
tools:allowlist. Each caller was then spawned and asked to report its own available tools, and — where the tool was present — called it, which returned a real result:generalagentexploreagenttools:omit itThe narrowing works where an allowlist exists. It does nothing where one does not.
generalis a bundled agent defined with the full tool set and holds a reserved name, so it cannot be shadowed with a locally-defined equivalent, and the main loop has no agent file at all. The mod author's assumption — that agents which do not list the tool simply do not get it — holds for exactly the agents that bothered to declare an allowlist, and fails for the two that matter most.Why a mod cannot fix this itself
cmd.addToolaccepts a schema, arunfunction, and flags such asreadOnly. There is no agent or scope parameter, so registration is global.beforeToolCall({toolCallId, toolName, input, state}, ctx)—ctxis{emit, signal, cwd, session}. There is no agent identity in it, so a mod cannot gate its own tool on "am I being called by agent X".subagentType, but only on thesubagent_start/subagent_progressevents, which are observe-only (cmd.on). The blocking hook has no equivalent field.permissions.denyrule is global, so removing the tool from the main loop also removes it from the one agent that legitimately uses it. There is no per-agent exemption, and deny outranks every narrower allow.The practical result is that minimal-privilege tool design is unreachable for mods. The author's intent degrades silently: the tool works, appears correctly in the one intended agent, and is additionally present everywhere else — including the context with the largest tool surface and the least scrutiny.
Expected behavior
Any one of these would close it:
addTool(by agent name, wildcard, or "main loop only").beforeToolCallcontext —subagentType, or an explicit "main loop" marker when there is none — so a mod can enforce its own scoping.deny/allowrules, so a tool can be withheld from the main loop while remaining available to a named agent.Related
PreToolUsehooks and modbeforeToolCall. Cited as related; not independently re-verified for this report. It compounds this one: ifbeforeToolCalldoes not run for sub-agent calls, then even option (2) above would leave no working seam. Both reports turn on the same underlying question — which execution contexts a mod's hooks and a mod's tools are actually scoped to.Command Code Version
1.54.0
Operating System
Linux
Confidence / what was not verified
addTool, and of agent identity in the mod hook context, is read from the shipped mods and hooks reference documentation, not from the implementation.beforeToolCallexecutes for sub-agent tool calls (see Sub-agent tool calls bypass PreToolUse hooks and mod beforeToolCall hooks — only permission rules apply #852). The compounding interaction described under "Related" is conditional on that being true.