Catalog PyPI
PACKAGE EXPLORERView in registry

agent-replay-journal

PyPI

Canonical session-journal format, replay engine, and diff tool for AI agent transcripts. Zero-dependency dual-package (Python + Node.js).

Versions collected1
Direct dependencies1From release 0.1.1
Last observed20 Oct, 23:12 UTC

README

Version 0.1.1 documentation

agent-replay-journal

License: MIT Python Node.js

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-journal
from 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.ts type 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
FlagRequiredDescription
--sourceyesAgent source: claude-code, cursor, codex, hermes
--pathyesPath to the session file or directory
--outputyesPath 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
FlagRequiredDescription
--journalyesPath to the canonical journal JSON
--dry-runone ofShow replay plan without executing tools
--liveone ofExecute tools against target directory (stub)
--agentnoTarget agent name (e.g. claude-code)
--modelnoModel name for the replay
--target-dirnoWorking directory for live replay
--from-checkpointnoResume 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
FlagRequiredDescription
<journal_a>yesFirst journal file
<journal_b>yesSecond journal file
--formatnoside-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": "test@1.0", "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 dict

Node.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: 'test@1.0', 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 object

Canonical Journal Schema (v1.0)

{
  "version": "1.0",
  "agent": "claude-code@1.0",
  "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-run for 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

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.110 Aug 20261

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 23:12 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:01fdf4edd9aec36637edb716b5f8b0c78487a0464f5444228c4762733b57493b