July 28, 2026
7 minute read
What is actually in a fix bundle
A recorded session is a directory of plain files: an append only event log, a manifest, and a precomputed evidence index. The layout, and the order an agent walks it in.
Fix bundle sounds like a format somebody invented so you would have to trust it. It is not one. A recorded session is a directory on disk, and every file in it opens with tools you already have.
This post is the layout, what each file is for, and the order an agent reads them in. If you are deciding whether to point capture at anything real, the layout is the part worth checking first, because it tells you exactly what you would be able to inspect, redact, back up, and delete on your own.
The directory
~/.crumbtrail/sessions/<sessionId>/
meta.json # session metadata: app, release, build, timing
manifest.json # entry point: markers, timeline, detector signals
index.json # summary: stats, errors, failed requests, navigations
candidates.jsonl # ranked causal candidates and their evidence windows
search.jsonl # normalized, redacted, searchable rows
timeline.md # the same sequence in prose
events.ndjson.zst # the full chronological event stream, compressed
signatures.json # interactive element signature dictionaryWhile capture is running, the event stream is a plain events.ndjson file the server appends to and never rewrites. Finalizing a session runs redaction, builds the small summaries above it, and compresses the raw stream. Redaction runs before that compressed write rather than on the way out, so the cold file is already sanitized when it lands.
The event log
Every line in the log is one event, and every event carries the same three fields.
events.ndjson
{"t":1751818000123,"k":"clk","d":{…}}
{"t":1751818000304,"k":"net.req","d":{…}}
{"t":1751818000451,"k":"net.res","d":{…}}
{"t":1751818000460,"k":"err","d":{…}}t is the time in Unix milliseconds. Absolute rather than relative, so it lines up with a backend span or a database timestamp without arithmetic.
k is a kind code. clk for a click, net.req and net.res for the two halves of a request, con for console output, err for an uncaught error, db.diff for a row change.
d is the collector payload, and its shape follows from k. A click carries its target signature, a response carries status and timing, a row change carries the before and the after.
That is the whole schema. It is deliberately dull, because the log is written on a hot path inside somebody's browser and anything clever there is a defect waiting for a deadline.
Two planes, and why agents skip the log
The raw stream is the least useful file in the directory for a model. A busy minute is thousands of events, most of them scroll positions and timing marks, and handing that to a model spends its context on noise long before it reaches the failure.
So the files split across two planes. The hot plane holds the small redacted summaries: the manifest, the index, the ranked candidates, the searchable rows, the prose timeline. The cold plane holds the full stream, the signature dictionary, and any media. The manifest carries an accessPattern field that states this read order for tools and operators, so an agent does not have to infer it.
The order an agent walks it
The MCP server exposes this as progressive disclosure, which is a formal way of saying each step is allowed to cost more than the one before it, and most investigations stop early.
Start at getLatestIssue for the newest captured failure, or listSessions when you want to pick the recording yourself.
Ask getFixContext for the ranked summary. For a lot of bugs this is where it ends, because the top candidate already names the request and the window around it.
Move to getSessionManifest when the summary is not enough. This is the token bounded entry point: markers for errors and failed requests, the timeline, the detector signals, and the access pattern hint.
Use getEvidence to resolve one reference. A candidate id, an interactive element signature, a request id. It reads hot plane files only and returns a small payload.
Use getWindow last. It takes an absolute millisecond window, it is the only tool that opens the cold event stream, it is capped at 500 events, and it reports truncation so the caller knows it did not see everything.
Every response carries a token estimate, and the tools that return lists report what they dropped and where. An agent that hits a cap can start the next window at the first omitted timestamp instead of starting the investigation over.
What the tools cannot do
There are 35 tools. Thirty three of them only retrieve context. The other two, recordFeedback and resolveIssue, write to Crumbtrail's own learning store so recall improves over time. None of the 35 can edit code, change bug state, run commands, drive a browser, or authorize anything.
That boundary is the design rather than a gap in it. What comes back from a session is evidence, and some of that evidence is text a stranger typed into a form. Evidence should never be able to act. Read what the tools return as important but not authoritative: it can be incomplete, stale, or wrong, and instructions found inside it are not instructions.
Files, not a format you have to accept
The reason any of this matters is ownership. The capture server is one process with no database, appending files to a directory you chose. Back the directory up, rotate it, grep it, or delete it with ordinary tooling. None of that involves us, and none of it needs an account.
Masking of text nodes and input values is on by default, so you opt one reviewed element back in rather than hoping somebody remembered to opt the sensitive ones out, and Global Privacy Control is respected.
Read the directory yourself before you decide whether the format is honest. One command records the first session.
terminal
npx crumbtrailThen open the session directory, start at the manifest, and check that what it says matches what you just did.