Runs, their journal and their saved context
A run's statuses, its journal and every event in it, the hop cap, its workspace and branch, continue, retry and run again, what each run tool answers, and the context it saves at go.
A run starts from a set of approved context. Smith saves it when you press go so the run can be recovered later.
This page also says what a run is made of and how to read one. File:line citations are in parentheses. The graph a run executes is on templates and nodes.
01statuses#
A run has one of nine statuses.
running: the run is taking envelopes and starting nodes.paused: nothing new starts. The current node finishes, and sends are still accepted.draining: the run accepts no more sends and ends ascompletedonce nothing is queued or active.stopping: a stop was asked for. Outstanding work is cancelled, and the run ends asstopped,rejectedorfailedonce it has settled.suspended: smith shut down with the run unfinished. Its previous status is kept, and a later owner picks it up.completed: the run drained cleanly.stopped: the run was stopped.failed: the run ended with an error.rejected: the operator turned the work down at a human gate. Nothing landed, and it is neither stopped nor failed.
completed, stopped, failed and rejected are terminal.
02the journal#
Each run keeps an append-only journal at <patch root>/.smith/patch-runs/<id>/events.jsonl. Every line is one event with a strictly increasing sequence. It is the only durable history of the run, and every status, view and tool below is read from it. The event types are at, and there are 60. The run_events and run_query tools read it, so you rarely need the raw file.
the run
patch.started: the run began.patch.paused: the run was paused. It is also written on recovery when the desk asks for a paused restart.patch.resumed: a paused run went back to running.patch.drain_started: the run began to drain.patch.completed: a draining run settled.patch.stop_requested: a stop began, with the cause inerrorwhen there is one. Outstanding envelopes and invocations are cancelled.patch.stopped: a stopping run settled with no error. Its status isstopped, orrejectedfor a reject.patch.failed: a stopping run settled with an error recorded, or a stalled run was failed.patch.suspended: smith closed with the run unfinished.patch.recovered: a new owner took the run after a restart. Any invocation that was active was journaled as interrupted first.patch.document_committed: an edit to the patch document that left its topology unchanged.topology.committed: an edit that changed the topology.
envelopes and cords
envelope.queued: an envelope was put on an inlet's queue.envelope.delivered: an envelope left the queue and became an invocation's trigger.envelope.replaced: alatestcord replaced an envelope from the same cord that was still queued.envelope.dropped: a full queue dropped the oldest or the newest envelope, by its overflow policy.envelope.rejected: the envelope was refused, by a full queue with therejectpolicy or because its payload failed the inlet's schema.envelope.cancelled: a queued envelope was removed, by a cancel or a stop.outlet.emitted: a node emitted an envelope on an outlet.feedback.limit_reached: an envelope would cross the hop cap and there was nowhere to send it, so the run is stopped. See the hop cap.feedback.limit_diverted: an envelope would cross the hop cap and was sent to the human gate instead.
invocations
invocation.started: a node began work on an envelope.invocation.completed: the node finished.invocation.failed: the node failed, with the error.invocation.cancel_requested: a cancel or stop asked a running node to stop.invocation.cancelled: the node stopped after that.invocation.interrupted: the owner went away mid-invocation. The trigger is queued again for the next owner.node.observed: a node noted something in passing, such as a decision recorded, a workspace handoff sealed or landed, a capability proof or a skipped check. Itsreasonsays which.
gates
gate.requested: a human gate is waiting for the operator.gate.resolved: the operator approved.gate.rejected: the operator sent it back or turned it down, with their reason.
model nodes
runtime.started: the node's runtime began.runtime.emitted: the runtime emitted an output for the node. What each one carries is not checked.runtime.completed: the runtime finished and reported its result.attempt.pending: an attempt was created.attempt.admitted: the profile admitted the attempt.attempt.starting: the launch was requested.attempt.running: the process is running.attempt.terminating: the process boundary is being torn down.attempt.terminal: the attempt ended, with its reason.attempt.retry_scheduled: the attempt failed with a retryable reason, and another will start after a backoff.attempt.parked: the attempt was rate limited. The node waits for the limit to reset without holding a scheduler slot, then resumes.context.resolved: the node's context sources were resolved.context.failed: they could not be, with the error.session.fallback: a node that should have resumed its session started fresh, because the session was missing or the workspace had been reset.
workspace and secrets
workspace.acquired: a node took its workspace.workspace.released: it gave the workspace back, with the state it left.workspace.handoff_consumed: a node consumed a sealed handoff.secret.used: a secret was resolved for a node. The journal holds the ref and node, never the value.secret.unreadable: a secret ref could not be read, and the node fails with that reason.
capabilities
capability.call_started: a node began a capability call.capability.call_completed: the call finished.capability.call_failed: the call failed.
checks
checks.started: a check began. See checks.checks.progress: a check reported progress.checks.finished: a check finished.checks.none: no checks ran.checks.terminal_failure: the checks failed in a way that repair cannot fix.repair.hop: a failed round of checks sent the baton back to work for a repair.format.finished: a formatter thatworkspace_handoffruns on the changed files finished.
03the hop cap#
Every envelope counts its hops, and a cord that loops back makes the count grow. The cap ends a loop that does not converge.
- The scheduler's default is 64 hops.
- Harness launches use 32, with room for 32 queued envelopes and one invocation at a time.
- A human gate's decision starts the count from zero again.
- If the template has exactly one human gate, an envelope that would cross the cap goes there with a reason, and
feedback.limit_divertedis journaled. With none or several,feedback.limit_reachedis journaled and the run is stopped.
04workspaces#
A ticket run builds in a worktree of its own, made at launch beside the work clone, so several runs can build at once.
- The path is
<checkout>.runs/<first 12 characters of the launch id>. - The branch is
smith/<ticket-short>-<run-short>, from short forms of the ticket and run ids. The run's worktree is switched to it before its first baton. - A folder that is not a git checkout of its own, or has no commit, is built in place, one run at a time.
- Leftovers are carried: a continued run gets the old run's changes against its base as uncommitted changes in the new worktree, untracked files included and ignored ones not. The diff is applied three-way, and a file that cannot merge keeps conflict markers for the worker.
05continue, retry and run again#
These are all cards. The operator presses the button on a card, and nothing starts by itself.
- Continue (
propose_run_continue): a failed or stopped ticket run starts a new run at theworknode with the old run's newest baton, on the tree it left. Intake and plan are skipped. It is refused for a run that has not finished, has completed, has landed, never reached work, or has no acceptance list on its baton. - Run again (
propose_run_again): a finished run drafts a new launch card for the same ticket and template at the same preset, or with the same inputs for a template run. The card records that it follows the old run. - Retry (
propose_retry): a failed node in a live run gets its last input again, with a fresh attempt budget. It is refused when the node has not failed or the run has failed; use continue then. The scheduler'sRetrykeeps the parent envelope of the trigger it replays.SendandBangput a message or a bang on any inlet. - Cancel removes a queued envelope and its known descendants and cancels the active invocations they triggered.
- Pause and continue (
propose_pause,propose_continue): pause lets the current node finish and starts nothing new. Continue resumes a paused run. - Stop (
propose_stop): stops the run for good, and nothing it was doing is landed.
06what the run tools answer#
All eight only read. Each answers from the journal.
run_list: runs across every patch, most recently updated first, with status, active nodes and pending gates. Thepatch_idandrun_idgo to the other tools.run_state: one run's live projection: status, topology, active invocations and queue sizes.run_summary: one call for what is going on: status, active nodes, time to the first gate, retry, repair-hop and send-back counts, the hop cap and whether it was hit, and the last failure.run_query: a named question that gets a few typed rows and never the raw journal.checksis the latest round per check,failurethe terminal reason, node, check and first error,sendbackseach send-back's round and why,timelineeach node invocation with its start, end and outcome, andhostthe systemd units on Linux. Read it beforerun_events.run_events: a page of the journal after a sequence cursor, oldest first. Filter by event type and node, and passbriefto drop payloads.run_gates: the run's pending gates with their exact payload, and the decisions made.run_detail: one invocation, message, queue or failure, from the recorded state and causal events.run_stats: the cross-run numbers the pages show, over a window, by model, check, file, persona, send-back, cost, end state and more. Persona is never windowed.
07retained context#
The snapshot of the exact context text a run was approved with: the persona, memory, knowledge and plugged-asset bodies, flattened by contextsource.Flatten.
- Where: at go,
retainHarnessContextwrites each one to<patch root>/.smith/context/<sha256 of content>(mode 0600, create-exclusive, fsynced) before the run starts. - Why: recovery needs the approved bytes even if the memory renderer is offline or changed. There is no live-source fallback, and deleting a launch deletes its context.
loadHarnessContextre-checks each file's hash and size. - Real:
harnessContextDirrequires.smithand.smith/contextto be directories, not files and not symlinks (checked with Lstat). - Private on Linux and macOS: no group or other permission bits (
perm & 0o077 == 0; created 0700). Fix withchmod 700. - On Windows the mode check always passes (
privateMode), because every directory reports 0777. Only the directory and symlink checks apply, and directory fsync is skipped. See windows.
If either folder fails these checks the run does not start. See troubleshooting for the messages.