Skip to main content

⏺ Reflight

Flight recorder for AI agents: record every run, replay it deterministically, turn failures into regression tests.

Reflight is reliability infrastructure, not a detector or an eval: it makes agent behavior reproducible, testable, and governable. Recordings use an open, documented format that anything can consume — detectors, evals, and observability tools run on top of it.

Live demo · real recorded runs, replayable in your browser, no install.

New: a real one. Fifteen live runs of a gpt-4o-mini scheduling agent all passed every tool-level check — and all booked the meeting on a Sunday. The recordings, the judge whose catch rate swung from 5/5 to 1/5 on identical failures, and the 15-line assertion that caught every one: the case study.

A real recording, replaying: a support agent sends the refund amount as a string, retries the same broken call, and gets caught —

The flight recorder replaying a recorded failure: the agent retries a malformed refund call until the classifier labels it

A recorded agent run: the loop caught, labeled, and frozen on the timeline

Two runs of the same task, diffed — the passing run sent query, the failing run sent q. First divergence highlighted:

Run diff: first divergence highlighted at the exact event

Agents are programs whose most important steps are non-deterministic and external. When one fails, the failure evaporates — re-running gives you a different run. Reflight makes agent failures reproducible, and builds the whole reliability loop on top:

agent fails → the recorded run is already a reproducible test case → reflight promote <run_id> adds it to your suite → CI replays it forever, so that failure can never silently come back.

What you get

🎥 Record Every LLM call, tool call, token and dollar — 3 added lines, sync or asyncio (record_async)
Replay Re-run any recording byte-identically: offline, ~7ms, $0.00
🔍 Debug Timeline UI with event inspector; --step CLI debugger; run-diff with first-divergence highlighting
🏷 Classify Rule-based failure labels (loop, wrong_tool_args, cascade, crash, runaway) + LLM judge with ensemble voting (--votes 3)
🛂 Flight check flight_check=True flags network I/O that bypassed the session — the run is marked unrecorded_io instead of silently un-replayable
🔱 Fork Replay to step N, go live after — test a fix mid-run
Promote One command: recorded failure → editable YAML regression test
📊 Harness N-run consistency scoring, baselines, CI gate that blocks reliability regressions
Govern Hard cost/token budgets, loop circuit breaker, tool-call cache, cost dashboard with anomaly flags
📡 Export reflight otel <run_id> ships any run to your OTLP collector as GenAI-convention spans — works with Langfuse/Datadog/Jaeger, not against them

Quickstart

git clone <repo> && cd reflight
uv sync                      # installs the SDK + CLI (Python 3.12+)

# record two demo runs (scripted model — no API key needed)
uv run python examples/research_agent/main.py record \
    "What is the population of Tokyo, and what is that number divided by 2?" \
    --offline --run-id demo-research
uv run python examples/research_agent/main.py record \
    "What is 12 divided by 0? Use the calculator." --offline --run-id demo-failure

# replay the failure — network off, $0.00, byte-identical
uv run python examples/research_agent/main.py replay demo-failure --step

# query them
uv run reflight import runs
uv run reflight runs
uv run reflight show demo-failure

The timeline UI

uv run reflight serve            # API on :8724
cd ui && npm install && npm run dev   # UI on :3000

Runs list → click a run → color-coded timeline → event inspector. Findings banner on failed runs; pick two runs to diff; /costs for the money view.

To build the zero-backend static demo site (what the hosted demo runs):

uv run reflight export-static        # db → ui/public/demo/*.json
cd ui && STATIC_EXPORT=1 NEXT_PUBLIC_STATIC_DEMO=1 npm run build   # → ui/out/

Instrument your own agent — 3 lines

import reflight

session = reflight.record("runs/my-run", task=task, db_path="runs/reflight.db")  # 1
client = session.wrap(anthropic.Anthropic())                                          # 2
my_tool = session.tool(my_tool)                        # 3 — or @session.tool

# ... your agent code runs unchanged ...
session.end(final_text=answer)

OpenAI-compatible clients: client = session.wrap_openai(OpenAI()). MCP tool calls: mcp = session.wrap_mcp(mcp_client_session) — recorded and replayed on the same timeline as everything else (async).

Recordings contain no API keys by construction (arguments are recorded, not HTTP headers). For secrets that flow through tool data, pass redact=reflight.redact_patterns(r"sk-\w+") — masked before disk, hash fields preserved so the recording stays replayable.

LangGraph / LangChain agents instrument without code changes:

from reflight.adapters.langchain import instrument

model, tools = instrument(session, ChatOpenAI(model="gpt-4o-mini"), tools)
agent = create_react_agent(model, tools)   # unchanged LangGraph code

Validated against the real thing: examples/langgraph_live.py records a live LangGraph run and replays it byte-identically offline. (Sync paths; coroutine-only tools rejected loudly.)

Replay it later — same agent code, session swapped:

session = reflight.replay("runs/my-run")     # no network, no key, no cost
client = session.wrap()

Every failure becomes a regression test

This is how you build a golden dataset from real failures, automatically — the thing every 2026 eval-methodology guide says reliable agent teams need, assembled one promote at a time instead of hand-curated.

uv run reflight promote my-failed-run       # → agent_tests/my-failed-run.yaml

Edit the assertions to state what SHOULD happen — then they're just pytest tests. Point pytest at your agent once:

# pytest.ini
[pytest]
reflight_agent = my_pkg.agent:run_agent            # agent(session, task)
reflight_tools_factory = my_pkg.agent:make_tools   # optional
reflight_client_factory = my_pkg.agent:make_client # optional: enables live re-verify

and every agent_tests/*.yaml collects and runs in your normal pytest invocation. Replay-first economics: passing tests cost $0.00; replay failures are re-verified live; code changes trigger a live re-run. Programmatic alternative: reflight.testing.run_suite. See the full loop in examples/flaky_agent/regression_demo.py and the CI gate in examples/flaky_agent/ci_gate.py.

The governor

from reflight import Governor

session = reflight.record(..., governor=Governor(
    max_cost_usd=0.50,       # hard kill at the cap — reason recorded in the run
    loop_breaker=3,          # N identical consecutive tool calls allowed
    cache_tool_calls=True,   # serve repeats from cache (still recorded)
))

Demos (all offline, no API key)

uv run python examples/quickstart/agent.py record && uv run python examples/quickstart/agent.py replay
uv run python examples/flaky_agent/fleet.py 10          # classifier labels a flaky fleet
uv run python examples/flaky_agent/fix_demo.py          # fork a failed run mid-flight
uv run python examples/flaky_agent/regression_demo.py   # fail → promote → fix → pass
uv run python examples/flaky_agent/governor_demo.py     # runaway killed at $0.50
uv run python examples/flaky_agent/ci_gate.py           # CI reliability gate (add --degrade)

Where it sits in your stack

The question everyone asks: "how is this different from what I already use?"

You already use… It does Reflight adds
LangSmith / Langfuse / Braintrust Hosted observability: traces, dashboards, datasets Deterministic replay — their traces describe a run; a Reflight recording can re-execute it. Local-first, no SaaS. Composes with them via reflight otel.
pytest-vcr / vcrpy Records HTTP for API tests The same idea lifted to the agent layer: tool calls, parallel execution, streaming, divergence detection, failure classification — plus promote, which VCR never had.
Eval harnesses (capability benchmarks) "Can the model do X?" "Does my agent still do X, every time, this week?" — consistency over capability, wired into CI as a merge gate.
Detectors / guardrails (hallucination checkers, semantic judges) Judge content in the moment The substrate they should run on: a detector consuming recordings gets reproducible inputs and can write findings back. Reflight's own judge is one small example.
Docker cagent VCR cassettes for agents built in its runtime Reflight instruments your existing Python agent — any loop, any framework — and adds everything downstream of the cassette: classification, promote→pytest, fingerprinting, fork, governor.
Laminar Hosted replay-from-a-step in their UI The same debugging move, local-first: reflight.fork(run, at_seq=N) — plus the recording is a file you own, not a SaaS row.
MCP recorders (mcp-recorder, Agent VCR) Record/replay one MCP server's wire protocol session.wrap_mcp(...) records MCP tool calls inside the whole agent recording — one timeline for LLM calls, local tools, and MCP together.

Short version: everything else observes or evaluates. Reflight makes runs reproducible — and everything downstream of reproducibility (regression tests, CI gates, recurrence tracking) is what the others can't offer.

How replay works (and its honest limits)

Recording captures every request/response pair in an append-only events.jsonl. Replay re-executes your agent code with all external I/O served from the recording, verifying at each step that the code is making the same requests it made before — a changed prompt or tool raises ReplayDivergence instead of lying. Replay is deterministic for the recorded path; it is not time travel for arbitrary changes — that's what fork mode and live re-verification are for. Streaming agents are supported (the messages.stream() helper pattern replays chunk-identically), and so are parallel tool calls — replay matches by tool_use_id, so any completion order replays. Agent code that consults the clock, PRNG, or uuid.uuid4() between calls is covered too: wrap the loop in with session.pin(): and those draws are recorded and served back on replay, so timestamped requests and generated ids replay exactly. The full honest map of what replay can and can't see — including what the pin does not cover — is docs/limits.md; smaller open items are tracked in NOTES.md.

Verified against a real API: examples/live_api_check.py records two dependent live calls and replays them byte-identically with the network blocked. Judge accuracy vs seeded ground truth: 12/12 (examples/flaky_agent/judge_accuracy.py).

Layout

sdk/reflight/    the library: recorder, replayer, fork, classify, judge,
                   testing (promote/runner), executor, reliability, governor,
                   store (SQLite), server (FastAPI), cli
ui/                Next.js timeline UI
examples/          research agent, quickstart, flaky fleet + demos
tests/             the whole story as pytest (100+ tests)
docs/              quickstart, concepts, blog drafts

Development

uv sync && uv run pytest       # tests
uv run ruff check .            # lint

Plans live in PROJECT_PLAN.md, GAMEPLAN.md, SPRINTS.md. Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

reflight-0.1.0.tar.gz (175.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

reflight-0.1.0-py3-none-any.whl (61.9 kB view details)

Uploaded Python 3

File details

Details for the file reflight-0.1.0.tar.gz.

File metadata

  • Download URL: reflight-0.1.0.tar.gz
  • Upload date:
  • Size: 175.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for reflight-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ad73afa87a9c07069253b079182d07edf289c450b66d0cb62135cdba66ce9200
MD5 8aa71fe2fe12bd2da6d07b40f2aaf317
BLAKE2b-256 cdbe2434a11e92e474c48c5f333a7767447bfda913aa77f6f88342f3a839c838

See more details on using hashes here.

File details

Details for the file reflight-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: reflight-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 61.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for reflight-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b2c0f7ce7c784027a2557ef223d8093de3f7e837c2796cd511b6e99abe4448b7
MD5 576505b6cebb2e9270881952c240dd1b
BLAKE2b-256 152d0cb26421a840b781c126758e3adef9c526780622e52079c391decf994a46

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page