Coding agents moved my bottleneck. Writing the code got fast. Understanding what the agent actually did became the slow part.
The evidence already exists. Claude Code, Codex CLI, and Hermes Agent all keep full session records on disk (~/.claude/projects, ~/.codex/sessions, and ~/.hermes): every tool call, every error, every retry, every subagent and delegation. Almost nobody reads them, because a single session runs to thousands of lines of JSONL.
So I built rungraph. Free, MIT licensed, no paid tier.
npx rungraph
It scans the transcripts already on your disk and opens an interactive graph of any session: turns run down the spine in time order, tool calls are grouped, and subagents get their own lanes. No hooks, no wrappers, no setup, so the run that went sideways yesterday is already there. Live sessions update on the graph while the agent works.
That part is table stakes. The two things below are why I still use it every day.
1. The graph is something you can talk to
npx rungraph mcp --install
That wires rungraph into your agent over MCP. Now you stop scrolling transcripts and start asking questions in the terminal you already work in:
- "Which edits in my last run failed?"
- "Did it actually run the tests, or just say it did?"
- "Where did the auth refactor first touch
token.js?"
Here is the part I did not expect to matter as much as it does. The agent answers in your terminal, and then the nodes behind that answer light up on the open graph. It pans the canvas to them. If your dashboard is showing a different run, it follows the answer there, with one-click undo. If nothing is open, it opens a tab on the right run.
Those are two ends of one loop, not two features. The terminal is where you ask, in your own session, with your own model, where you can inspect exactly what was said. The canvas is where you see. You get a claim and the evidence for that claim at the same time, in the place each one belongs, so you are reviewing a run instead of trusting a summary about it.
Every highlight also produces a pastable link. Links name a focus by its source rather than by a frozen list of node ids, so a link and a fresh query can never disagree with each other: open one tomorrow, after the run has grown, and the query re-runs.
It is plain MCP over stdio, so any MCP-capable agent can wire it. Hermes, for example:
hermes mcp add rungraph --command npx --args -y rungraph mcp
The tool names are identical everywhere (list_runs, find_nodes, get_graph, get_detail, focus_nodes, get_current_view, open_visualization), and so is the loop.
2. Hand a run to someone else, and let their agent read it
Agent work is getting collaborative, and "what did your agent do" is currently answered by pasting a wall of terminal output into Slack.
Select the runs in the dashboard and hit export, or stay in the terminal:
rungraph export --last 2
Either way you get a single .rungraph file. Your teammate opens it in their own dashboard:
rungraph open <file>
Three things make this more useful than a transcript dump.
The bundle carries the intermediate representation, not raw transcripts. So the viewer needs no adapters at all, and vendor neutrality survives the handoff: a Hermes run opens perfectly for someone who has only ever used Claude Code. Nobody has to install your agent to review your run.
Their agent can query your run. rungraph mcp aggregates across every live server, so a colleague's opened bundle sits alongside their own dashboard, and their agent answers questions about your session with the same tools and the same highlighting. That is the collaborative version of the loop: you send a file, they ask their own agent what went wrong in it, and the nodes light up on their screen. Code review for agent runs, rather than for the diff the run happened to produce.
Signals are derived at view time, not baked in. A bundle exported months ago gets today's calibrated flags when it is opened.
The export guard, and why it exists
While building the Codex adapter I found that Codex logs file reads verbatim. When it read my .env, an npm token and two API keys were sitting in plain text in my session files. Check yours before you back them up or share them.
So every export shows you an inventory of what is about to leave your machine, and blocks outright when the secrets scan finds a high-confidence match. You then choose your fidelity: redact each finding to a placeholder and keep the rest, strip all content down to just the shape, tool names, files and timings, or override the block when the finding is a false positive.
The dialog and the flags are the same code path with the same defaults, deliberately. Two consent surfaces teaching two different privacy postures would be worse than either one alone. Sharing a run should not be how you leak a key.
Flags worth your attention
The graph marks a tool that kept failing in one spot, an error the run never came back to fix, and a step that burned far more tokens than everything around it. Deliberately conservative, because a false alarm costs more than a missed one. Once you stop trusting the markers, you are back to reading the whole run.
Click any node for the actual inputs, outputs, errors, and timing behind it.
Local by default
The server binds 127.0.0.1 only and makes zero outbound requests. Your transcripts never leave your machine, and nothing is shared until you run export yourself.
Notes for format archaeologists
These formats churn more than you would guess. Exit codes have lived in three shapes across Codex exec generations, forked threads embed a re-stamped copy of the parent's history that has to be cut structurally rather than by timestamp, and Hermes keeps its delegation tree in SQLite (which needs Node 22.13+ for the built-in reader; older Nodes skip Hermes runs with a warning and everything else still works). My whole corpus parses clean across all three agents, but I want to see the rollout that breaks it. If you have one, send me the error.
Try it
Run npx rungraph against your own sessions, then wire the MCP server and ask your agent something you would previously have scrolled for. If it flags something real in a run you had already trusted, I want to hear about it.

Top comments (2)
the .env finding is the part people should actually act on and it's sitting underneath the graph feature.
it generalizes too. any agent that logs tool results verbatim has this, and the read path is where it lives, because reading a secret produces no diff and no review. the file didn't change so nothing looks like it happened, and the value is now in a jsonl on disk, in a backup, and in whatever you pasted into an issue.
on the parser challenge: the case i'd expect to break it is a session that got compacted or resumed mid-run. the tail is a summary of the head rather than the head, so the spine is real up to the compaction point and synthetic after it, and there's usually nothing in the record marking where the seam is. a graph renders that as one continuous run, which is worse than failing, because a false continuous timeline is exactly what a reviewer would trust.
related: forked threads embedding a re-stamped copy of parent history, which you already handle structurally, is the same class. compaction is that but lossy and unlabeled.
deriving signals at view time so an old bundle gets today's calibration is a good call and an unusual one.
Revised version
The read-path framing is sharper than mine. A write gets a diff and a reviewer; a read gets nothing, even though the value is already in the JSONL and the backup. I'll move that up.
On compaction, I went and checked rather than answer from memory, and you're half right in the way that counts. The seam is in the record for every format I support: Claude Code writes a
compact_boundarysystem record plus the summary as a user message flaggedisCompactSummary; Codex writes acompactedevent; opencode fabricates a user message with a compaction part. Codex and opencode are handled. Claude Code isn't, because not one session in my corpus has ever compacted, so the adapter never met the shape.I traced what it would do today: it drops the boundary silently and draws the summary as a prompt a human typed. That's worse than the smooth line you predicted. It's the bug I asked people to send me, except I found it by reading your comment. The fix is a visible seam on the spine, the summary drawn as what it is, and a fixture so it can't regress.
Agreed that a continuous timeline that's secretly synthetic after row 800 is exactly the wrong thing for the coverage badge to prevent.