Skip to content

docs(hooks): per-event stdin payload fields are undocumented (tool_name, tool_input, tool_call_id, tool_output, agent_name, error_type, reason, notification_type, ...) #916

Description

@ken-jo

Summary

The hooks guide (docs/en/customization/hooks.md) documents the base stdin payload a hook receives, but never documents the per-event additional fields. The doc itself promises them — and the doc's own example relies on one — yet the field names appear nowhere in the docs, only in the engine source. A hook author has to read packages/agent-core to discover the JSON keys for each event.

(Filed as a documentation issue; runtime fields like version/plan/model/platform are N/A. Suggested label: documentation.)

Where the docs fall short

docs/en/customization/hooks.md, "Event Data Format" (lines 57–69) shows only the base payload:

{
  "hook_event_name": "PreToolUse",
  "session_id": "session_abc",
  "cwd": "/path/to/project"
}

and then states (line 69):

Specific events will also include additional fields (such as tool name and command content); see the event reference below. All field names use snake_case.

But the "Event Reference" table (lines ~92–114) only documents what the matcher matches per event — it never lists the JSON keys each event adds to the payload. So "see the event reference below" points at a table that doesn't contain the promised fields. The only place a concrete field surfaces is the worked example at line 137, which reads payload.tool_input?.command — a field that is otherwise undocumented.

Why it matters

I hit this building a cross-platform MCP/hook adapter that has to write hooks targeting many CLIs. Because the per-event keys aren't documented, the field names have to be reverse-engineered from the engine; an integrator can easily reach for the wrong key (e.g. assuming UserPromptSubmit's prompt is a plain string, or guessing tool_response instead of tool_output for PostToolUse) and get a silent no-op with no diagnostic. Documenting the schema makes hooks usable without reading agent-core.

The actual fields (verified against main)

All keys are emitted camelCase in source and snake_cased by toHookInputData/camelToSnake (packages/agent-core/src/session/hooks/engine.ts:176-184). Per-event keys, with their trigger sites:

Event Added stdin fields Source
PreToolUse, PermissionRequest tool_name, tool_input, tool_call_id permission/policies/pre-tool-call-hook.ts:15-17; permission/index.ts:139-144
PostToolUse tool_name, tool_input, tool_call_id, tool_output (truncated to 2000 chars) agent/turn/index.ts:735-739
PostToolUseFailure tool_name, tool_input, tool_call_id, error (an object: code/message/name/details/retryable) agent/turn/index.ts:735-738
PermissionResult tool_name, tool_input, tool_call_id, result permission/index.ts:170-219
UserPromptSubmit prompta ContentPart[] array (e.g. [{ "type": "text", "text": "..." }]), not a plain string agent/turn/index.ts:568-571
SubagentStart agent_name, prompt (preview-truncated) session/subagent-host.ts:381-386
SubagentStop agent_name, response (preview-truncated) session/subagent-host.ts:392-396
StopFailure error_type, error_message agent/turn/index.ts:484-486
Interrupt reason agent/turn/index.ts:524-525
SessionStart source ("startup" | "resume") session/index.ts:685-686
SessionEnd reason ("exit") session/index.ts (triggerSessionEnd("exit"))
PreCompact trigger ("manual" | "auto"), token_count agent/compaction/full.ts:373-378
PostCompact trigger, estimated_token_count agent/compaction/full.ts:388-392
Notification notification_type, title, body, severity, source_kind, source_id, sink agent/background/index.ts:130-140

(The doc already correctly notes the snake_case convention, so only the per-event field list is missing.)

Two fields are especially easy to get wrong and worth calling out explicitly in the docs:

  • UserPromptSubmit.prompt is a ContentPart[] array, not a string.
  • PostToolUse emits tool_output; the failure variant PostToolUseFailure emits error instead (and no tool_output).

Related

Issue #345 ("PreToolUse hooks: input mutation via updatedInput") is about the same hook output surface — a clearer payload reference would complement that discussion. PR #578 also touches this file (anchor-link fix only), so a small rebase awareness is worth noting if both land.

Proposed fix

Add a "Per-event payload fields" subsection (or a column on the existing Event Reference table) to docs/en/customization/hooks.md listing the keys above, and mirror it in docs/zh/customization/hooks.md. Docs-only, so no changeset/tests per CONTRIBUTING.

I'm happy to open the PR (title docs(hooks): document per-event stdin payload fields) if a maintainer confirms the table format you'd prefer (separate subsection vs. an extra "Payload fields" column on the existing table).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions