Skill Tracer
Skills › Scientific Agent Skills › pi-agent › json.md

json.md

79 lines · skills/pi-agent/references/json.md at 5f2bc03

Open on GitHub
1# JSON Event Stream Mode
2
3Source: https://pi.dev/docs/latest/json
4
5Reviewed against Pi 0.99.2 and the package versions listed in `../SKILL.md` on 2026-09-30.
6
7Use JSON mode for one-shot prompts that output all session events as JSON lines to stdout.
8
9```bash
10pi --mode json "Your prompt"
11```

JSON Event Stream Mode

Source: https://pi.dev/docs/latest/json

Reviewed against Pi 0.99.2 and the package versions listed in ../SKILL.md on 2026-09-30.

Use JSON mode for one-shot prompts that output all session events as JSON lines to stdout.

pi --mode json "Your prompt"
Raw lines 1 to 12
13## Event Types
15Wire events use `JsonAgentSessionEvent`, which matches `AgentSessionEvent` except that streaming message updates omit cumulative snapshots:
17```typescript
18type WithoutPartial<T> = T extends { partial: unknown } ? Omit<T, "partial"> : T;
20type JsonAssistantMessageEvent<T> = T extends { type: "toolcall_start"; partial: unknown }
21 ? WithoutPartial<T> & { id: string; toolName: string }
22 : WithoutPartial<T>;
24type JsonAgentSessionEvent =
25 | Exclude<AgentSessionEvent, { type: "message_update" }>
26 | { type: "message_update"; usage: Usage; assistantMessageEvent: JsonAssistantMessageEvent<AssistantMessageEvent> };
27```
29`AgentSessionEvent` is `AgentEvent` plus session-level events:
31- `agent_settled` — no further automatic continuation
32- `queue_update` — `{ steering: readonly string[], followUp: readonly string[] }`, emitted whenever either queue changes
33- `compaction_start` — `{ reason: "manual" | "threshold" | "overflow" }`
34- `compaction_end` — `{ reason, result: CompactionResult | undefined, aborted, willRetry, errorMessage? }`
35- `auto_retry_start` — `{ attempt, maxAttempts, delayMs, errorMessage }`
36- `auto_retry_end` — `{ success, attempt, finalError? }`
37- `summarization_retry_scheduled` — `{ attempt, maxAttempts, delayMs, errorMessage }`
38- `summarization_retry_attempt_start` — `{ source: "branchSummary" }` or `{ source: "compaction", reason }`
39- `summarization_retry_finished`
41Base `AgentEvent` types:
43- `agent_start`, `agent_end` (`messages`, `willRetry`)
44- `turn_start`, `turn_end` (`message`, `toolResults`)
45- `message_start` (`message`), `message_update` (`usage`, `assistantMessageEvent`), `message_end` (`message`)
46- `tool_execution_start` (`toolCallId`, `toolName`, `args`), `tool_execution_update` (+ `partialResult`), `tool_execution_end` (`result`, `isError`)

Event Types

Wire events use JsonAgentSessionEvent, which matches AgentSessionEvent except that streaming message updates omit cumulative snapshots:

type WithoutPartial<T> = T extends { partial: unknown } ? Omit<T, "partial"> : T;

type JsonAssistantMessageEvent<T> = T extends { type: "toolcall_start"; partial: unknown }
  ? WithoutPartial<T> & { id: string; toolName: string }
  : WithoutPartial<T>;

type JsonAgentSessionEvent =
  | Exclude<AgentSessionEvent, { type: "message_update" }>
  | { type: "message_update"; usage: Usage; assistantMessageEvent: JsonAssistantMessageEvent<AssistantMessageEvent> };

AgentSessionEvent is AgentEvent plus session-level events:

  • agent_settled — no further automatic continuation
  • queue_update — { steering: readonly string[], followUp: readonly string[] }, emitted whenever either queue changes
  • compaction_start — { reason: "manual" | "threshold" | "overflow" }
  • compaction_end — { reason, result: CompactionResult | undefined, aborted, willRetry, errorMessage? }
  • auto_retry_start — { attempt, maxAttempts, delayMs, errorMessage }
  • auto_retry_end — { success, attempt, finalError? }
  • summarization_retry_scheduled — { attempt, maxAttempts, delayMs, errorMessage }
  • summarization_retry_attempt_start — { source: "branchSummary" } or { source: "compaction", reason }
  • summarization_retry_finished

Base AgentEvent types:

  • agent_start, agent_end (messages, willRetry)
  • turn_start, turn_end (message, toolResults)
  • message_start (message), message_update (usage, assistantMessageEvent), message_end (message)
  • tool_execution_start (toolCallId, toolName, args), tool_execution_update (+ partialResult), tool_execution_end (result, isError)
Raw lines 13 to 47
48## Output Format
50First line is the session header:
52```json
53{"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}
54```
56RPC shares these event shapes but emits no session header. Split records on LF only. The following sequence is schematic: message and usage objects are abbreviated, and other events may interleave.
58```json
59{"type":"agent_start"}
60{"type":"turn_start"}
61{"type":"message_start","message":{"role":"assistant","content":[]}}
62{"type":"message_update","usage":{},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
63{"type":"message_end","message":{}}
64{"type":"turn_end","message":{},"toolResults":[]}
65{"type":"agent_end","messages":[],"willRetry":false}
66{"type":"agent_settled"}
67```
69`toolcall_start` additionally carries `id` and `toolName`; nested execution events may carry `parentToolCallId`. Session events also include `entry_appended`, session-info/thinking changes, and queue lifecycle notifications; tolerate new event types.
71`message_update` records are delta-only: they omit both the cumulative `message` field and `assistantMessageEvent.partial` to keep stream size linear. The top-level `usage` field carries the latest cumulative provider-reported usage and may stay zero when a provider only reports usage at completion. Assemble live text, thinking, or tool-call arguments from `contentIndex` and `delta`; `message_end` holds the final authoritative message.

Output Format

First line is the session header:

{"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}

RPC shares these event shapes but emits no session header. Split records on LF only. The following sequence is schematic: message and usage objects are abbreviated, and other events may interleave.

{"type":"agent_start"}
{"type":"turn_start"}
{"type":"message_start","message":{"role":"assistant","content":[]}}
{"type":"message_update","usage":{},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
{"type":"message_end","message":{}}
{"type":"turn_end","message":{},"toolResults":[]}
{"type":"agent_end","messages":[],"willRetry":false}
{"type":"agent_settled"}

toolcall_start additionally carries id and toolName; nested execution events may carry parentToolCallId. Session events also include entry_appended, session-info/thinking changes, and queue lifecycle notifications; tolerate new event types.

message_update records are delta-only: they omit both the cumulative message field and assistantMessageEvent.partial to keep stream size linear. The top-level usage field carries the latest cumulative provider-reported usage and may stay zero when a provider only reports usage at completion. Assemble live text, thinking, or tool-call arguments from contentIndex and delta; message_end holds the final authoritative message.

Raw lines 48 to 72
73## Example
75```bash
76pi --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'
77```
79For bidirectional control, use RPC instead of JSON mode.

Example

pi --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'

For bidirectional control, use RPC instead of JSON mode.

Raw lines 73 to 79