Stabilize and version agent_type / agent_id in tool-event hook stdin
Summary
agent_id and agent_type are documented in the hooks reference under "Subagent context" as available "when running with --agent or inside a subagent." They are verified present in PreToolUse and PostToolUse stdin on Claude Code 2.1.92 (Linux + Windows) and are load-bearing for hook-enforced subagent isolation patterns. The current documentation does not commit to schema stability. This issue asks for explicit stability guarantees and structural protections against silent drift.
Use case
Outbound prompt-injection containment via hook-enforced subagent isolation. The orchestrator is treated as presumed-compromised by untrusted web content. PreToolUse hooks distinguish orchestrator tool calls from a designated quarantine subagent (read-only, no write tools) and apply differential security policies — orchestrator WebFetch is denied, quarantine subagent WebFetch is allowed. The discriminator is the presence/absence of agent_type in stdin. Routing untrusted content through an MCP-based proxy was rejected because it sends the most untrusted input through the most privileged gateway.
This is one shape of a broader pattern: any hook-based security control that needs to differentiate trust contexts depends on these fields.
Why current documentation is insufficient
The fields are mentioned, but they sit in a context-conditional sub-table rather than in the stable schema contract. The existing PreToolUse example doesn't include them, leading downstream consumers to overlook them entirely (see #40140, where the original tester's diagnostic missed them — partially because the example doesn't show them).
A documentation note that the fields exist is insufficient. The risk surface is silent drift: rename, removal, or semantic change at any minor version. Detection lag for downstream consumers building security pipelines on these fields is days to weeks — long enough for a quarantine boundary to fail open or fail closed in production without anyone noticing.
Asks
- Promote
agent_idandagent_typeto the stable hook schema contract, not just a context-conditional sub-table. Treat them as part of the public interface forPreToolUse,PostToolUse, and any tool-event hook where subagent context is relevant.
- Add a
schema_versionfield to hook stdin. This is the structural ask. With a version field, downstream consumers detect drift mechanically instead of via production failures. Existing consumers ignore the field by default; security-critical consumers can fail closed on unrecognized versions.
- Specify enumerated values and stability for
agent_type. Today: "Agent name (e.g.,Exploreor custom name)." Specify: is the orchestrator absence-of-field or a sentinel value? What is the stability guarantee on built-in agent type names (Explore,general-purpose, etc.)? Are custom agent names guaranteed to round-trip exactly as defined in agent files?
- Specify lifecycle/scope for
agent_id. Process-scoped? Session-scoped? Globally unique? Stable across hook events for the same agent instance (soPreToolUse→PostToolUsecorrelation works)?
- Publish a deprecation policy for hook stdin schema. Field removal or rename gets ≥1 minor-version parallel emit and a changelog entry. This is the structural protection that turns documentation into a contract.
- Update the
PreToolUseandPostToolUseinput examples to include subagent-context examples that showagent_idandagent_typepopulated. The current orchestrator-only example is what led #40140 to be misfiled — the original tester didn't realize the fields appear conditionally.
Tested
Verified on Claude Code 2.1.92 across Linux and Windows. Subagent PreToolUse stdin contains agent_type (e.g., "quarantine-web" for a custom subagent); orchestrator PreToolUse stdin omits the field. Same pattern observed for PostToolUse.
Alternatives considered
- Routing untrusted web fetches through an MCP tool. Rejected — creates an open web proxy on the most privileged gateway and defeats the isolation purpose.
- Warn-only hooks without agent differentiation. Rejected — the orchestrator's judgment is the thing already compromised by injection. Warnings to a compromised orchestrator do not help.
- Working-directory inference (worktree isolation). Rejected — brittle, only works under specific isolation modes, does not generalize across subagent types.
Backward compatibility
All asks except (6) are non-breaking. (6) is documentation-only. The schema_version field is additive; consumers that ignore it continue to work.
Related
- #40140 (closed stale, 2026-04-28): same field-existence ask. Closed before resolution; current docs partially address it but provide no stability guarantees.
- #54898 (closed, 2026-05-01): per-agent permission control gap.
- #6885 (open): Agent Context Detention in Hook Events.
- #34692 (open):
PreToolUse/PostToolUsehooks do not fire for subagent tool calls — adjacent reliability concern; field stability is moot if the events do not fire.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗