Record-replay debugger for AI agent runs
Project description
rewind
Record-replay debugger for AI agent runs. Time-travel debugging for agent harnesses.
An agent only touches the outside world through a narrow boundary: model calls in, tool calls out. rewind captures everything crossing that boundary, then replays it exactly — or branches from any step to explore alternate trajectories.
Installation
pip install rewind-llm
With optional SDK extras:
pip install rewind-llm[anthropic] # Anthropic SDK support
pip install rewind-llm[openai] # OpenAI SDK support
Quickstart — SDK instrumentation
from rewind import Session, Mode, instrument
session = Session(mode=Mode.RECORD, trace_path="run.jsonl")
# One line — captures all HTTP traffic through the SDK client.
instrument(client, session)
# Your agent code stays exactly the same:
response = client.messages.create(model="claude-sonnet-4-20250514", messages=[...])
Tools still use the decorator:
@session.tool
def search(query: str) -> str:
return my_search_api(query)
Record → Replay → Branch
# RECORD a run
session = Session(mode=Mode.RECORD, trace_path="run.jsonl")
instrument(client, session)
run_my_agent(client)
# REPLAY it — exact same trajectory, no API calls
session = Session(mode=Mode.REPLAY, trace_path="run.jsonl")
instrument(client, session)
run_my_agent(client) # returns recorded results
# BRANCH at step 2 — inject a different model response, go live after
session = Session.branch("run.jsonl", "branch.jsonl", at_step=2,
override=my_edited_response)
instrument(client, session)
run_my_agent(client) # replays steps 0-1, injects override at 2, live from 3+
CLI proxy recording
Record and replay CLI tool sessions through a transparent HTTP proxy — no code changes required.
# Record a Claude Code session
rewind record -- claude "fix the bug"
# Replay it (no API calls, instant)
rewind replay traces/anthropic_20260101_120000.jsonl -- claude "fix the bug"
# Standalone proxy (connect your tool manually)
rewind proxy --mode record --trace session.jsonl
The proxy intercepts HTTP traffic between your CLI tool and the AI provider, capturing every request/response pair.
Provider auto-detection
The proxy auto-detects the AI provider from the command name and sets the appropriate environment variable:
| Command | Provider | Env var |
|---|---|---|
claude, claude-code |
Anthropic | ANTHROPIC_BASE_URL |
opencode, aider |
OpenAI | OPENAI_BASE_URL |
gemini |
Gemini | GOOGLE_GEMINI_BASE_URL |
agy |
Antigravity | ANTIGRAVITY_BASE_URL |
CLI commands
rewind ls # List traces
rewind show <trace.jsonl> # Pretty-print
rewind diff <a.jsonl> <b.jsonl> [--html out.html] # Diff traces
rewind branch <trace> --at N --edit|--inject|--live # Branch
rewind migrate <traces>... # v0 → v1
rewind record -- <cmd> # Record via proxy
rewind replay <trace> -- <cmd> # Replay via proxy
rewind proxy --mode record|replay --trace <file> # Standalone proxy
Configuration
| Variable | Default | Description |
|---|---|---|
REWIND_TRACE_DIR |
traces |
Directory for storing trace files |
# Store traces in a custom directory
export REWIND_TRACE_DIR=~/.rewind/traces
rewind record -- claude "fix the bug"
# List traces from a custom directory
REWIND_TRACE_DIR=/tmp/test rewind ls
How it works
Transport capture
instrument(client, session) swaps the httpx transport inside your SDK client (Anthropic or OpenAI). Every HTTP request/response is captured transparently — no changes to your agent code.
Normalization
Real requests contain volatile fields (timestamps, request IDs, SDK versions) that change on every run. rewind strips these before hashing so irrelevant changes don't cause false divergences. Configure with MatchConfig:
from rewind import MatchConfig, Session, Mode
config = MatchConfig(
ignore_headers=["x-request-id", "date"],
ignore_body_paths=["metadata.session_id"],
ignore_body_patterns=[r"[0-9a-f-]{36}"], # UUIDs
)
session = Session(mode=Mode.REPLAY, trace_path="run.jsonl", match_config=config)
Structured divergence reports
When inputs don't match, DivergenceError carries a DivergenceReport showing which fields differ and whether each was marked as ignorable — so you can tighten config in one pass.
Modes
- RECORD: executes for real, appends each request/response to a JSONL trace
- REPLAY: returns recorded results by step order, verifies inputs via normalized SHA-256 hash
- BRANCH: replays up to step N, injects an override or goes live, writes a child trace
Development
pip install -e ".[dev]"
python -m pytest tests/ -v
No API key required — tests use MockTransport and MockModel.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rewind_llm-0.2.0.tar.gz.
File metadata
- Download URL: rewind_llm-0.2.0.tar.gz
- Upload date:
- Size: 41.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
825eaace19b3a0700ae363eccfcae275a8385499dc8db2798e9463ebe8ba76ab
|
|
| MD5 |
33b9fe3628f0f649055791f9df771420
|
|
| BLAKE2b-256 |
364e0f495e99e4a2d6593504b5549bd9185146faa05329d5b7035b904c8a23b4
|
Provenance
The following attestation bundles were made for rewind_llm-0.2.0.tar.gz:
Publisher:
ci.yml on Praashh/rewind
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rewind_llm-0.2.0.tar.gz -
Subject digest:
825eaace19b3a0700ae363eccfcae275a8385499dc8db2798e9463ebe8ba76ab - Sigstore transparency entry: 2129747533
- Sigstore integration time:
-
Permalink:
Praashh/rewind@64b4c15747204242c9182356ac4c7b8447dfcd1c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Praashh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@64b4c15747204242c9182356ac4c7b8447dfcd1c -
Trigger Event:
push
-
Statement type:
File details
Details for the file rewind_llm-0.2.0-py3-none-any.whl.
File metadata
- Download URL: rewind_llm-0.2.0-py3-none-any.whl
- Upload date:
- Size: 34.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73967de32b3b3845d27bb061cde954023401fc777f5e75182888e0bf7b2bd466
|
|
| MD5 |
4c72ddd7e6a63c2d0d4a0a0251b87314
|
|
| BLAKE2b-256 |
f95a0e67e46d8f76bbe5889a35caf9362b07d6b4b01c5a3684b0e6cb1f59d1c0
|
Provenance
The following attestation bundles were made for rewind_llm-0.2.0-py3-none-any.whl:
Publisher:
ci.yml on Praashh/rewind
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rewind_llm-0.2.0-py3-none-any.whl -
Subject digest:
73967de32b3b3845d27bb061cde954023401fc777f5e75182888e0bf7b2bd466 - Sigstore transparency entry: 2129747582
- Sigstore integration time:
-
Permalink:
Praashh/rewind@64b4c15747204242c9182356ac4c7b8447dfcd1c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Praashh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@64b4c15747204242c9182356ac4c7b8447dfcd1c -
Trigger Event:
push
-
Statement type: