The only tool that physically deletes hallucinated files β git reset --hard, not just state rollback.
pip install ai-agent-vcrNo API keys. No cloud. No vendor lock-in. Works with TERX β memory layer for browser agents.
You ran Claude Code, OpenHands, or a LangGraph agent autonomously.
It wrote 40 files. It failed at step 8. Now you have:
- 23 files that shouldn't exist
- A broken import chain
- State that says "success" on steps that half-ran
- No way to know what the repo looked like before step 6
Your repo after a bad autonomous run:
/src/handlers.py β hallucinated, breaks import
/src/auth_v2.py β duplicate of auth.py, never needed
/src/models_refactor.py β partial rewrite, syntax error
/tests/test_fake.py β tests for code that doesn't exist
/config/settings_new.py β overwrote working config
Every other tool shows you logs. Agent VCR runs git reset --hard and deletes every one of those files.
from agent_vcr import VCRRecorder
from agent_vcr.integrations.openhands import ACIDWorkspace
recorder = VCRRecorder()
acid = ACIDWorkspace("/my/workspace", recorder=recorder)
acid.begin(session_id="task-001") # isolated git branch
acid.savepoint(state, node_name="coder") # checkpoint state + filesystem
acid.savepoint(state, node_name="tester")
# Agent writes 47 files. 23 are hallucinated garbage. Step 6 failed.
acid.rollback(to_frame_index=1)
# git reset --hard
# All 23 files: physically deleted from disk. Not hidden. Gone.
# Pre-existing ignored files like .env are preserved.
acid.commit() # merge only the clean branchBefore rollback: After rollback:
/src/handlers.py β DELETED
/src/auth_v2.py β DELETED
/tests/fake_test.py β DELETED
/src/utils.py β kept
/src/models.py β kept
LangSmith shows you what happened. LangFuse shows you what happened. Arize shows you what happened.
Agent VCR changes what happened.
Agent succeeds? Save it. Run it again for free forever.
from agent_vcr.golden_cache import GoldenRunCache
cache = GoldenRunCache()
identity = GoldenRunCache.build_identity(
model="gpt-4o",
prompt_hash="prompt:v3",
code_commit="abc123",
tool_schema_hash="tools:v1",
)
cache.save_golden_run("Build a REST API with JWT auth", recorder, identity=identity)
# Every future run of the same task:
outputs, ledger = cache.replay("Build a REST API with JWT auth", identity=identity)
print(ledger)RUN 1 (original) RUN 2 (Ghost Replay)
βββββββββββββββββ βββββββββββββββββββββ
Tokens: 4,100 Tokens: 0
Cost: $0.0123 Cost: $0.00
Time: 2,350ms Time: 1ms
π° 100% savings Β· $0.0123 saved Β· 4,100 tokens Β· 2,349ms faster
Agent fails at step 8 of 10? Don't re-run from zero.
from agent_vcr import VCRPlayer
from agent_vcr.models import ResumeConfig
player = VCRPlayer.load(".vcr/my_run.vcr")
# See exact state at every step
print(player.goto_frame(6)) # {'files_written': [...], 'plan': '...'}
print(player.get_errors()) # what broke and where
# Fix the prompt. Resume from step 6. Skip steps 0-5.
player.resume(
agent_callable=coder,
config=ResumeConfig(
from_frame=6,
state_overrides={"plan": "use SQLAlchemy instead of raw SQL"}
)
)Without Agent VCR With Agent VCR
ββββββββββββββββββ ββββββββββββββββββββββββββ
Agent fails step 8 Agent fails step 8
Patch the code player.goto_frame(7)
Re-run ALL 10 steps Fix the state
$0.04 + 2 min wasted Resume from step 7
Repeat for every bug Done. $0.00 extra.
You need this if you're running:
- Claude Code / Cursor autonomous mode
- OpenHands on real codebases
- LangGraph agents that write files
- CrewAI pipelines with filesystem access
- Any autonomous coding agent on a repo you care about
You don't need this if you're only:
- Doing RAG / chatbots (no filesystem risk)
- Already happy with LangSmith for tracing
from agent_vcr import VCRRecorder
recorder = VCRRecorder()
recorder.start_session("my_run")
state = {"query": "build a REST API"}
state = planner(state)
recorder.record_step("planner", input_state, state)
state = coder(state)
recorder.record_step("coder", input_state, state)
recorder.save() # β .vcr/my_run.vcrOr use the context manager β frames are saved even if the agent crashes:
with VCRRecorder() as recorder:
recorder.start_session("my_run")
# ... your agent code ...player = VCRPlayer.load(".vcr/my_run.vcr")
diff = player.compare_frames(5, 6)
# {'added': {'bad_file': '...'}, 'modified': {'plan': '...'}}
player.resume(
agent_callable=coder,
config=ResumeConfig(from_frame=5, state_overrides={"plan": "fixed"})
)from langgraph.graph import StateGraph
from agent_vcr import VCRRecorder
from agent_vcr.integrations.langgraph import VCRLangGraph
recorder = VCRRecorder()
graph = VCRLangGraph(recorder).wrap_graph(graph) # β one line, that's it
result = graph.invoke({"query": "Build a todo app"})
recorder.save()from agent_vcr.integrations.crewai import VCRCrewAI
recorder = VCRRecorder()
recorder.start_session("crew_run")
result = VCRCrewAI(recorder).kickoff(crew)
recorder.save()pip install "ai-agent-vcr[crewai]"
pip install "ai-agent-vcr[langgraph]"from agent_vcr.integrations.langgraph import vcr_record
@vcr_record(recorder, node_name="research_step")
def research(state: dict) -> dict:
return {"findings": search(state["query"])}Catches what the agent wrote before it moves to the next step.
from openhands_sentinel import Sentinel
sentinel = Sentinel(recorder=recorder)
sentinel.attach(runtime.event_stream) # 3 lines. auto-intercepts every write.STEP 2: Agent writes handlers.py
π‘οΈ SENTINEL: VIOLATIONS DETECTED
CRITICAL hash_password() already exists in auth/utils.py:8 β reuse it
CRITICAL handle_auth_request() is 109 lines (limit: 40) β break it up
CRITICAL Cyclomatic complexity: 32 (limit: 8)
STEP 3: Agent self-corrects
π‘οΈ SENTINEL: handlers.py β CLEAN β
| Without Sentinel | With Sentinel | |
|---|---|---|
| Agent writes bad code | β | β |
| Sentinel catches it | β | < 10ms |
| Agent self-corrects | β | done |
| Human reviews PR | manual | zero |
| Cost | 2Γ LLM + human time | 1 extra LLM call |
Standalone scan:
sentinel scan ./my-ai-project
sentinel watch ./my-ai-projectvcr .vcr/my_run.vcrββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β πΌ Agent VCR Session: my_run Β· 8 frames β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β βΆ Frame 0 β planner β 100ms β β β
β Frame 1 β researcher β 250ms β β β
β Frame 2 β coder β 480ms β β ERROR β
β Frame 3 β tester β 80ms β β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β { "query": "build a todo app", "plan": null } β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β/β navigate β e edit β d diff β r resume β q quit β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Keybindings: β/β or j/k navigate Β· e edit state Β· 1/2/3 input/output/diff Β· r resume Β· s search Β· q quit
Claude Code hooks:
vcr init --claude-codepip install "ai-agent-vcr[dashboard]"
vcr-server --vcr-dir .vcr --auth-token local-secret
# http://127.0.0.1:8000original_run βββββββββββββββββββββββββββββββββββββββββββΊ [done]
β frame 3
β°βββΊ fork_v1 βββΊ [coder] βββΊ [tester] βββΊ [done]
β°βββΊ fork_v2 βββΊ [coder] βββΊ [done]
Live WebSocket streaming. Every fork is a branch. Errors in red.
Honest take: LangSmith, Langfuse, Arize Phoenix, and AgentOps are serious platforms with large teams. They are observability tools β they show you what happened. Agent VCR is an intervention tool β it lets you change what happened. Different category. The overlap is tracing. Everything else diverges.
| Capability | πΌ Agent VCR | LangSmith | LangFuse | AgentOps | Arize Phoenix |
|---|---|---|---|---|---|
| Record execution traces | β | β | β | β | β |
| Production dashboards | Local | β best-in-class | β | β | β |
| Eval / scoring pipelines | β | β | β | β | β |
| Time-travel / session replay | β | β | β | β (view only) | β |
| Edit state & resume mid-chain | β | β | β | β | β |
| ACID filesystem rollback | β | β | β | β | β |
| Ghost Replay (zero tokens) | β | β | β | β | β |
| Sentinel (real-time code guard) | β | β | β | β | β |
| Fork from any frame | β | β | β | β | β |
| TUI debugger | β | β | β | β | β |
| Fully local / self-hosted | β | β Cloud | β | β Cloud | β |
| Framework-agnostic | β | β | β | β |
AgentOps β closest competitor on time-travel. It lets you view past sessions. It does not let you edit state and resume, fork a session, rollback the filesystem, or replay for zero tokens. If you need view-only replay, AgentOps is mature. If you need to actually intervene, you need Agent VCR.
Use LangSmith/Langfuse/Phoenix/AgentOps for production tracing and evals. Use Agent VCR when you need to actually fix a broken run without re-running it, rollback filesystem damage, or replay a successful run for free.
LangGraph's checkpointer is solid if you're 100% LangGraph and only need state inspection.
The gap: when your agent writes files to disk and fails, the checkpointer rolls back the state object. The files stay. Agent VCR runs git reset --hard. The files are gone.
| LangGraph Checkpointer | Agent VCR | |
|---|---|---|
| Checkpoint in-memory state | β | β |
| Rollback files from disk | β | β |
| Ghost Replay (zero tokens) | β | β |
| Sentinel (code guardian) | β | β |
| Works with CrewAI, raw Python | β | β |
| JSONL format (git-diffable) | β | β |
| Session forking | β | β |
Every benchmark is enforced in CI. If it regresses, CI fails.
pip install -e ".[dev]"
pytest tests/benchmarks/ -v --benchmark-only| Benchmark | Limit | What it measures |
|---|---|---|
test_benchmark_recorder_overhead |
< 5ms mean | Serialize + buffer one state snapshot |
test_benchmark_file_write_speed |
> 1,000 frames/sec | Sustained write throughput (10K frames) |
test_benchmark_load_speed |
< 500ms | Load a 10,000-frame session from disk |
test_benchmark_goto_frame |
< 1ms | Random-access time-travel to any frame |
Historical results: ixchio.github.io/agent-vcr/dev/bench/
Plain JSONL. One object per line.
{"type": "session", "data": {"session_id": "my_run", "created_at": "..."}}
{"type": "frame", "data": {"node_name": "planner", "input_state": {...}, "output_state": {...}}}
{"type": "frame", "data": {"node_name": "coder", ...}}- Human-readable β open in any text editor
- Git-diffable β review agent state in PRs
- Append-only β safe for concurrent agents, no full-file rewrites
- Streamable β parse line-by-line without loading the full file
recorder = VCRRecorder(
output_dir=".vcr",
auto_save=True,
diff_mode=False,
)
recorder.start_session(session_id="my_run", tags=["prod"])
recorder.record_step(node_name, input_state, output_state, metadata)
recorder.record_llm_call(model, messages, response, tokens_input, tokens_output, latency_ms)
recorder.record_tool_call(tool_name, tool_input, tool_output, latency_ms)
recorder.record_error(node_name, input_state, error)
recorder.save() -> Path
recorder.fork(from_frame=3) -> VCRRecorderplayer = VCRPlayer.load(".vcr/my_run.vcr")
player.goto_frame(index) # β output state at frame N
player.get_input_state(index) # β input state at frame N
player.get_errors() # β [Frame, ...]
player.compare_frames(a, b) # β {'added': {}, 'removed': {}, 'modified': {}}
player.get_total_cost() # β float (USD)
player.resume(
agent_callable,
config=ResumeConfig(
from_frame=7,
state_overrides={"k": "v"},
mode=ResumeMode.FORK, # FORK | REPLAY | MOCK
)
)acid = ACIDWorkspace("/workspace", recorder=recorder)
acid.begin(session_id="task-001")
acid.savepoint(state, node_name="coder")
acid.rollback(to_frame_index=2) # git reset --hard
acid.commit()cache = GoldenRunCache(cache_dir=".vcr/golden")
identity = GoldenRunCache.build_identity(model="gpt-4o", code_commit="abc123")
cache.save_golden_run(task_description, recorder, identity=identity)
outputs, ledger = cache.replay(task_description, identity=identity)
cache.invalidate(task_description)
cache.list_golden_runs()# ACID rollback + Ghost Replay β start here
python examples/acid_golden_run.py
# Time-travel: rewind, edit state, resume
python examples/time_travel_demo.py
# Sentinel: watch agent self-correct in real time
python examples/sentinel_demo.py
# LangGraph auto-instrumentation
python examples/langgraph_integration.py
# Basic recording and playback
python examples/basic_usage.py- Core recording and playback
- Time-travel resume with state injection
- LangGraph + CrewAI integrations
- Async recorder and player
- Terminal TUI debugger (
vcr) - Claude Code hook scaffolding (
vcr init --claude-code) - Live dashboard with DAG visualization
- ACID Transactions (git-backed filesystem rollback)
- Ghost Replay (zero-cost replay of successful runs)
- Sentinel β real-time code quality guardian
- Context manager (
with VCRRecorder() as r:) - Claude Code / Cursor integration
- AutoGen integration
- Replay regression tests (golden paths as CI assertions)
- Collaborative debugging (share sessions)
- Cloud storage backend (S3, GCS)
If Agent VCR saved your repo from a bad autonomous run, share it:
- OpenHands β Discord
#toolschannel - LangGraph β Discord
#communitychannel - r/LocalLLaMA β post your ACID rollback story
- Hacker News β Show HN posts with real before/after diffs get traction
The best growth comes from developers sharing the moment it saved them. If that's you, a post with your actual corrupted-repo story (even anonymized) is worth more than any ad.
git clone https://github.com/ixchio/agent-vcr.git
cd agent-vcr
pip install -e ".[dev,tui]"
make verifySee CONTRIBUTING.md for guidelines.
MIT β see LICENSE.
Every AI agent developer has had a bad run trash their codebase. Agent VCR is the undo button.
pip install ai-agent-vcrβ Star on GitHub Β· π¦ PyPI Β· π Docs
Built by ixchio Β· MIT License