JSON events
The event stream written by hm agent --output json and --rpc.
hm agent -p --output json "prompt" writes what the agent does to standard output, one JSON object per line. Nothing else goes there: warnings and errors for people go to standard error. hm agent --rpc writes the same events, with a response to each command; see rpc.md.
hm agent -p --output json "list the packages" | jq -c 'select(.type == "tool_call")'
hm agent -p --output json "list the packages" | jq -r 'select(.type == "session_end").answer'Every line#
{"v":1,"type":"text_delta","session":"k3j9x2","time":"2026-11-06T10:00:00.123Z","text":"There are"}| field | |
|---|---|
v |
The format version, 1. |
type |
What the line reports; one of the types below. |
session |
The session it happened in: the one you started, or one of its sub-agents'. |
time |
When it was written, RFC 3339 in UTC. |
New types and new fields can appear without a new v. Ignore what you do not know. v changes only when a field changes meaning or goes away.
Order#
session_startis the first line andsession_endthe last, whatever happened in between. A stream withoutsession_endwas cut off.- A model reply is
message_start, thenthinking_delta,text_deltaandtool_startlines as it streams, thenusage, thenmessage_endonce it joined the session. - A tool call is
tool_call, thenapproval_neededandapprovalwhen it needs approval, orblockedwhen guard.yaml refuses it, thentool_result. The results of one message's calls are onemessage_endwith roletool. - Each turn ends with
turn_end. Onehm agentrun can hold several turns: queued messages and background sub-agents' reports start more. - Sub-agent lines carry the sub-agent's
sessionand can interleave with the parent's. Each sub-agent's turn ends withsubagent_end.
Types#
session_start#
| field | |
|---|---|
root |
The workspace folder. |
mode, provider, model |
What runs. model is empty for the provider's default. |
resumed |
Whether the session was saved before (--session, --continue). |
prompt |
The prompt, with piped input included. |
message_start#
role: "assistant". A reply has started streaming.
text_delta, thinking_delta#
text: more of the answer, or of the model's reasoning summary.
tool_start#
tool: the model began a call; its input is still streaming.
tool_call#
| field | |
|---|---|
tool, call_id |
The call. call_id ties it to its approval and result. |
summary |
What it will do: the command, or what changes. |
input |
The call's input as the model wrote it, as JSON. Input that is not valid JSON is a string. |
approval_needed#
The mode asks about this call. call_id, tool, category (read, edit, delete, shell, network, command, …), summary, and when they apply command, paths and reason.
approval#
call_id, tool, allow (bool), and note, which the model reads when the call is refused.
question#
call_id, text: the agent asks you something (ask_user). Over RPC, send answer; with -p nobody can answer, and the agent is told so.
blocked#
tool, reason: guard.yaml refused the call. No approval was asked.
tool_result#
tool, call_id, text (what the model reads), is_error (bool), and images when the result showed the model pictures, such as read on a PNG.
Each image is {"media_type": "image/png", "data": "<base64>", "width": 1568, "height": 784}; media_type is image/png, image/jpeg, image/gif or image/webp, and the size is what the model was sent.
message_end#
A message joined the session. role is user (your message), assistant (a reply) or tool (tool results), and text its text; empty for a reply that only made tool calls. images holds the pictures you sent, or the tool results gave back, as in tool_result.
usage#
One model call's tokens: input, output, cache_read, cache_write, and cost in USD (0 when unknown).
retry, error#
text: a model call failed and is retried soon, or something went wrong (the turn may go on).
warning#
text: something to know that does not stop the turn, such as the model having no vision, so its images are sent as [image omitted: model has no vision]. Given once per session.
compaction_start, compaction_end#
Older messages are being summarised to fit the model's window. compaction_end's text says what it saved; empty when it failed.
subagent_end, turn_end#
error: why the turn ended early; absent when it finished.
session_end#
| field | |
|---|---|
answer |
The final answer; empty when the run failed. |
exit_code |
The process's exit code: 0 done, 1 the agent failed, 3 a call was refused for want of approval, 130 interrupted. |
refused |
The tools refused for want of approval, in order; [] when none. |
usage |
The session's totals, as in usage. |
Bad usage (exit code 2) is reported on standard error before any session opens, so it writes no lines.
response#
RPC only: the answer to a command, with its id, command, ok, error and data. See rpc.md.