Runtime logs contract
Each recorded workflow run writes two append-only JSONL files:
.loom/.runtime/runs/<run_id>/
state.jsonl
events.jsonl
Each line is one JSON object. Both files carry run_id and timestamp.
Context may additionally include workflow_id, job_id, step_id and
command_id. These IDs connect output to the operation that produced it.
State records
state.jsonl records lifecycle transitions in append order. A record contains:
| Field | Meaning |
|---|---|
kind | Workflow, job, step or command scope. |
name | Readable operation name. |
status | Recorded lifecycle status. |
exit_code | Optional integer result, including zero when available. |
error | Optional protected error message. |
Read the records for an operation in file order to follow its state. A final workflow state records the run outcome when finalization completes. An interrupted run can end with a running state.
Event records
events.jsonl stores contextual messages and process output. Records contain
level, stream and message, with optional exit_code. message preserves
its string contents, including embedded newlines, blank lines, carriage returns
and output without a terminating newline. A record need not be one output line.
The order is the order in which recording accepted events; timestamps do not
establish an independent cross-process chronology.
Declared workflow secrets and known run redaction values are protected before recording. Review excerpts before sharing them because undeclared or generated secrets may appear in tool output.
Reading a run
Discover saved runs, then select an exact run ID:
loom runs
loom logs <run_id> --state
loom logs <run_id> --tail 30
loom logs <run_id> --json
MCP exposes loom_list_runs, loom_read_run and loom_read_events; see
the tools reference.
Discovery summarizes only complete workflow records from state.jsonl: the
directory run ID, latest workflow ID/status/optional exit and first/last workflow
timestamps in append order. Missing or zero timestamps stay unavailable. Rows
sort by first recorded timestamp descending, run ID ascending for ties, with
unavailable starts last. Empty/no-workflow state still lists the ID. Recorded
pending/running states are not process-liveness claims.
A missing runs directory is an empty result. Non-directory entries, symlink
aliases and invalid run-ID directories are ignored. A candidate with missing,
unreadable, nonregular, escaping or malformed state data fails discovery without
a partial successful list. A nonempty workflow run ID must match its directory.
Discovery writes no index or other run files. See loom runs.
Readers accept a complete final JSON object without a newline. They ignore an incomplete final object left by an interrupted append and reject malformed complete lines. They read these files directly. There are no hash inventories, manifest-selected histories or separate stdout/stderr segment files in this recording format.
Job artifacts
Declared artifact files are separate from workflow recording. Local runs publish
them beneath .loom/.runtime/artifacts/<run_id>/jobs/<job-id>/. Artifact messages
and failures use the same contextual event stream; the recording directory still
contains only the two JSONL files.