Deterministic tests for LLM apps and agents.
retake records the OpenAI, Claude and other LLM API calls your code makes, then replays them in every test run — offline, in milliseconds, byte-for-byte the same. Built for AI agents, tool calling and streaming. One binary. Any language. No code changes.
curl -fsSL https://zecrari.github.io/retake/install.sh | sh
Windows: irm https://zecrari.github.io/retake/install.ps1 | iex · or download a binary
$ retake record -- npm test
● recorded POST /anthropic/v1/messages → 200
● recorded POST /anthropic/v1/messages → 200
✓ agent looks up the order (2.8s)
retake: 0 replayed, 2 recorded
$ retake replay -- npm test
✓ agent looks up the order (31ms)
retake: 2 replayed, 0 recorded, 0 unmatched
# someone edits the prompt…
$ retake replay -- npm test
no recording matches POST /anthropic/v1/messages
closest: step 1
- "content": "What is the status of order 1042?"
+ "content": "Where is order 1042?"
Works with
OpenAIAnthropic ClaudeOllamavLLMOpenRouterGroq PythonTypeScriptGoJava.NETRust GitHub ActionsThe problem
Testing code that calls an LLM is painful.
Real API calls make every test run slow, costly and different. Hand-written mocks drift from reality and fall apart as soon as an agent makes more than one call.
Flaky
The same prompt returns a different answer on every run, so assertions fail at random and nobody trusts the suite.
Expensive
Every push, every branch and every retry burns real tokens — and CI needs a production API key to run at all.
Slow
Seconds per call add up to minutes per suite. Agents that loop through tools make it far worse.
How it works
Record once. Replay forever.
retake is a tiny local proxy between your code and the API. It points your SDK at itself through standard environment variables — no plugins, no wrappers, no code changes.
Record a real run
Run your tests through retake with a real key. Every call is forwarded and saved as a readable JSON cassette.
retake record -- pytest
Commit the cassettes
Secrets are stripped automatically. Prompt and response changes show up in pull request diffs.
git add cassettes/
Replay everywhere
Locally and in CI, calls are served from cassettes. Nothing reaches the network, and no key is needed.
retake replay -- pytest
Any language
Works with the SDK you already use.
Because retake speaks plain HTTP, it works the same from Python, TypeScript, Go, Java, .NET, Ruby, Rust or curl. The official OpenAI and Anthropic SDKs read OPENAI_BASE_URL and ANTHROPIC_BASE_URL automatically.
Want one cassette per test? Send an x-retake-session header — that's the only line you'll ever add.
from openai import OpenAI
# Base URL comes from retake. Nothing else changes.
client = OpenAI(default_headers={
"x-retake-session": "checkout/refund-flow",
})
reply = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[{"role": "user", "content": "Refund order 1042"}],
)import Anthropic from "@anthropic-ai/sdk";
// ANTHROPIC_BASE_URL is set by retake.
const client = new Anthropic({
defaultHeaders: { "x-retake-session": "agent/lookup-order" },
});
const msg = await client.messages.create({
model: "claude-sonnet-5-5",
max_tokens: 512,
messages: [{ role: "user", content: "Where is order 1042?" }],
});# .github/workflows/test.yml
steps:
- uses: actions/checkout@v5
- uses: Zecrari/retake@v0
- run: retake check # no secrets in cassettes
- run: retake replay -- npm test
# no API key, no network, no cost# Any OpenAI-compatible API: Ollama, vLLM, Groq, OpenRouter…
retake record \
--upstream ollama=http://localhost:11434 \
-- python app.py
# Your app uses $RETAKE_OLLAMA_URL/v1 as its base URL.
# Or run the proxy on its own and point anything at it:
retake replay --port 9000Features
Small tool. Sharp edges filed off.
Everything you need to trust LLM tests in CI, and nothing you don't.
Byte-identical streaming
Server-sent events are stored as whole events and replayed exactly. Add --timing realtime to reproduce the original pacing.
Built for agents
Repeated identical calls replay in recorded order; parallel calls match independently. Tool-calling loops just work.
Diffs, not mysteries
An unrecorded call fails with a clear 404 and a diff against the closest recording — never a silent real call or a retried 5xx.
Safe to commit
Request headers are never stored, and keys and tokens in bodies are redacted. retake check guards your repo in CI.
Smart matching
JSON is compared after sorting keys, so formatting never matters. --ignore skips fields like request IDs.
Single static binary
Written in Rust. No Python, Node or Docker required. Prebuilt for Linux, macOS and Windows.
Compared
Mocks, live calls, or a recording?
Recordings give you real model output with the speed and determinism of a mock.
| Live API calls | Hand-written mocks | retake | |
|---|---|---|---|
| Real model behavior | Yes | No — invented | Yes — recorded |
| Deterministic | No | Yes | Yes |
| Cost per CI run | Tokens every time | Free | Free |
| Speed | Seconds per call | Instant | Instant |
| Works offline / without a key | No | Yes | Yes |
| Effort for a multi-step agent | None | High, and it drifts | One record run |
Use cases
Everything that calls a model, under test.
From a single prompt to a 30-step agent: if it speaks HTTP to an LLM API, retake can record it.
AI agent regression tests
Record a full agent run — every tool call and tool result — and replay the exact trajectory. A changed prompt shows up as a diff, not a mystery.
Tool calling & structured outputs
Lock down function-calling and JSON-schema responses so parsers, validators and downstream code are tested against real model output.
RAG pipelines
Replay embeddings and completions together, so retrieval and generation are tested end to end without paying for either.
Prompt changes in code review
Cassettes are readable JSON. Re-record after a prompt change and reviewers see the prompt diff and the new model output side by side.
A fast evals inner loop
Iterate on scoring and post-processing against recorded outputs in milliseconds, and re-record only when you change the model or prompt.
Offline development & demos
Run your app on a plane, in air-gapped CI, or in a live demo where the network can't be trusted — with real responses.
Guides
Learn LLM testing, the practical way.
Step-by-step guides for the questions teams ask most when they start testing AI features.
How to test AI agents deterministically
Record multi-step, tool-calling agent runs and replay them as fast, reliable regression tests.
Read the guide → CI/CDRun LLM tests in CI without API keys
Keep secrets out of CI, stop paying for every push, and make pipelines deterministic.
Read the guide → ConceptsVCR for LLMs: record/replay vs mocks
When to mock, when to call the real API, and when a recording beats both.
Read the guide →FAQ
Questions, answered.
What is retake?
retake is a free, open-source record and replay proxy for LLM APIs — a “VCR for LLMs”. It records real OpenAI, Anthropic or OpenAI-compatible API calls once, saves them as readable cassette files, and replays them in later test runs so tests are fast, free, offline and deterministic.
Do I need to change my code?
No. retake sets OPENAI_BASE_URL and ANTHROPIC_BASE_URL for the command it runs, and the official SDKs read those variables automatically. Optionally, send an x-retake-session header to use one cassette per test.
Which languages and providers are supported?
Any language, because retake is an HTTP proxy. OpenAI and Anthropic work out of the box, and any OpenAI-compatible API — Ollama, vLLM, LM Studio, Groq, OpenRouter, Azure OpenAI — can be added with --upstream name=url.
Does it support streaming responses?
Yes. Server-sent event streams are stored as whole events and replayed byte-for-byte. Replays are instant by default; --timing realtime reproduces the original pacing when you need to test timeouts or streaming UI.
Is it safe to commit cassettes to git?
retake never stores request headers, so keys sent in headers can't reach a cassette, and it redacts anything in bodies that looks like an API key, token or private key. Run retake check in CI or as a pre-commit hook to catch anything else, and review cassettes for personal data before committing.
What happens when a prompt changes?
In replay mode the request no longer matches, so retake fails it with a 404 and prints a diff against the closest recording. Re-record with retake record, or use retake auto to record only the new calls.
How do I test AI agents with retake?
Run the agent's test once with retake record. Every model call is saved in order, including tool calls. On replay, the first response is identical, so your agent sends the same follow-up requests, which match the recording too — the whole trajectory replays deterministically. Keep your tools deterministic in tests (fixed clocks, seeded data) or ignore volatile fields with --ignore.
Is retake an evals framework?
No. Evals measure how good model output is; retake makes tests repeatable by replaying recorded output. They work well together: replay recorded outputs to iterate on your scoring code quickly, and re-record when you change the model or prompt.
Is retake free?
Yes — free and open source under the MIT license.
Make your LLM tests boring again.
Install in seconds, record once, and never pay for a flaky test run again.