agent-replay-journal
v0.1.1
Published
Canonical session-journal format, replay engine, and diff tool for AI agent transcripts. Zero-runtime-dependency dual-package (Node.js + Python).
Maintainers
Readme
agent-replay-journal
Canonical session-journal format, replay engine, and diff tool for AI agent coding transcripts. Zero runtime dependencies in both Python and Node.js.
Mandatory Rule
agent-replay-journal ships zero runtime dependencies in both Python (pyproject.toml declares dependencies = []) and Node.js (package.json carries no dependencies key). All imports are stdlib only.
tests_passing: true — verified by npm test and python3 -m pytest tests/ (160 tests across both runtimes: 102 Python + 58 Node, as of v0.1.1).
"I want to replay a session exactly as it happened — same tool calls, same order, same results — against my own codebase to verify the same bug is fixed."
Quick Start
# Python
pip install agent-replay-journal
# Node.js
npm install agent-replay-journalfrom agent_replay_journal import Journal, Journalify, diff_journals
# Import a session into canonical journal format
journal = Journalify.from_hermes("/root/.hermes/sessions/session-xyz.jsonl")
# List all tool calls
for tc in journal.tool_calls:
print(f" {tc['id']}: {tc['tool']}({tc['args']}) -> {tc['status']}")
# Resume from a named checkpoint (session branching)
resumed = journal.resumeFrom("cp_001")
# Diff two journal runs
delta = diff_journals(run_a, run_b)
print(delta.summary()) # e.g. "3 entries differ, 1 new, 2 missing"Why agent-replay-journal?
Existing agent session exporters lock you into one agent's format. Claude Code sessions stay in Claude Code. Cursor sessions stay in Cursor. Switching agents means losing your history.
agent-replay-journal solves this by defining a vendor-neutral canonical format that any agent can emit, and providing replay and diff tools to verify session behavior across agents and code versions.
Trade-off: live replay is a stub (it detects what would be replayed without calling real tools). Use dry-run mode to compare execution paths without modifying your filesystem.
Key Features
- Canonical journal format — Schema-versioned JSON with typed tool-call and model-response entries
- Checkpoint-based branching — Mark a position in tool_calls and fork a new exploration branch via
resumeFrom(cp_id) - Journalify — Import sessions from Claude Code, Cursor, Codex, and Hermes into canonical format
- Replay engine — Dry-run or live (stub) replay of journal sessions
- Diff tool — Side-by-side and JSON diff of two journal runs
- Dual runtime — Ships as a zero-dependency Python package and zero-dependency Node.js package with identical APIs
- TypeScript declarations — Full
.d.tstype coverage for Node.js consumers
CLI Reference
journalify
Convert native agent session formats into the canonical journal.
# Import a Claude Code session
journalify --source claude-code --path ~/.claude/history/sessions/abc123 \
--output session.json
# Import a Cursor session
journalify --source cursor --path ~/.cursor/sessions/xyz789.db \
--output session.json
# Import a Codex session
journalify --source codex --path ~/.codex/sessions/session.json \
--output session.json
# Import a Hermes JSONL session
journalify --source hermes --path ~/.hermes/sessions/session-xyz.jsonl \
--output session.json| Flag | Required | Description |
|---|---|---|
| --source | yes | Agent source: claude-code, cursor, codex, hermes |
| --path | yes | Path to the session file or directory |
| --output | yes | Path to write the canonical journal JSON |
replay
Replay a canonical journal against a target agent.
# Dry-run: show what would be replayed without executing
replay --journal session.json --dry-run \
--agent claude-code --model sonnet-4
# Live replay (stub): detect errors without calling real tools
replay --journal session.json --live \
--agent claude-code --target-dir /workspace/project
# Resume from a checkpoint
replay --journal session.json --dry-run --from-checkpoint cp_001 \
--agent claude-code --model sonnet-4| Flag | Required | Description |
|---|---|---|
| --journal | yes | Path to the canonical journal JSON |
| --dry-run | one of | Show replay plan without executing tools |
| --live | one of | Execute tools against target directory (stub) |
| --agent | no | Target agent name (e.g. claude-code) |
| --model | no | Model name for the replay |
| --target-dir | no | Working directory for live replay |
| --from-checkpoint | no | Resume from a named checkpoint (cp_001) |
diff-journals
Compare two canonical journals.
# Human-readable side-by-side diff
diff-journals run-a.json run-b.json --format side-by-side
# Machine-readable JSON diff
diff-journals run-a.json run-b.json --format json
# Shortcut: diff identical runs
diff-journals session.json session.json --format json| Flag | Required | Description |
|---|---|---|
| <journal_a> | yes | First journal file |
| <journal_b> | yes | Second journal file |
| --format | no | side-by-side (default) or json |
Python API
from agent_replay_journal import Journal, Journalify, diff_journals
# Journal class
j = Journal.from_json(open("session.json").read())
j = Journal.from_dict({"version": "1.0", "agent": "[email protected]", "tool_calls": []})
j.add_tool_call("read_file", {"path": "a.py"}, "file contents", "success", 12)
j.add_model_response("Done.", "tc_001")
j.add_checkpoint("tc_001", "before-fix")
resumed = j.resumeFrom("cp_001")
errors = j.validate() # list of validation error strings
is_valid = j.is_valid() # True if no errors
text = j.to_json() # serialise to JSON string
data = j.to_dict() # serialise to plain dict
repr(j) # human-readable string
# Journalify factory
j = Journalify.fromClaudeCode("~/.claude/history/sessions/abc123")
j = Journalify.fromCursor("~/.cursor/sessions/xyz.db")
j = Journalify.fromCodex("~/.codex/sessions/session.json")
j = Journalify.from_hermes("~/.hermes/sessions/session-xyz.jsonl")
# diff_journals
delta = diff_journals(j_a, j_b)
delta.summary() # e.g. "3 differ, 1 new, 2 missing"
delta.changed # list of changed entries
delta.added # list of added entries
delta.removed # list of removed entries
delta.to_dict() # machine-readable dictNode.js API
const { Journal, Journalify, diff_journals } = require('agent-replay-journal');
// Journal class
const j = Journal.fromJSON(fs.readFileSync('session.json', 'utf8'));
const j = new Journal({ version: '1.0', agent: '[email protected]', tool_calls: [] });
j.addToolCall('read_file', { path: 'a.py' }, 'contents', 'success', 12);
j.addModelResponse('Done.', 'tc_001');
j.addCheckpoint('tc_001', 'before-fix');
const resumed = j.resumeFrom('cp_001');
j.validate() // []
j.isValid() // true
j.toJSON() // plain object
j.toString() // JSON string
j.toolCalls // accessor for tool_calls array
// Journalify factory
const j = Journalify.fromClaudeCode('./claude-session');
const j = Journalify.fromCursor('./cursor-session.db');
const j = Journalify.fromCodex('./codex-session.json');
const j = Journalify.fromHermes('./hermes-session.jsonl');
// diff_journals
const delta = diff_journals(j_a, j_b);
delta.summary() // string
delta.changed // array
delta.added // array
delta.removed // array
delta.toDict() // plain objectCanonical Journal Schema (v1.0)
{
"version": "1.0",
"agent": "[email protected]",
"model": "claude-sonnet-4",
"task": "Fix authentication bug in auth.py",
"started_at": "2026-08-09T14:23:11Z",
"ended_at": "2026-08-09T14:31:45Z",
"tool_calls": [
{
"id": "tc_001",
"type": "tool_call",
"tool": "read_file",
"args": { "path": "auth.py" },
"result": "file contents",
"status": "success",
"elapsed_ms": 12
},
{
"id": "msg_002",
"type": "model_response",
"content": "I found the issue...",
"tool_call_id": "tc_001"
}
],
"checkpoints": [
{ "id": "cp_001", "after_id": "tc_001", "label": "before-fix-attempt" }
]
}Full schema reference: rules/journal-schema.md
Limitations
- Live replay is a stub — it detects execution errors without calling real tools. Use
--dry-runfor cross-version comparison. - Import adapters (
fromClaudeCode,fromCursor,fromCodex,from_hermes) handle the documented native formats; non-standard session files may require pre-processing. - Replay parallelism (
--parallel) is not yet implemented in the Node.js CLI. - Session files larger than 100 MB may cause memory pressure during full journalification.
Non-Goals
- Not a general-purpose diff tool for arbitrary JSON files — only canonical journals are supported.
- Not a session recorder or middleware — this library operates on exported session files, not live agent streams.
- Not a cloud service — all replay and diff happens locally.
- Not a replacement for pytest or node --test test runners — journal replay is for session verification, not unit testing.
License
MIT License — Copyright (c) 2026 prasad-a-abhishek
