Documentation / Agents

Reports and signals

How a card returns a result, how the orchestrator notices it finished, and what "parked" means.

A card reports a structured result that outlives it: the report lives in the table, not in the scrollback. That is how an orchestrator reads what happened without parsing ANSI.

The report

Each report carries:

  • the payload, with ok: true for success and ok: false for a declared failure;
  • a verdict (aprovado / reprovado / null), when it is a review;
  • the role of the reporter at the moment of the report — that is how you tell a review from an implementer approving itself;
  • the channel it came in through, stamped by the server.

Reports are numbered; reading with the last number seen returns the next one, without re-reading the same and without losing old rounds.

Knowing a card finished

The app pushes a text pointer to whoever should know: the card that spawned it, or the last directive sent, or the board’s orchestrator mark. It is not a system notification — nothing blinks outside the window, and that was asked for, not forgotten. There are four notices:

Notice When it fires
report available the card called report
exited without calling report the process died owing a report
idle without calling report it stayed quiet beyond the floor, with a live task
came up and produced no byte at all 30s with no single output — the process is alive and silent, and nothing was terminated

The third has three different sentences, and the difference is the mechanism, not style: with no agent reading the line, the card could not report and the sentence does not accuse; with the turn declared finished by the card itself, the accusation is backed by a fact it emitted; with no turn fact, it is inferred silence — the sentence says how long the card has been quiet and asks for a check, instead of asserting abandonment. An alarm that is wrong teaches the orchestrator to ignore it, and that is how the true signal dies.

The last is the only one that is not about silence after working, but about never having spoken: it is the honest name of a PTY that produced not a single byte. It warns, never kills — a process that just took a while to paint cannot be destroyed by a clock.

The default remains querying the status and then reading the report. card_status answers:

State What it means
running the declared turn ended and output arrived after — a new turn began
idle turn closed, or stopped waiting for you
at-prompt free shell at the prompt (a shell has no turn, so it is never idle)
waiting blocked on a consent decision
exited the process died
no-output came up and emitted no byte; the first byte erases the state on its own
unknown the output does not distinguish work from repaint

unknown is not an app failure: a stopped TUI repaints the screen forever, and a TUI can be running inside a bash card. Read it as check the screen before deciding a dispatch — never as free.

Talking to a live card

Sending text to a card is queuing, and it returns right away. The text can end in a few different states, and the difference matters:

State What happened
queued it is in the card’s queue
delivered confirmed on screen — the agent has the text
parked the provider’s queue held it; the agent has not seen it yet
unconfirmed it wrote, with no evidence on screen
failed visibly stuck and cleared — resend
cancelled the author died before the delivery went out

parked is not delivered. That distinction was born from real damage: a “stop now” notice sat in the queue and arrived after the damage. A correction channel that only delivers at the end of the turn is not a correction channel.

Lineage

Who created whom is recorded with reason, provider and depth, and survives a restart. Every agent spawn declares a reason — it is the only field the app cannot derive. There is a depth cap on the spawn chain.