Journal events
Every event the run journal and the headless stream write, with the name each record carries on the wire.
The event vocabulary
Journal event vocabulary — 3 sets exported from
src/engine/reference_vocabulary.rs
Run events
31 values from src/domain/mod.rs
The engine's event stream, as gantry's JSONL surfaces write it: the durable run journal at `.gantry/<plan>/history.jsonl`, which a resumed run replays to rebuild its feed, and the headless `--json` stream a watcher reads live. A record's token is its `t` field. Several tokens keep a spelling the Rust name no longer has, because a journal is git-tracked and travels with a merge: renaming the wire name would strand every already-committed history, so the encoder keeps writing the old one. A value with no token at all is an event that reaches a front-end in process and is written nowhere — a reader of a file will never meet it. The rows carry names and meanings, not payload fields: a record's fields are written by hand at the encoder's call site, one shape per event, and a list of them transcribed here would be a second copy nothing keeps true.
| value | wire name | what it means |
|---|---|---|
| run_started | run_started | The run began: its plan is split and building is about to start. It carries the plan's name and the whole unit roster, so a reader knows what the run means to build before any of it happens. The journal does not keep it — a resumed run rebuilds it from the roster on disk before replaying anything — so it is a record only the headless stream carries. |
| sprint_started | chunk_started | A unit of the run became the active focus. Every stage record that follows belongs to it until the next unit starts or the run ends. |
| stage_started | stage_started | One stage of the pipeline began — an agent stage, or a mechanical one such as the gate or the merge. It opens a card: which stage, on which unit, under which harness and model where an agent is about to run, and where its log is being written. |
| stage_progress | — | A heartbeat for the stage running right now: how long it has been going and what it is doing. It is never written to either JSONL surface, so a reader of a file sees a stage start and then finish with nothing in between. |
| stage_finished | stage_finished | The stage closed, carrying the stage outcome it closed with and a one-line summary of what it did. For an agent stage it also carries what the work cost: tokens, turns and duration. This is the record that says whether that stage's work stood. |
| agent_retrying | agent_retrying | An agent stage hit a transient failure — an overloaded API, a rate limit, a usage window that has not reopened yet — and is waiting before its next attempt. The run is waiting rather than hung and the unit's status has not changed; the stage still finishes normally if a later attempt succeeds. |
| gate_lock_waiting | gate_lock_waiting | A gate is waiting for the per-repository gate lock another run of the same repository holds, or has just taken it. Nothing has failed: the gate simply has not started yet. The journal does not keep it, because a resumed run contends for the lock again rather than replaying an old wait. |
| checkout_lock_waiting | checkout_lock_waiting | A merge back is waiting for the per-checkout merge lock, or has just taken it — the same waiting-not-hung signal as the gate lock, for the section that folds a run into your branch. Not journaled either, for the same reason. |
| sprint_finished | chunk_finished | A unit reached a terminal state, carrying the status it is being recorded under and, where it was built, the commit it produced. The ledger on disk holds the same verdict durably. |
| milestone_sprints_planned | milestone_chunks_planned | A milestone's own roster became known: the child units it was just decomposed into. Only a milestone-structured run writes it, and it arrives before any of those children's stage records. |
| roster_updated | roster_updated | A flat run's top-level roster changed mid-run: a replan inserted, renumbered or retitled the units still to build. It carries the whole current roster, so a reader replaces what it had rather than guessing at the difference. A run whose plan never changed never writes one. |
| recovery_attempted | recovery_attempted | The recovery ladder spent an attempt on a unit whose review found the work incomplete — a retry or a replan — or halted after reaching its cap. It carries the reviewer's own note about what was missing, and is the audit row behind a unit that took more than one pass. |
| map_started | — | The run is a map fan-out rather than a sequential build, and this says how many units it will work at once. It is never written to either JSONL surface: a reader of a file sees the fan-out in the pattern journal's own declaration instead. |
| progress_updated | progress_updated | The driver published where the run has got to, already phrased for each surface that shows it. A run whose shape is not a roster of sprints says its own progress this way instead of leaving every surface to invent one. |
| pattern_journal | — | One pattern journal record, delivered live beside the run stream so a consumer can follow the executing structure as it happens. It is never written to the run journal: the pattern engine writes those records itself, durably, and they are the pattern journal records set below. |
| prompt_needed | prompt_needed | The run needs a human answer before it can go on, and is waiting for one. It carries the question and the prompt kind that says what sort of answer will do. The journal does not keep it: a resumed run asks again live rather than replaying a question you may already have answered. |
| prompt_resolved | prompt_resolved | A waiting prompt was answered — by a person, or by the safe default a headless run falls back to — and the run is moving again. Like the ask, only the headless stream carries it. |
| assistant_console_up | — | The run's Gantry Agent console is up and can take chat turns, under the harness and model named. It is never written to either JSONL surface — it tells a front-end its assistant affordances are live, and a file has none. |
| assistant_console_skipped | — | The run deliberately has no assistant console, and this is the reason to show wherever one would have been offered. Like the console coming up, it is never written to either JSONL surface. |
| assistant_selection_pending | assistant_selection_pending | Someone asked the assistant to answer as a different harness or model, and the console stored that for the next turn. A reply already in flight keeps the identity it started under. |
| assistant_selection_activated | assistant_selection_activated | The pending assistant identity was taken up for a turn just submitted, and is now the one answering. |
| assistant_selection_failed | assistant_selection_failed | An assistant identity was asked for that the console cannot use, and the reason says why. Nothing changed: the assistant is still whatever it was. |
| agent_reply_identity | agent_reply_identity | The harness and model that are about to produce the assistant reply for a chat turn. It is journaled, so a transcript read back later attributes each answer to what actually wrote it rather than to whatever is selected now. |
| agent_reply_started | agent_reply_started | The assistant began answering a chat turn. It opens the message; the text itself arrives when the turn closes. |
| agent_reply_chunk | — | One fragment of an assistant reply still streaming in. It is never written to either JSONL surface — the whole text arrives when the turn finishes — so a reader of a file sees complete replies only. |
| agent_reply_finished | agent_reply_finished | The assistant's answer to a chat turn is complete, and this carries the whole of it rather than the last fragment. A resumed run replays these, which is how the conversation is still there afterwards. |
| agent_reply_failed | agent_reply_failed | An assistant turn failed before it produced a complete answer, and the reason says why. Only that turn is lost: the run, and any prompt waiting on you, are untouched. |
| settings_write_completed | — | A settings change asked for from a front-end finished, and the refreshed catalog to redraw from comes with it. It is never written to either JSONL surface: it answers a front-end's own request, and belongs to no run's history. |
| reconciled | reconciled | Your branch advanced while the run was building, and the run folded that work into its own branch: which files had to be reconciled, and which of your commits were folded in. Written on every integrate, clean or not, so what the merge absorbed stays auditable after the fact. |
| stopped | stopped | The run halted and is handing back to you, with the diagnosis to act on and, where one was written, the path of a fuller report. A terminal record, and one only the headless stream carries: what a stopped run is resumed from is the ledger and the worktree, not this. |
| run_complete | run_complete | Every unit is built and merged back: the run is over and there is nothing left to resume. The other terminal record, and like the stop it goes to a headless watcher rather than into the journal. |
Pattern journal records
6 values from src/engine/run/pattern_interpreter.rs
The pattern engine's own durable journal, one record per line in `.gantry/<plan>/pattern-events.jsonl`. It sits beside the run journal rather than inside it: the run events carry the cards a front-end draws, and these records carry the shape the interpreter actually executed — the declared hierarchy, and the task-id path of everything that happened under it. Every positioned record carries that path, so a reader takes the structure from the path rather than inferring it from the order records arrive in. The token is the record's own discriminant, from the serialization the interpreter journals through.
| value | wire name | what it means |
|---|---|---|
| structure | structure | The shape the run is about to execute, declared once at the start: which pattern is running and what its levels are called, outermost first. A reader takes its vocabulary from this rather than assuming every run is milestones and sprints. |
| fan_out | fan-out | A fan-out began, and this declares its parallel shape up front: every task that will run under it and how many run at once. It arrives before any of them start, so the whole set is known before the first result. |
| step | step | One step of the pattern reached a point in its life — the step phases below — at one position in the task tree. This is the bulk of the journal: what kind of step ran, where, and whether it was starting, ending, or noting something on the way. |
| script_result | script-result | A command the pattern ran finished, recorded whole: what it exited with, what it printed, and the verdict the run drew from it. A replay of the run reads the result from here rather than running the command a second time. |
| progress | progress | A loop published where it has got to, at one position in the task tree — the same progress phrasing the run stream carries, but placed in the structure rather than standing for the whole run. |
| work_list_inserted | work-list-inserted | A work list read again mid-run had grown, and these are the tasks that appeared, under the position they belong to. Announced rather than absorbed quietly, so a reader sees work arrive instead of finding more of it than the run declared. |
Step phases
3 values from src/engine/run/pattern_interpreter.rs
Which point of a step's life a journaled step record is at. Two of them bracket a step that ran; the third records something worth reading that did not end it. The token is from the same serialization the record it rides on is written through.
| value | wire name | what it means |
|---|---|---|
| started | started | The step began. Every step that ran has one of these, and whatever it did is recorded at the same position afterwards. |
| finished | finished | The step is over. Whether the run carried on from there, and what it did next, is what the records after it say. |
| note | note | The step recorded something worth reading without ending — a fall-through, a degrade, a decision taken and carried on from. Nothing failed and the run kept going. |