Skip to main content

rr for nondeterministic AI agents — deterministic record-replay and counterfactual branching.

Project description

Kinescope

rr for nondeterministic AI agents — capture every nondeterministic input so any run replays deterministically, and can be branched: "what if the model had chosen the other tool here?"

Kinescope records the nondeterministic frontier of an agent (LLM calls, tool calls, clock, RNG/UUID, retrieval), replays any run deterministically from the trace, and lets you fork at any step — override one recorded event and resume live — to explore counterfactuals. A Textual timeline lets you scrub steps, inspect message/tool I/O and state diffs, and fork with one key.

The demo: an agent fails a task; you scrub to the step where it picked the wrong tool, fork and override just that decision, and watch the branched run complete — fully reproducible from the recording.

The Kinescope timeline TUI: forking a recorded run at the sensor step and watching the downstream classification flip from "cold" to "warm" — reproduced live from the trace.

Fork-and-fix in the timeline TUI: override one recorded step, and the tail re-runs live. Reproduce it with python examples/fork_demo_tui.py.

  • Local-first, pluggable: traces live in .kinescope/ (SQLite index + content-addressed blobs) by default — no external services; a MongoStore backend (kinescope[mongo]) drops in via the same TraceStore port.
  • Tiny core: the engine depends on httpx only; anthropic, openai, the CLI, the TUI, and Mongo are optional extras.
  • Provider-agnostic: interception is at the httpx transport, so the same record→replay→fork engine drives Anthropic Messages, OpenAI Chat Completions, Google Gemini generateContent (a very different wire shape — model in the URL, not the body), and local models via Ollama. Only the gen_ai.* metadata normalization differs (src/kinescope/adapters/).
  • Proven on real calls: three genuine runs are recorded and committed as bundles that replay offline, bit-for-bit in CI — hosted Anthropic and Gemini calls, plus a local Ollama model (no key, no network). See examples/fixtures/real_*_run.zip; regenerate with python examples/live_record.py / live_gemini_record.py / live_ollama_record.py.
  • Interoperable: event metadata follows the OpenTelemetry GenAI conventions, so any recorded run exports as gen_ai.* spans (kinescope export-otel) into existing observability backends (Phoenix, Langfuse, …).

Status: feature-complete — deterministic record→replay across the full nondeterministic frontier (LLM calls — sync, async, SSE streaming; @kinescope.tool calls; opt-in clock/RNG/UUID), an honest divergence detector, state snapshots with per-step diffs, counterfactual branching (fork at any step, override one event, run the tail live), a timeline TUI, a full CLI runner (record/replay/fork your agent script), three providers (Anthropic, OpenAI, Gemini), a real recorded Anthropic run that replays offline, OpenTelemetry export, a MongoDB backend, and shareable trace bundles. 62 offline tests. See ROADMAP.md and PROGRESS.md.


Run it

Prerequisites: Python ≥ 3.11 (check: python --version).

py -m venv .venv
source .venv/Scripts/activate      # Windows Git Bash; use `.venv/bin/activate` on macOS/Linux
pip install -e ".[dev]"            # core + anthropic + openai + cli + tui + otel + test tooling
python examples/fork_demo.py       # the flagship fork-and-fix loop (cold -> warm)

(A Makefile offers make demo / make test / make lint shortcuts if you have make.)

Run the examples end-to-end (offline — no API key, no network):

python examples/record_demo.py     # records one Anthropic call, then replays it deterministically
python examples/tool_agent.py      # a tool + clock + RNG + LLM agent, recorded and replayed
python examples/stateful_agent.py  # snapshots state across steps, then diffs it
python examples/fork_demo.py       # fork-and-fix: override one step, watch the outcome change
python examples/fork_demo_tui.py   # the same, in the timeline TUI — scrub, then press 'f'
python examples/openai_demo.py     # the same engine recording a second provider (OpenAI)
python examples/otel_export.py     # export a recorded run as OpenTelemetry gen_ai spans
python examples/share_bundle.py    # export a run to a zip, import it elsewhere, replay it

Inspect and drive recorded runs from the CLI:

kinescope record -- python your_agent.py            # record an agent script (uses kinescope.http_client())
kinescope replay <run-id> -- python your_agent.py   # replay it deterministically
kinescope fork <run-id> --at 3 --override '{"output": 72}' -- python your_agent.py  # counterfactual
kinescope ls                         # list recorded runs (with fork lineage)
kinescope show <run-id> [--step k]   # inspect a run's events and I/O
kinescope diff <run-id> <a> <b>      # state diff between two steps
kinescope ui <run-id>                # scrub the timeline TUI (view-only)
kinescope export-otel <run-id>       # emit OpenTelemetry gen_ai.* spans to the console
kinescope export <run-id> run.zip    # package a run into a shareable bundle; `kinescope import run.zip`

record/replay/fork run your agent script (which builds its client with kinescope.http_client()) in-process under a session — try it offline with examples/agent_script.py.

The timeline (TUI)

kinescope ui <run-id> opens a three-pane timeline — steps · detail · state diff — that you scrub with ↑/↓. Launched with an agent (kinescope.ui(run_id, agent=run_agent)), f forks the highlighted step, overrides its output, and runs the tail live — the fork-and-fix loop shown in the gif above (static frame):

┌ Kinescope ── weather#fork@0  …  ⑂ from <parent>@0 ───────────────────────────────────┐
│ seq kind  name        │ #1 tool classify              │ state diff (sensed → …)     │
│  0  tool  sensor  fork│ ok · 0ms                      │ ~ /verdict   "warm"         │
│ ▸1  tool  classify    │ input  [72]                   │                             │
│                       │ output "warm"                 │                             │
└ ↑/↓ scrub · f fork · q quit ───────────────────────────────────────────────────────┘

Both examples use the real Anthropic SDK wired through a Kinescope transport with a stub inner transport, so they record and replay with no network and no key — and replay provably never touches the network.

Use it in your own agent

import anthropic, kinescope

@kinescope.tool                              # tool calls are recorded boundaries
def get_weather(city: str) -> dict:
    ...

def run_agent():
    client = anthropic.Anthropic(http_client=kinescope.http_client())
    msg = client.messages.create(
        model="claude-opus-4-8", max_tokens=256,
        messages=[{"role": "user", "content": "What's the weather in Paris?"}],
    )
    return msg

# capture=[...] also records direct clock/RNG/UUID use (opt-in; off by default)
with kinescope.record("paris", capture=["clock", "rng"]) as rec:
    run_agent()

with kinescope.replay(rec.run_id) as rep:    # reproduce, offline & deterministic
    run_agent()
assert not rep.divergences

# counterfactual: override step k's output, then run the tail LIVE
with kinescope.fork(rec.run_id, at=3, override={"output": {"temp_f": 71}}) as branch:
    run_agent()                            # steps 0–2 replay; step 3 is overridden; 4+ go live
print(branch.run_id)                       # a new child run, linked to its parent

For async agents use kinescope.async_http_client() with anthropic.AsyncAnthropic. Streaming (messages.stream(...)) is captured and replayed automatically.

Commands

Command What it does
python examples\record_demo.py Run the offline record→replay demo
kinescope ls List recorded runs
kinescope show <id> [--step k] Inspect a run's events / per-step I/O
pytest Run the tests
ruff check . && mypy src Lint + typecheck

How to give feedback

You mainly test and report:

  • Describe what happened in plain language.
  • Paste any errors verbatim (the single most useful thing).
  • Screenshots for anything visual (the TUI, once it lands).

Every milestone in ROADMAP.md ends with explicit Test steps.


Project docs

Doc What's in it
DESIGN.md The full design and rationale — the single source of truth.
ROADMAP.md The milestone checklist (the plan + what's done).
PROGRESS.md Build log: what shipped each milestone and why.
docs/ Deeper docs and architecture decisions (ADRs).
Eidetic-Foundational-Doc.md The original thesis the design grew from (written under the project's original name, Eidetic).

Determinism, honestly (limitations)

Determinism is guaranteed at recorded boundaries, and leaks are surfaced, not hidden — the divergence detector flags input/order/count mismatches (strict raises, warn continues). Known limits:

  • One recording context per run. The active session is a contextvar, so boundaries on worker threads that don't inherit it are not captured — and since they never enter the sequence, the detector can't flag them. Single-thread or asyncio (tasks inherit the context) is the supported model.
  • Concurrent boundary ordering (asyncio.gather) may differ between record and replay; when it does, replay is flagged, never silently wrong.
  • Streaming replays batched — SSE is reproduced by content, not re-timed.
  • Clock/RNG capture is opt-in (record(capture=[...])); it monkeypatches time/random/uuid, so library calls to those are captured too (and replay deterministically as long as the library's call pattern is stable).
  • Throughput: inline (clock/RNG) events record at ~20k–190k/s (cache-warmth dependent) and replay faster — 10k events record+replay in well under a second; tool/LLM events are bound by per-payload blob writes (~1k/s for distinct payloads; identical payloads dedup for free).

Tech stack

Python 3.11+ · httpx transport interception · Anthropic / OpenAI / Gemini adapters · SQLite + content-addressed blobs (or MongoDB via the same port) · Typer (CLI) · Textual (TUI) · OpenTelemetry export. Hexagonal/ports-and-adapters around a deterministic core.

License

MIT — see LICENSE.

Project details


Download files

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

Source Distribution

kinescope-0.0.1.tar.gz (198.6 kB view details)

Uploaded Source

Built Distribution

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

kinescope-0.0.1-py3-none-any.whl (42.1 kB view details)

Uploaded Python 3

File details

Details for the file kinescope-0.0.1.tar.gz.

File metadata

  • Download URL: kinescope-0.0.1.tar.gz
  • Upload date:
  • Size: 198.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for kinescope-0.0.1.tar.gz
Algorithm Hash digest
SHA256 ddd62c1ca7c36f0b1673d561c141a071993eddd80d44a5790a36115b05b002c7
MD5 e48f0d7bbfa7fdfbdaa0147aa6fd3863
BLAKE2b-256 3cb6d2809b38fa036ef6c37d5a9c5928ed6964637d8b9cdd1ea1e39ff3ae5929

See more details on using hashes here.

Provenance

The following attestation bundles were made for kinescope-0.0.1.tar.gz:

Publisher: publish.yml on satchmakua/kinescope

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kinescope-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: kinescope-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 42.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for kinescope-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2d00373c76e1a29d996bf2e4686b8cb24a311636a09df93811f83a3472ef9ccf
MD5 e1eceb7296e49f6ec2f294e074ea959a
BLAKE2b-256 cea49b7a9596d3c81643b19dee5e50739211c4d6c78b5f071e09744a3c3d7af8

See more details on using hashes here.

Provenance

The following attestation bundles were made for kinescope-0.0.1-py3-none-any.whl:

Publisher: publish.yml on satchmakua/kinescope

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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