This release is a pre-release and may not be stable for production use.
lockstepd
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.
Metadata
Release files for lockstepd 0.2.0b0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lockstepd-0.2.0b0.tar.gz | 163.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lockstepd-0.2.0b0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 216.7 kB
Release files / lockstepd-0.2.0b0.tar.gz
| Download URL | lockstepd-0.2.0b0.tar.gz |
|---|---|
| Size | 163.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0f9cb9e3671c07bef3e62bdeb004e828d0cba6dd0c6776532caf2e58cbab82c7
|
|
BLAKE2b-256 checksum How to use checksums |
41d2f17930f4fd2110be72ed2782c7d0b333aec95b0e992a17f633efc0d53ac0
|
| 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 Aug 26, 2026.
Transparency logRelease files / lockstepd-0.2.0b0-py3-none-any.whl
| Download URL | lockstepd-0.2.0b0-py3-none-any.whl |
|---|---|
| Size | 53.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0cc72562ab81f841200495e85a9e306494c3d051f4f5c1354b46abe9a5b7709a
|
|
BLAKE2b-256 checksum How to use checksums |
f53255412fdf4480654ada614729da11e15fa8d590db06deda19dd2b720ec0fa
|
| 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 Aug 26, 2026.
Transparency log