Quick Start
1
Decode a frame
decodeEvent never throws. Every rejection is a value with a reason, so a client can count them.2
Stop at the terminal event
The 11 Events
Every event carriesmsgId. Fields listed are the ones beyond that.
How A Turn Streams
Fields That Trap Readers
Terminal events are mutually exclusive and final. After
end, cancelled, or error, nothing else may follow. A cancelled turn is never persisted, so no end and no usage follow it.Unknown
ErrorKind degrades to "internal". decode.ts maps any kind it does not recognise to "internal" rather than dropping the event, so a newer engine’s category still reaches the user.Error Kinds
ErrorKind selects the recovery the UI offers.
Best Practices
Trust tool_result.ok, never the output
Trust tool_result.ok, never the output
ok is the only signal of tool success. Inferring success from a non-empty output is the exact defect the field prevents.Route approvals by approvalId
Route approvals by approvalId
Bind a decision to a row by
approvalId, not by position — position holds only while exactly one approval is outstanding.Treat null as a real value
Treat null as a real value
For
end.userIndex and tool_result.seconds, null means “unknown / not persisted”, which is different from 0 and from absent.Related
Approvals & Cancellation
The human-in-the-loop flow on mobile.
Capabilities & Gaps
Which events each engine emits today.

