📼 Rerunner
Deterministic flight recorder, replay engine, and CI test runner for AI agents.
Record your AI agent once. Replay forever in CI in 0ms with $0 API tokens.
⚡ The Problem
Building production AI agents requires automated testing and continuous integration (CI). But running multi-step agents in tests creates three massive bottlenecks:
- Flaky CI Builds: LLMs are non-deterministic. Even at
temperature=0, small prompt variations break downstream assertions. - Exorbitant API Costs: Re-running an 8-step agent across 50 pull requests burns thousands of dollars in LLM API credits.
- Debug Nightmare: When an agent fails at Step 5, you cannot reproduce the bug locally without paying to re-run Steps 1 through 4.
Rerunner solves this by providing a zero-overhead, tamper-evident cassette recorder that intercepts httpx traffic natively across the Anthropic Claude SDK, OpenAI SDK, and custom agents.
🚀 Key Features
- $0 CI Replays: Freeze agent runs into append-only JSONL cassettes. Replay in 0ms without hitting external LLM APIs.
- Fork from Step N: Replay Steps 1..4 from the cassette for free, and execute Step 5 live against the model with your new prompt or bug fix.
- Tolerant Request Matching: Automatically strips volatile nonces, millisecond timestamps, request IDs, and SDK metadata headers (
x-stainless-*). - Side-Effect Safety: The
@side_effectdecorator prevents destructive external actions (database writes, Slack webhooks, payments) during replays. - Cryptographic Integrity: SHA-256 tamper-evident hash chaining ensures recorded cassettes have not been altered.
- Native Pytest Integration: Seamless
@pytest.mark.rerunnermarker and fixtures.
📊 Comparison
| Capability | rerunner |
vcrpy |
LangSmith |
LangGraph |
|---|---|---|---|---|
| Primary Focus | Deterministic CI Replay | Generic HTTP | Web Observability | Orchestration |
| LLM Streaming (SSE) Support | ✅ Yes | ❌ Breaks | ✅ Yes | N/A |
| Fork-from-Step Execution | ✅ Yes | ❌ No | ❌ No | ⚠️ Graph-locked |
| Side-Effect Stubbing | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Zero Infrastructure / $0 Cost | ✅ Local JSONL | ✅ Local YAML | ❌ Cloud / Paid | ❌ Variable |
| Framework Agnostic | ✅ Any httpx SDK | ✅ HTTP | ⚠️ Complex | ❌ Locked |
📦 Installation
pip install rerunner
🛠️ Quickstart
1. Recording an Agent Session
Rerunner transparently attaches to standard SDK clients via httpx.Client(transport=...):
import anthropic
import httpx
from rerunner import CassetteTransport
# 1. Record live interactions to a cassette
transport = CassetteTransport("session.jsonl", mode="record")
client = anthropic.Anthropic(http_client=httpx.Client(transport=transport))
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=[{"role": "user", "content": "Analyze quarterly revenue report."}]
)
print(response.content[0].text)
2. Deterministic $0 Replay in CI
# 2. Replay locally or in CI without spending API tokens or waiting on network
transport = CassetteTransport("session.jsonl", mode="replay")
client = anthropic.Anthropic(http_client=httpx.Client(transport=transport))
# Instant response, zero cost, completely reproducible
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=[{"role": "user", "content": "Analyze quarterly revenue report."}]
)
3. Forking from Step 3
from rerunner import fork
# Replay steps 1 through 3 from cassette; run step 4 live with your modified prompt
with fork("session.jsonl", step=3) as session:
client = session.get_client()
# Steps 1..3 replayed from tape
# Step 4 executed live against model
Compressed Cassettes
For long-running agent workflows, use the .jsonl.gz extension to store cassettes
in gzip-compressed form:
from rerunner import CassetteTransport
transport = CassetteTransport("session.jsonl.gz", mode="record")
Rerunner automatically compresses .jsonl.gz cassettes when recording and
decompresses them when replaying. The same CLI commands and SHA-256 integrity
verification work with both .jsonl and .jsonl.gz files:
rerunner inspect session.jsonl.gz
rerunner verify session.jsonl.gz
rerunner play session.jsonl.gz
🛡️ Guarding Destructive Side-Effects
Ensure your replayed agents don't charge cards or send duplicate Slack messages:
from rerunner import side_effect
@side_effect(name="post_slack_alert")
def send_slack_notification(channel: str, message: str) -> bool:
# Runs live during recording. During replay, safely returns recorded result!
return slack_client.chat_postMessage(channel=channel, text=message)
🧪 Pytest Integration
Mark your unit tests with @pytest.mark.rerunner:
import pytest
@pytest.mark.rerunner("tests/fixtures/agent_run.jsonl")
def test_agent_decision(rerunner_transport):
client = openai.OpenAI(http_client=httpx.Client(transport=rerunner_transport))
completion = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Evaluate risk factor"}]
)
assert "low risk" in completion.choices[0].message.content.lower()
Run test suite in replay mode (0 network calls, $0 cost)
pytest
Re-record all cassettes when prompts change intentionally
pytest --rerunner-record
For a reusable GitHub Actions workflow that restores recorded cassettes before
replay tests, see the [GitHub Actions cassette caching recipe](docs/recipes/github_actions_caching.md).
---
## ⚡ 1-Line Client Wrappers
Wrap your existing SDK instances with zero configuration:
```python
import anthropic
import openai
from rerunner.integrations import wrap_anthropic, wrap_openai
# Wrap Anthropic client
client_claude = wrap_anthropic(anthropic.Anthropic(), "agent_run.jsonl", mode="replay")
# Wrap OpenAI client
client_openai = wrap_openai(openai.OpenAI(), "agent_run.jsonl", mode="replay")
LangChain & LangGraph Integration
from rerunner.integrations import RerunnerCallbackHandler
handler = RerunnerCallbackHandler("langgraph_agent.jsonl", mode="replay")
agent_executor.invoke({"input": "Fetch stock price"}, config={"callbacks": [handler]})
🔒 Enterprise Secret & PII Sanitization
Never accidentally commit API keys or auth tokens to GitHub. Rerunner automatically scrubs:
- Anthropic API keys (
sk-ant-...) $\rightarrow$[REDACTED_ANTHROPIC_KEY] - OpenAI API keys (
sk-proj-...,sk-...) $\rightarrow$[REDACTED_OPENAI_KEY] - Authorization headers (
Bearer ...) $\rightarrow$Bearer [REDACTED_TOKEN] - AWS access keys (
AKIA...) $\rightarrow$[REDACTED_AWS_KEY_ID]
💻 CLI Commands
# Calculate CI cost reductions and token savings
rerunner stats session.jsonl
# Visually play back agent execution steps in terminal
rerunner play session.jsonl
# Inspect cassette details and step sequences
rerunner inspect session.jsonl
# Cryptographically verify tamper-evident hash chain
rerunner verify session.jsonl
# Compare prompt and response divergences between two cassettes
rerunner diff session_v1.jsonl session_v2.jsonl
🤝 Contributing
Contributions from the community and frontier AI research teams are warmly welcomed. Please review CONTRIBUTING.md to set up your development environment.
📜 License
Rerunner is licensed under the Apache 2.0 License.
Metadata
Release files for rerunner 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rerunner-0.1.1.tar.gz | 34.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rerunner-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.6 kB
Release files / rerunner-0.1.1.tar.gz
| Download URL | rerunner-0.1.1.tar.gz |
|---|---|
| Size | 34.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9a154cb17a13a00657920d2ffc5fbeee26fc98e226826f33aded902c72bdf561
|
|
BLAKE2b-256 checksum How to use checksums |
534611581abb0c975dd349380e36f9da4c722e6a3d7f54ccb1d6ff7501ee86f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / rerunner-0.1.1-py3-none-any.whl
| Download URL | rerunner-0.1.1-py3-none-any.whl |
|---|---|
| Size | 25.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0867225f21b319ff27e61f36db70bb1fe5bc6aeeae7dea55d0eaca30e7d70719
|
|
BLAKE2b-256 checksum How to use checksums |
9bcb35a2e557fbc6406a05d8420c0cb2363f882dba722b47548177f44ef1d9bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency log