trace
Turn one recorded run of a flow (a trace file of steps - who called whom, with what values) into a sequence diagram, or compare two runs and mark what changed (added, removed and changed steps). Use w
SKILL.mdskills/trace/SKILL.md
GitHubTrace: a real run as a sequence diagram
A diagram drawn from a real run shows what happened, with real values. A diagram drawn from code shows what should happen. Use this skill when the real run matters.
trace file ─► trace run.json ─────────► Mermaid ─► flow (fd / pic)
two traces ─► trace a.json b.json ────► Mermaid with [+] [-] [~] marks
The trace file
One JSON object. Only steps is required, and each step needs from, to and label.
{
"title": "Checkout",
"participants": [{"id": "api", "label": "Orders API"}],
"ignore": ["orderId"],
"steps": [
{"from": "app", "to": "api", "label": "POST /orders", "t": "2026-10-11T09:00:00Z", "values": {"orderId": 1041}},
{"from": "api", "to": "queue", "label": "order.created", "kind": "async", "note": "fires after commit"}
]
}
| Field | Meaning |
|---|---|
kind |
sync (default, solid arrow), reply (dashed), async (dotted) |
t |
ISO time or epoch milliseconds; used by --time |
values |
what the step carried; shown on the arrow and compared in a diff |
note |
a note box under the arrow |
participants |
optional order and display names; others appear in order of first use |
ignore |
value keys that change every run (ids, times); left out of the diff |
A bare array of steps, or JSONL with one step per line, also works. JSONL suits a recorder that appends steps as they happen.
Rule for anyone who writes a recorder: keep the label stable between runs (update order, not update order 1041). Put anything that changes every run in values, and list it in ignore. The diff matches steps on from, to and label, so a label that holds an id never matches.
Commands
"${CLAUDE_SKILL_DIR}/trace" run.json --text # one run as chat text
"${CLAUDE_SKILL_DIR}/trace" run.json --time --text # with +120ms before each arrow
"${CLAUDE_SKILL_DIR}/trace" a.json b.json --text # b compared with a
"${CLAUDE_SKILL_DIR}/trace" a.json b.json --context 2 # fold unchanged steps, keep 2 around each change
"${CLAUDE_SKILL_DIR}/trace" a.json b.json --json # diff rows for other tools
- Without
--text, the output is Mermaid. Pipe it intodiagrams:flow:trace a.json b.json | fd -, or save it and runpicfor a picture page. - A diff prints one summary line to stderr:
trace: 1 added, 0 removed, 1 changed, 5 same. The exit code is 0 when the runs match, 1 when they differ, and 2 on an error, so scripts can use it as a check. - Marks on the arrows:
[+]only in the second run,[-]only in the first,[~]the same step with other values (status: PAID → FAILED). --ignore id,timeadds keys to the file's ownignorelist.--values none|short|allsets how many values an arrow shows (default: the first 3).
Fit
- Each participant is one column, and a long label widens the gap between two lifelines. Five participants with values often pass 90 columns. Then use
--values none,--context, or a picture page:trace a.json b.json > d.mmd && pic d.mmd -o d.html. fdnotes a lifeline that a label covers. This is a layout limit of the text renderer; the picture page has no such limit.
Example
examples/order.a.json and examples/order.b.json are two runs of one checkout. In run B, the payment fails and the worker queues a retry:
"${CLAUDE_SKILL_DIR}/trace" examples/order.a.json examples/order.b.json --context 1
Tests: node --test skills/trace/*.test.mjs from the plugin root.