Tracing a run
Open one run as a timeline in Perfetto: each agent's sessions in rows, a slice for every thing it did, with the prompts and tool output attached. Use this after a long run, to see what each agent did, in what order, and where the time went. By the end of this page you will have found a run, exported its trace and read it.
Try it
- In the project you ran in, type
/epics. Every run here is listed, newest first. - Move to the run with ↑ ↓ and press enter. In a long list, press / first (or the Search… button) and type part of the run's flow, task or name to narrow it.
- Choose export epic. Humanize gathers the trace and packs the run into an archive, then says what it wrote under the list.
- Open ui.perfetto.dev and drop in
traces/export.trace.jsonfrom the archive. Nothing is uploaded: Perfetto reads the file in your browser.
To read a run without leaving the terminal, choose Exomyth instead of export epic: every session is a row of bars under the session that started it. w s zoom, a d pan, ← → step from span to span, enter shows the one under the cursor whole, p its process, and v picks a stretch from one span to another and sums it by category. tab turns it into a flame of where that stretch went, each agent with its sessions merged or apart, weighed by time, tokens in or out, or count; and again into a table of every slice name, sorted by any column. Every key is in Exomyth. The run going opens there from the monitor as well, with ctrl+e.
Or choose graph: its agents as the monitor draws them, who handed to whom, the flows it called, and its sessions under each agent. enter on a session reads what it did, turn by turn, read back out of its log.
Before you start
- A run of a flow in this directory.
/epicslists the runs of the directoryhmzwas started in, finished or not. - A browser, for Perfetto.
chrome://tracing, or anything else that reads a Chrome JSON trace, opens it as well. - Agents on a CLI whose logs a trace can read: every built-in CLI but Cursor Agent (see Which CLIs a trace can read).
Every run is kept
Humanize keeps a record of every run of a flow, called an epic, whether the run finished or not. /epics lists them for the directory you are in: when each ran, which flow, what it was asked to do, its agents, what it spent and how long it took, where it is backed up, how many sessions it opened, and how it ended if it did not finish.
A run ends one of three ways: done, failed, or stopped, which covers a stop by hand, ctrl+c, and a spent budget. enter goes into a run, where you can export it or, for a flow that can be picked up, resume it. Carrying a run on starts a new run, with its own sessions and trace.
A trace is built from that record and from each agent's own log of its sessions. It is gathered when you export, so it covers the run as it stands then.
Example: read the trace of a Ralph loop
A Ralph loop ran three rounds on a small project, each round a fresh session of Claude Code. Its /epics list:
hmz › Epics
Every epic in this directory, newest first: task, agents, spend,
duration, session count, and status.
╭──────────────────────────────────────────────────────────────────────────╮
│ 2026-09-30 05:38 · ralph_loop Make the tests in test_slug.py pass. Change│
│ slug.py only. · Ralph · 1 session · stopped│
│ 2026-09-30 05:37 · ralph_loop Make the tests in test_slug.py pass. Change│
│ slug.py only. · Ralph · 3 sessions · │ ①
│ stopped │
╰──────────────────────────────────────────────────────────────────────────╯
Search… ②
enter open / search tab actions esc close↓ to the second run, enter, export epic, and say where it goes (Exporting a run):
/tmp/hmzdocs-C/app/issues/20260930T053725.504Z-a3d685.hmzepic · 162 kB · 3 sessions, 53 slices
③ ④Unpack the archive and drop its traces/export.trace.json into Perfetto. Laid out the way Perfetto lays out a trace, it looks like this:
What each part means
3 sessions · stopped: three rounds of a Ralph loop are three sessions, and the run was stopped by its budget. The row ends inresumablewhen the flow can be picked up.- Search… narrows the list as you type, by flow, task or run name, for a directory with a long history. / opens it too, and esc clears it.
3 sessions: every session the run opened and a trace could read. The same figure as the list, unless an agent ran on a CLI a trace cannot read.53 slices: the things the agents did, across those sessions.
And in Perfetto:
| Part | Is |
|---|---|
| a process | one agent of the run: its role, its model (and its effort, where the CLI logs one) and how many sessions it opened, as agent · claude-haiku-4-5-20251001 · 3 sessions |
| a track | a row of that agent's sessions: main for its own, subagent for agents its turns started, with their kind after it when the row holds one kind. Sessions that never overlap share a row. |
| a slice | one thing the agent did: its session and each turn, and inside a turn a tool call (Read: …/test_slug.py, Bash: python -m pytest test_slug.py -v), a message (say: …), time spent reasoning (think: …) or waiting on the model (generate) |
Click a slice to see its arguments: the prompt, the reasoning, the tool's input and output, as much as the CLI logged.
Check that it worked
- The summary line has sessions in it.
0 sessions, 0 slicesmeans the trace is empty; see If it goes wrong. - Perfetto shows one process per agent, each named after its agent and model, with as many sessions as
/epicscounted. - The slices read like the transcript. The first tool calls of the first session are the first things the agent did in the run.
What to look for
On a first trace, look for:
- A gap on every track. No agent was working: the flow was between turns.
- One very wide slice. A single tool call that took minutes, usually a test suite.
- A reviewer that only starts when the actor stops. The loop taking turns, as designed.
- Slices back to back on one
maintrack. A Ralph loop: a fresh session every round.
A trace shows what the agents did, not what it cost. For tokens and money, see Cost and rate.
Profile the programs too
An agent's turn is mostly other programs: the tests, the build, the greps. A CLI logs the tool call, not the processes it started. Profile a run and it also records each program its agents ran, what started it, and how long it took. Like the budget, it is a choice about a run, made where the budget is:
hmz › /flow › Installed › ralph_loop ● unsaved changes
Configure each role: an agent (CLI, account, model and effort) or an environment;
then what the flow takes and what an epic may spend.
╭──────────────────────────────────────────────────────────────────────────────╮
│ agent claude/claude-opus-5-5:high ▸ │
│ agent │
│──────────────────────────────────────────────────────────────────────────────│
│ budget set ▸ │
│ what an epic may spend: stops at 20m, $0.50 │
│──────────────────────────────────────────────────────────────────────────────│
│ profile flow ○ off ▾ │
│ traced only │
│──────────────────────────────────────────────────────────────────────────────│
│ profile environment ● on ▾ │ ①
│ samples the programs agents start │
╰──────────────────────────────────────────────────────────────────────────────╯
Update Uninstall Copy here Save ②
enter choose tab actions esc backprofile environment, just underbudgetandprofile flowon/flow: a switch.profile flowabove it is the same switch for the flow's own Python. On the web page they are the Profile flow and Profile environment boxes under Options. enter dropsonandoffunder it, the cursor already on the other one, so enter twice turns it round. It is off until you turn it on.- Save: kept with the rest of the flow's setup in this directory, so the next run of the flow here is profiled too until you turn it off.
From the command line, add --profile-environment to hmz exec; from Python, profile_environment=True to Hmz().run.
The flow's own Python can be profiled too, apart: --profile-flow, or profile_flow=True. Its trace then has one more process, python, whose one track is the flow's code as a sampling profiler draws it -- each function a slice as long as the flow stayed in it, what it called nested under it, and the time it spent waiting on a turn an [await] under the call that waited.
A trace of a profiled run shows each program as a process of its own, on the same clock as the sessions, and its summary counts them. The same Ralph loop, resumed once profiling was on:
/tmp/hmzdocs-C/app/issues/20260930T054014.242Z-bdae4a.hmzepic · 59 kB · 1 session, 13 slices, 7 programsA run already going is not profiled halfway through, and /resume profiles the run it picks up exactly as the run it goes on from was. An hmz exec line is profiled only when it says --profile-environment or --profile-flow.
Which CLIs a trace can read
A trace reads each CLI's own logs, where the run kept them, so it holds the sessions of every built-in CLI but one:
| CLI | In a trace |
|---|---|
| Claude Code, Codex, Antigravity, DeepSeek Harness, Grok Build, Kimi Code, MiniMax Code, pi, Oh My Pi, Qwen Code, opencode, mimocode | yes |
| Cursor Agent | no Watch it live on the monitor instead. |
Variations
Read one session's own log
Each session a run opened is kept in the sessions/ folder in the run's directory, a folder per CLI laid out as that CLI lays out its home: Claude Code's are under sessions/claude/projects/. It is the only copy -- the CLI wrote it there, not into its own home, and resumes it from there -- so the run is the one place to look, and nothing a run did shows up among the conversations you had with the CLI yourself.

To send a run elsewhere, export it.
Trace sessions no run opened
Your own sessions with a coding agent, outside any flow, are not in /epics. Trace them by id from Python:
from hmz.sdk import Hmz
Hmz().epics.trace(
sessions=["0a1b2c3d"], # the start of an id is enough
output="trace.json",
start="3 days ago", # anything dateparser understands
)See SDK reference and the Tracing reference.
If it goes wrong
… · 0 sessions, 0 slices. The run opened no session before it ended, its agents ran on Cursor Agent, or the CLI's logs have been moved or deleted since. See Troubleshooting.- Fewer sessions in the trace than
/epicscounted. Some agents ran on Cursor Agent, which a trace cannot read. Everything else is still there. - No programs in a profiled trace. The run was started before profiling was turned on, or by an
hmz execline without--profile-environment. Run the flow again with it on.
Next steps
- Exporting a run: the whole run as one archive, to send to someone else
- Picking a run up
- The monitor: the same shape, live, while the run goes
- Tracing reference