Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

lockstepd

CI

Status: experimental · v0.2.0-beta. Kernfunktionen sind durch 187 Tests abgedeckt (185 in der Standard-Suite, grün ohne Keys und Netz; 2 key-gated Live-Smoke-Tests), das Format ist stabil (v1) — die API darf sich vor 1.0 aber noch ändern.

Deterministischer Replay-Debugger für Agent-Läufe. Zeichne jeden LLM-Aufruf, jedes Tool-Ergebnis, jede Uhr- und Zufalls-Lesung in eine manipulationssichere Datei auf. Spiele den Lauf offline bit-exakt wieder — prüfbar per Hash-Kette. Verzweige an beliebiger Stelle und lass lockstepd bisect automatisch den Schritt finden, an dem alles gekippt ist.

Änderungen: CHANGELOG.md.


Das Problem

Agenten sind nicht reproduzierbar: erneutes Laufen lässt das Modell anders samplen, Tools liefern andere Daten, und der Bug ist weg, bevor du ihn siehst. Observability-Tools zeigen dir Traces — aber ein Trace ist Protokoll, kein Debugger: du kannst nicht anhalten, einen Schritt ändern und von dort neu laufen lassen. Genau diese Lücke füllt lockstepd: Aufzeichnung wird zur ausführbaren Wahrheit, gegen die du Code ändern, verzweigen und Ursachen eingrenzen kannst.

Demo-Session

$ make demo

──── 1 · RECORD ────
recorded examples/data/demo.lockstep.gz  events=214 steps=26 trace=c2a74eb72004be11…

──── 2 · REPLAY (offline, kein Netz) ────
replay identical trace=c2a74eb72004be11…

──── 3 · VERIFY ×20 (Determinismus-Nachweis) ────
identical replays: 20/20

──── 4 · SCRUB ────
scrubbed 96 events -> clean.lockstep.gz (remaining suspicious: 0)
clean-check: clean rc=0

──── 6 · BISECT (eingebauter Fehler bei tools:10 finden) ────
┌─────────── bisect result ───────────┐
│ field           │ value             │
│ culprit step    │ 22  (= tools:10)  │
│ first bad fork  │ 23                │
│ probes / budget │ 7 / 7             │
│ total steps     │ 52                │
└─────────────────────────────────────┘

Der Bisect-Lauf oben ist echt: ein 25-Schritt-Demo-Agent mit einem Gift-Wert im Tool-Ergebnis von Schritt 10 — gefunden in 7 Proben (Budget ⌈log₂(52)⌉+2).

Installation

uv add lockstepd            # Kern (msgspec) + CLI (typer/rich)
uv add "lockstepd[httpx]"   # Transport-Instrumentierung (empfohlen)
pip install "lockstepd[anthropic]"   # oder [openai] – optional, SDK-seitige Helfer

Python ≥ 3.12. CI-fähig ohne API-Schlüssel und ohne Netzwerk (Fake-Backend inklusive).

Schnellstart

Variante A — CLI (Subprozess, empfohlen):

lockstepd record run.lockstep.gz -- examples/demo_agent.py --steps 12
lockstepd replay run.lockstep.gz -- examples/demo_agent.py --steps 12   # gleiche Syntax
lockstepd verify run.lockstep.gz --times 100 -- examples/demo_agent.py --steps 12
lockstepd inspect run.lockstep.gz

Der ---Fallback über LOCKSTEP_COMMAND (JSON) funktioniert weiterhin, ist aber nicht mehr nötig.

Dein Agent braucht dafür genau zwei Zeilen:

from lockstepd.runtime import auto_session

session = auto_session()          # liest LOCKSTEP_RECORD / LOCKSTEP_REPLAY / LOCKSTEP_FORK_*
with session:
    ...  # normaler Agentencode; httpx-Clients werden automatisch instrumentiert

Variante B — In-Process-API:

import httpx
from lockstepd.session import Session
from lockstepd.integrations.httpx_transport import LockstepTransport
from lockstepd.patchers.concurrency import OrderedExecutor

with Session.record("run.lockstep.gz") as s:
    client = httpx.Client(base_url="https://api.provider.test/v1",
                          transport=LockstepTransport(s))          # zeichnet auf
    # ... LLM-Aufrufe über client, Tools über OrderedExecutor ...
    s.final_state.update({"answer": answer})
print(s.trace_hash_hex)

Replay desselben Codes:

with Session.replay("run.lockstep.gz") as s:
    client = httpx.Client(..., transport=LockstepTransport(s))     # serviert vom Band
    ...
assert s.trace_hash_hex == recorded_hash                          # bit-exakt

Fork & Bisect siehe lockstepd fork --help / lockstepd bisect --help sowie examples/check_failed.py.

Was aufgezeichnet wird

LLM-Anfragen/-Antworten inkl. Streaming-Chunks mit relativen Ankunftsabständen, Tool-Aufrufe mit Abschlussreihenfolge (completion_index), Uhren (time, datetime), Zufall (random, uuid4, os.urandom), gelesene Umgebungsvariablen (redaktiert), optionale FS-Zugriffe, Retries und Fehler — alles in einer gzip-JJSONL-Datei mit BLAKE2b-Hash-Kette. Details: FORMAT.md.

CLI

Befehl Zweck
lockstepd record OUT -- script.py args… Lauf aufzeichnen
lockstepd replay TAPE -- script.py args… offline wiederabspielen; Divergenz ⇒ Fehler mit Diff
lockstepd verify TAPE --times N -- script.py … Integrität + N-facher Identitätsnachweis
lockstepd inspect TAPE interaktiver Trace-Browser (rich)
lockstepd diff A B erste Divergenz + Unified-Diff + Kind-Statistik
lockstepd fork TAPE --at N --out F -- script.py … Prefix abspielen, Suffix live
lockstepd bisect BAD --predicate check.py -- script.py … Ursachen-Schritt per Binärsuche
lockstepd scrub TAPE -o CLEAN / --check Secrets entfernen / nachweisen
lockstepd export TAPE -o otlp.json OTLP/JSON-Spans

Echte SDKs ohne API-Key

Die echten anthropic-/openai-Clients laufen keyless gegen das Fake-Backend (lockstepd.testing.SdkFakeBackend, echte Wire-Formate inkl. SSE). Integrationstests beweisen Record → Replay bit-exakt durch den genuine SDK-Pfad — Sync und Async. Instrumentiert werden beide HTTP-Stapel: httpx und der httpx2-Fork aktueller SDKs.

Live-Smoke (opt-in, nie in CI)

Ein minimaler Record→Replay-Zyklus gegen die echten APIs liegt unter tests/test_live_smoke.py (Marker live). Er läuft nur, wenn LOCKSTEP_LIVE_SMOKE=1 und der jeweilige Provider-Key gesetzt ist — sonst Skip. Die Standard-Suite und CI schließen ihn explizit aus:

LOCKSTEP_LIVE_SMOKE=1 pytest -m live   # kostet echte Tokens; bewusst manuell

Garantien — und wo sie enden

verify --times N beweist Wiederholbarkeit empirisch; die Hash-Kette macht jede Manipulation und jede Divergenz sofort sichtbar (kryptografisch, nicht heuristisch).

Hook-Striktheit: Zeit-, Zufalls- und Env-Lesungen laufen über eigene sequentielle Queues, getrennt vom strukturellen Ereignis-Cursor. Im Standard (strict_hooks=True, Subprozess- Betrieb) ist jede Abweichung in diesen Strömen ein harter Fehler. Mit strict_hooks=False fällt lockstepd stattdessen auf reale Werte zurück und notiert die Abweichung transparent in session.soft_divergences — nützlich für In-Process-Replays, bei denen Bibliotheksräuschen (pytest-interne UUIDs, Cookie-Jar-Uhren) keine harte Divergenz wert sein soll. Die Liste macht jeden weichen Fallback sichtbar statt ihn zu verschweigen.

Was nicht reproduzierbar ist — von Set-Iteration bis C-Level-getenv — steht schonungslos in LIMITS.md. Ehrlicher Vergleich zu bestehenden Werkzeugen: PRIOR_ART.md. Aufzeichnungsformat: FORMAT.md. Entscheidungen: DECISIONS.md, Status: PROGRESS.md.

Entwicklung

make check   # ruff + ruff format --check + mypy --strict + pytest (185 Tests, ohne Keys/Netz)
make bench   # 10k-Ereignis-Benchmark
make demo    # obige Session

Lizenz: MIT.

Download files

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

Source Distribution

lockstepd-0.2.0b0.tar.gz (163.7 kB view details)

Uploaded Source

Built Distribution

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

lockstepd-0.2.0b0-py3-none-any.whl (53.0 kB view details)

Uploaded Python 3

File details

Details for the file lockstepd-0.2.0b0.tar.gz.

File metadata

  • Download URL: lockstepd-0.2.0b0.tar.gz
  • Upload date:
  • Size: 163.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lockstepd-0.2.0b0.tar.gz
Algorithm Hash digest
SHA256 0f9cb9e3671c07bef3e62bdeb004e828d0cba6dd0c6776532caf2e58cbab82c7
MD5 b1e94124f0c2d772354624bd9d72f2bf
BLAKE2b-256 41d2f17930f4fd2110be72ed2782c7d0b333aec95b0e992a17f633efc0d53ac0

See more details on using hashes here.

Provenance

The following attestation bundles were made for lockstepd-0.2.0b0.tar.gz:

Publisher: release.yml on dato-bitar/lockstepd

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

File details

Details for the file lockstepd-0.2.0b0-py3-none-any.whl.

File metadata

  • Download URL: lockstepd-0.2.0b0-py3-none-any.whl
  • Upload date:
  • Size: 53.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lockstepd-0.2.0b0-py3-none-any.whl
Algorithm Hash digest
SHA256 0cc72562ab81f841200495e85a9e306494c3d051f4f5c1354b46abe9a5b7709a
MD5 2ff73bf6ac9bd1bcc446f24932a51d14
BLAKE2b-256 f53255412fdf4480654ada614729da11e15fa8d590db06deda19dd2b720ec0fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for lockstepd-0.2.0b0-py3-none-any.whl:

Publisher: release.yml on dato-bitar/lockstepd

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

Release history Release notifications | RSS feed

This release

0.2.0b0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page