Kiro IDE hook payload - empirical reference
How Kiro IDE delivers context to a runCommand hook. The channel differs by
IDE generation:
- Pre-1.0 (0.12-main): context arrives through the
USER_PROMPTenvironment variable (camelCase JSON). Stdin is opened but never written or closed - reading it hangs. - IDE >= 1.0 (1.x): context arrives as JSON on stdin (snake_case:
{ tool_name, tool_input, tool_response }).USER_PROMPTis empty.
Current adapter behavior: the shipped adapter reads ONLY the USER_PROMPT
environment variable (the pre-1.0 channel). It never reads stdin. On IDE 1.x,
where USER_PROMPT is empty, the two payload-dependent targets
(audit-and-sensors, log-subagent) fire but no-op with a visible hook drop.
The remaining hooks are payload-independent and work on both generations. The
stdin context channel is planned as a follow-up enhancement.
Pre-1.0 channel: USER_PROMPT env var
Captured live on Kiro IDE 0.12-main by registering probe .kiro.hook files
that dumped stdin, argv, and the full environment.
- stdin is opened but never written or closed, so
Bun.stdin.text()hangs. USER_PROMPTis a JSON string of the shape:{ "toolName": "fs_write", "toolArgs": {}, "toolResult": "Created the /abs/path/file.md file.", "toolSuccess": true }
IDE 1.x channel: stdin (snake_case)
Captured live on Kiro IDE 1.0.165. The stdin payload shape (field-verbatim from the probe):
{ "session_id": "sess_...", "hook_event_name": "PostToolUse", "cwd": "/path/to/project", "tool_name": "execute_bash", "tool_input": {}, "tool_response": "Output:\n...\nExit Code: 0" }
USER_PROMPTis empty on 1.x.- No
toolSuccess/tool_successfield - only an explicitfalse(which 1.x never sends) triggers the #417 failed-write guard; absence falls through. tool_inputis always{}on both generations - the IDE never passes tool inputs.
Note: The adapter does not yet consume the 1.x stdin channel. This section documents the observed payload shape for the follow-up implementation.
VSCODE_IPC_HOOK / VSCODE_PID are also present in the IDE (absent on the CLI),
but the adapter keys off USER_PROMPT as the context channel.
Per-event captures
| Event | toolName |
toolArgs |
toolResult |
recoverable? |
|---|---|---|---|---|
| postToolUse(write) - create | fs_write |
{} (empty) |
Created the <ABS_PATH> file. |
path: from toolResult prose only |
| postToolUse(write) - edit | str_replace |
{} (empty) |
Replaced text in <ABS_PATH> |
path: from toolResult prose only |
| postToolUse(write) - append | fs_append |
{} (empty) |
Appended the text to the <ABS_PATH> file. |
path: from toolResult prose only |
| postToolUse(shell) | execute_bash |
{} (empty) |
Output:\n<stdout>\n\nExit Code: 0 |
command: not recoverable (only stdout) |
Critical limitations
toolArgsis always{}. The IDE never passes tool inputs. So the written file path must be parsed out of thetoolResultprose, and the shell command is not present at all (only its stdout + exit code).- Stdin is not read by the current adapter. On pre-1.0 it hangs (never
written/closed); on 1.x it carries the payload but the adapter does not
consume it yet. The adapter reads
process.env.USER_PROMPTonly. - Paths in
toolResultare workspace-RELATIVE, but the core hooks compare against an absolute record root - so the adapter resolves them to absolute before forwarding.
Consequences for each hook
- audit-logger / sensor-fire - recoverable on pre-1.0: scrape the file path
from
toolResult, resolve to absolute, feed the core hooks the Claude-shaped{tool_input:{file_path}}. A write-class tool whose wording does not match a known pattern records a visible hook-drop (never a silent no-op). On IDE 1.x these targets no-op (USER_PROMPT is empty, stdin not read). - runtime-compile - the shell command is unrecoverable, so the IDE path
drops the command filter and gates purely on the audit tail (with an mtime
idempotency guard so a lingering transition - e.g. after
WORKFLOW_COMPLETED - does not recompile on every subsequent shell command).
- sync-statusline - the IDE gives no task payload, so it derives the current
stage from the latest
STAGE_STARTEDin the audit tail. This is a forward-only mirror: it never rewindsCurrent Stageto a completed or skipped stage, and never fires when the workflow is notRunning(guards against resurrecting a finished workflow). Wired to theshellevent - thespecevent never fires in the IDE. - session-start / stop - need no payload; unchanged. (
session-endhas no v2 registration - see the harness guide for the rationale.) - log-subagent - on pre-1.0, recovers the delegate identity from
toolResult. On IDE 1.x, no-ops with a visible hook drop (USER_PROMPT is empty, stdin not read).
toolResult path-extraction patterns
| toolName | wording | canonical tool |
|---|---|---|
fs_write |
Created the <PATH> file. |
Write |
str_replace |
Replaced text in <PATH> (may carry a trailing (N occurrences)) |
Edit |
fs_append |
Appended the text to the <PATH> file. |
Edit |