# $comment
Discriminated-union root (oneOf, keyed on `type`) — strictness is enforced inside each branch via `additionalProperties: false`; a root-level setting would be ignored.

# description
Discriminated union of all SSE events emitted by the AI service and bridged to the frontend. Keyed on the `type` field.

# $defs.AgentDelegateEvent.$comment
`agent` is the delegate; `from_agent` is the delegator. Naming only the target made delegation unrenderable as a tree — a second specialist entering was indistinguishable from a sibling of the first and from a child of it, so concurrent work could only ever be drawn as a flat list. `depth` is the delegator's own depth plus one, with Billy at 0.

# $defs.AgentStatusEvent.$comment
One agent's lifecycle on the turn. Before this, a client could see that an agent had started (agent_delegate) but never that it had stopped: `node_update` carries a status with no agent, and `stream_metrics.agents_used` only arrives once the whole turn is over. A concurrent view needs both edges — otherwise 'who is working right now' has to be inferred from whether tokens happen to be arriving, which is a guess that reads as a hang whenever an agent is thinking. `at_ms` is milliseconds since the turn began, so elapsed time is the server's measurement rather than a clock the browser started when it happened to notice.

# $defs.AgentMessageEvent.$comment
A specialist addressing another agent rather than the reader. These already existed as scratchpad findings, but reached the browser as anonymous `token` frames — so a note analyst wrote *for* architect rendered as prose apparently addressed to the user. Carrying the addressee makes the collective's internal traffic showable as what it is.

# $defs.TaskRow.$comment
`status` is pending|running|done|error|cancelled — rows never leave the list, so work that stopped being necessary retires as `cancelled`. `note` is what the owner is doing on this row right now; `assignee` is the specialist working it, so a surface can hang that specialist's own live row beneath this one. `check` is the observable state that settles the row, declared when it opens so ticking it is a claim against a bar already on screen.

# $defs.TaskListEvent.$comment
One agent's own task list. Rows are UPSERT-by-id against that agent's list, so the same event creates it, checks a row off, reworks a title, or appends new work — every agent (Billy and each subagent) keeps its own list under `agent`.

# $defs.UserInputEvent.$comment
The one human-in-the-loop gate envelope (user-input primitives). `kind` selects the primitive — ask (get information) / confirm (get a decision on an act) / hand (get a thing only the user can produce). `input_id` correlates the gate with the resume that answers it so two tabs cannot double-submit. Each kind reads only the fields it needs.

# $defs.UserInputEvent.properties.escalated_from.$comment
The specialist a gate was relayed from when a sub-agent needed the person; empty on a gate Billy raised himself. When set, `agent` is billy and the client badges the child.