Stabilize and version agent_type / agent_id in tool-event hook stdin

Resolved 💬 3 comments Opened May 5, 2026 by GitHydrox Closed Jun 2, 2026

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

  1. Promote agent_id and agent_type to the stable hook schema contract, not just a context-conditional sub-table. Treat them as part of the public interface for PreToolUse, PostToolUse, and any tool-event hook where subagent context is relevant.
  1. Add a schema_version field 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.
  1. Specify enumerated values and stability for agent_type. Today: "Agent name (e.g., Explore or 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?
  1. Specify lifecycle/scope for agent_id. Process-scoped? Session-scoped? Globally unique? Stable across hook events for the same agent instance (so PreToolUsePostToolUse correlation works)?
  1. 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.
  1. Update the PreToolUse and PostToolUse input examples to include subagent-context examples that show agent_id and agent_type populated. 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/PostToolUse hooks do not fire for subagent tool calls — adjacent reliability concern; field stability is moot if the events do not fire.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗