Before you start
- A key with the
writescope. See Scopes. - The
exoCLI installed and holding that key. - Transcripts on disk:
~/.claude/projects/**/*.jsonlfor Claude Code,~/.codex/sessions/**/rollout-*.jsonlfor Codex.
A browser cannot read your local disk, which is why this is a CLI path and not an upload form. There is no way to drag a session transcript into a web page, because the file you would be dragging is not one file.
The short version
--source claude, --source codex and --source all all work. Re-runs are dedup safe: every event carries a stable dedup key, so a second backfill over the same transcripts adds nothing.
What backfill actually does
1
Walk the transcripts
The CLI reads each session file, drops noise, and normalises every turn into a session event. Claude Code and Codex go through the same builder, so the two sources produce the same shape and nothing downstream has to know which agent you used. Codex session ids are prefixed
codex- for provenance.Redaction happens here, on your machine, before anything leaves it.2
Send them in batches
Events go to
POST /v1/ingest/session-batch, up to 500 per call, with retry and backoff on 429 and 5xx. Because each event carries a dedup key, a retried batch cannot double-write.3
Finalize once
After the last batch is accepted, the CLI calls Session ingestion writes nodes. It does not, on its own, produce graph edges, domains, the identity extraction or the first cognition cycle. Finalize is what kicks that build. Skip it and you get a pile of session nodes and empty recall surfaces, which looks exactly like a broken import.It is idempotent. Calling it again while a build is running is a no-op and comes back with
POST /v1/ingest/session-finalize exactly once. This is the step that matters, and it is the one people miss when they script this by hand.enqueued: false and alreadyInFlight: true.4
Watch the layers fill in
The live tail
exo daemon watches for new session activity and streams it as you work, so the graph stays current without a second backfill. It watches the Claude Code root, and optionally a Codex root as well.
The daemon and the backfill share one implementation of the event builder, including the noise filter and the redaction pass. They cannot drift apart and start sending differently shaped events.
Reading sessions back
GET /v1/recall/sessions lists the coding sessions in the graph. DELETE /v1/recall/sessions/{session_id} removes one, which is the targeted way to drop a session that captured something it should not have.
Agent signals
POST /v1/ingest/agent-signals records where a coding agent went wrong: the corrections, retries and dead ends that a transcript alone does not label. Those signals are what the AgentFailurePattern object is built from.
The
AgentFailurePattern object is defined in the v1 contract and the signal ingestion route is real, but the team-facing surface that reads clustered patterns back is not part of v1. You can send signals today. There is no v1 route that returns the clusters. See AgentFailurePattern for the concept and the honest status.When it goes wrong
Session nodes exist but every recall surface is empty
Session nodes exist but every recall surface is empty
Finalize was never called, or it is still running. Check
finalizePending and building on GET /v1/ingest/session-status. If both are false and the warm layers are still empty, call POST /v1/ingest/session-finalize again. It is idempotent, so this is safe.A second backfill duplicated everything
A second backfill duplicated everything
It should not, and if it did, the events were not carrying dedup keys. That happens when a hand-rolled script posts to
POST /v1/ingest/session-batch directly instead of going through the shared event builder. Use exo backfill rather than reimplementing the normaliser.429 during a large backfill
429 during a large backfill
Expected on a big first import, and the CLI already backs off and retries. If you are posting batches yourself, honour
Retry-After on the 429. See Rate limits.Codex sessions are missing
Codex sessions are missing
Pass
--source codex or --source all. The default source does not include Codex. Codex support also needs an exo CLI release that includes it, and compressed rollouts need the zstandard dependency present.Next
Claude Code
Connect the client so new work is captured as it happens.
Phase
What Exo builds from the dates on all that history.