Skip to main content

The shared durable ledger

The ledger is the single most important idea in ContextRelay. Two agents that cannot read each other's minds need a place to leave durable, ordered, shared context - and that place is a local append-only JSONL file. Everything else (handoffs, deliberation, task lanes, finality, crash recovery, audit) is built on top of it.

What the ledger is

For each shared session, ContextRelay writes an append-only JSONL log on your own machine. One JSON object per line, never edited in place, only appended.

The file lives under the project's .contextrelay/ directory:

.contextrelay/
|-- config.json # project policy (coordinator, permissions, autonomy)
|-- current # pointer to the active session id
|-- sessions.json # named runtime-session registry
|-- sessions/
| `-- session_<epoch>_<hex>.jsonl # the shared durable ledger (one file per session)
`-- state/
|-- transcript.jsonl # runtime transcript
|-- queue.db # Claude-bound message queue (SQLite)
|-- status.json # latest daemon/session status snapshot
|-- daemon.pid / daemon.lock # daemon process + lock
`-- ... # tokens, ports, logs, pids

Two things are easy to mix up, so to be precise:

  • .contextrelay/sessions/<sessionId>.jsonl is the ledger - the durable, auditable record of the collaboration.
  • .contextrelay/state/ is runtime plumbing - pids, locks, tokens, ports, the SQLite delivery queue, a runtime transcript, and status snapshots. It is not the audit record.

Each session id looks like session_<epoch-millis>_<8-hex> (for example session_1717603200000_a1b2c3d4), and .contextrelay/current records which session is active.

Per-session files, shared history

ContextRelay writes a separate .jsonl file per shared session. When you use named runtime sessions (for example a side worktree for review), untagged entries stay visible to every runtime session as shared audit history, while explicitly tagged entries can be scoped to one runtime session. Treat the ledger as one shared record per session, not as isolated private logs.

Why it exists

Claude Code and Codex run as two separate processes. Neither can see the other's hidden reasoning - only what is written down. (See Why two agents in one session.) Live messages help in the moment, but they are ephemeral. The ledger is the durable layer that makes the collaboration real:

  • Shared context. It is the only place both agents can rely on for goals, plans, decisions, files touched, blockers, and next steps.
  • Authority for recovery. If a process crashes or you close a terminal, the ledger is what ctxrelay recover reads to reconstruct where things stood - recent failures, interrupted commands, and a resume prompt.
  • Authority for finality. Whether work is "done" is decided from ledger evidence (proposals, gate results, blockers), not from an agent's say-so. See Finality and human sign-off.
  • Audit. Because it is append-only and local, you get a faithful record of what the agents actually did before you ship - and it never leaves your machine.

What it records

Every collaboration event becomes a ledger entry. Each entry is a small JSON object with a stable shape:

{
"schema": "v1",
"id": "f3c0…",
"timestamp": 1717603200000,
"sessionId": "session_1717603200000_a1b2c3d4",
"type": "handoff",
"source": "claude",
"target": "codex",
"content": "Implement the retry backoff in client.ts"
}

The entry type is one of: session_started, message, handoff, runtime_event, error, and entries that additionally carry a structured artifact. So the ledger captures:

  • Messages between Claude and Codex (every reply / send_to_claude).
  • Handoffs - structured delegations with a reason, an ask, and a target.
  • Notes - durable context written with append_note.
  • Artifacts - structured evidence written with record_artifact.
  • Runtime events and errors - session lifecycle, failures, and recovery signals.

Artifacts the ledger carries

Artifacts are the structured evidence that drives task lanes, release readiness, and finality. The supported artifact kinds are:

patch_summary
release_gate
test_report
command_log
escalation_suggestion
idle_opportunity
idle_action_result
idle_fleet_result
idle_evaluation_result
idle_write_result

Each artifact carries a status so consumers can reason about outcomes:

passed
failed
blocked
unknown
skipped
timed_out
Entries are redacted and append-only

Before an entry is written, its content is redacted and truncated, and the write is taken under a per-session lock and flushed atomically. Entries are never rewritten - corrections are new appends. That is what makes the log trustworthy as an audit trail.

How agents use it

Agents do not touch the .jsonl file directly. The daemon is the single writer of record - it owns the ledger, serializes appends, and derives state from it. Both Claude and Codex go through the daemon using the same shared MCP tools (the Codex names are listed where they differ):

ToolWhat it does against the ledger
read_contextReturns recent ledger entries plus the latest active handoff - a derived "still-waiting" field - so you can resume without re-reading the whole log.
append_noteAppends a durable note (goal, plan, decision, blocker, next step).
record_artifactAppends a structured artifact (one of the kinds above) with a status.
task_stateDerives task lanes, policy state, artifacts, and finality blockers from the ledger.
session_infoReturns a session summary with ledger counts, the active handoff, and policy/autonomy/finality state.

The "latest active handoff" is computed, not stored as a separate flag: ContextRelay scans the entries, finds the most recent handoff per target, and drops any that a later note or message marked as handled. That is how a peer (or a future recovery) knows what is still owed without parsing the entire file.

Write enough to reconstruct state

Because hidden reasoning is invisible, the single most useful habit in ContextRelay is to write your goal, current plan, files touched, blockers, decisions, and next step into messages and the ledger. Do it before handing off, before a long-running step, and whenever the plan changes - so the peer agent and ctxrelay recover can pick up exactly where you left off.

Inspect the ledger yourself

You never need to open the raw file, but you can. To see derived state and counts from the command line:

# Daemon, session, connection, ledger, task, autonomy, and finality state
ctxrelay status

# Machine-readable snapshot
ctxrelay status --json

# Reconstruct context after a crash or a closed terminal
ctxrelay recover

You can also open the browser viewer, which renders task lanes, artifacts, policy, and a timeline built from the same ledger:

ctxrelay viewer
The viewer can clear shared history

The browser viewer is read-only for agent work - it cannot send messages or do the agents' work for them - but it can clear the current shared session history through its authenticated endpoint. Clearing the ledger discards the audit trail for that session, so treat it as a deliberate action, not routine cleanup.

Next steps