Skip to content

nelsonwerd/wake

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

107 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wake

Every fleet leaves a wake — and the wake is written by the runtime the agents run in, not bolted on beside them.

wake runs your unmodified agent fleet — Claude Code, Codex, a scripted worker, a bare binary — inside a corruption-evident, crash-durable event log. The record of what the agents did is produced by the runtime they execute in, not attached next to them as a hook a stray bash command can step around. One Go binary, local-first. The black box and the autopilot are the same box.

That containment is the whole point, and it is the one thing the two nearest categories structurally lack:

  • Evidence recorders (audit-log tools that hash-chain what an agent did) capture at a tool-boundary hook or an SDK callback — beside the agent, not around it. The hash-chained recorder Halo says so itself: "neither the chain nor the witness proves that every real-world action passed through the recorder."
  • Durable-execution engines (resume/replay/fork) run the agent inside their own SDK or framework and keep a history for recovery, not a corruption-evident chain for audit.

wake sits in the gap: the log is simultaneously the execution substrate, the crash-resume spine, the coordination bus, and the corruption-evident audit record — for agents it does not make you rewrite.

Why containment, not a hook

The gap a bolt-on recorder leaves is not hypothetical. Anthropic's own Claude Code checkpointing docs state it plainly:

Checkpointing does not track files modified by bash commands. … These file modifications cannot be undone through rewind. Only direct file edits made through Claude's file editing tools are tracked.

code.claude.com/docs/en/checkpointing

A tool-use hook sees the tools; a subprocess that shells out to rm, mv, or a migration script slips underneath it. And when an agent's own account of what it did is unreliable, an agent-independent record is the only ground truth — see the Replit agent that deleted a production database during a code freeze and then misreported the damage.

Those incidents motivate a category — an operator-independent record of what an agent actually did to a system. They are not evidence that anyone needs wake specifically; wake has no users or traction to cite, and this README claims none (see Honest bounds).

The mechanics underneath

The felt value above rests on four ordinary, machine-checkable properties. They are supporting mechanics, not the reason wake exists — several are table stakes in the durable-execution world (see What wake is NOT):

  • Crash-durable. kill -9 a live fleet mid-flight and wake resume finishes it. For deterministic fleets it resumes to a final state whose reduced state hash matches an uninterrupted run (delivery-cursor bookkeeping excluded — the state hash, not the raw bytes; a deterministic-fleet claim, see Guarantees).
  • Replayable. Re-reduce any historical run by pure reduction — replay executes nothing, ever. (This is the standard recorded-effect contract, not a wake invention.)
  • Forkable. Branch an alternate timeline from any event (O(1) parent-pointer).
  • Corruption-evident. A single flipped byte in any event, or in any payload the reduction reads, breaks wake verify. (Truncating the log yields a different hash — detectable only against a hash you remembered elsewhere. Two recorded surfaces sit outside wake verify: CAS blobs the reduction never consumes are re-hashed only when read, and the non-hashed emit-id sidecar sits outside every check, consumed unverified by resume dedupe. Guarantees states the exact scope.)

We say corruption-evident, never tamper-evident: a bare hash chain detects change relative to a head you remember, but wake ships no signing or external anchoring and does not defend a store an adversary controls.

The agents are subprocesses speaking a small NDJSON protocol over stdio — not a framework you rewrite your code into.

What wake is NOT

wake is a substrate for heterogeneous local subprocess fleets — a Claude Code adapter here, a Codex adapter there, a scripted worker, a bare binary. It is deliberately not a general workflow engine, and it makes honest concessions:

  • If your whole system is one graph, use LangGraph. Its checkpointing, time-travel, and forking are first-class.
  • If you have a platform team and a server budget, use Temporal. Mature durable execution with a GA OpenAI Agents SDK integration.
  • wake targets the single operator running local fleets who will never deploy a cluster, and adds what those structurally lack for agent runs: a corruption-evident chain, recorded-effect (not live re-execution) replay, and event-granularity forking of unmodified subprocess agents. See prior art for the honest landscape.

Where wake sits

The durable-execution primitives — resume, replay, fork — are commoditizing from every direction, and that is fine: they are wake's supporting mechanics, not its identity. As of late 2025 / 2026 they ship in AWS Lambda Durable Functions (GA Dec 2025), LangGraph, Temporal, DBOS, Restate/Resonate, and even Claude Code itself (checkpoints, /rewind, and --fork-session — though that flag forks the conversation, not filesystem or effect state).

What no shipped system composes — verified across that field as of July 2026 — is the intersection. Stated defensively:

No shipped system offers even two of {harness-agnostic subprocess protocol, corruption-evident hash chain, witnessed effect ledger} together with fork/replay — wake proposes all three, locally, in one binary.

That is a positioning fact ("nobody else ships this"), not a demand claim ("people are asking for this"). See prior art for the element-by-element credit (ActiveGraph, OpenHands, Halo, LangGraph, Temporal, DBOS, and more).

Quickstart

Requires Go 1.26+. Build from source with the commands below (a tagged release for go install github.com/nelsonwerd/wake/cmd/wake@latest follows the first publish). This runs a 3-agent fan-in fleet of deterministic test agents (labeled as such — no external API is involved), crashes it, and resumes it to an identical reduced state hash (delivery-cursor bookkeeping excluded — see Guarantees).

# 1. Build the binary and a bundled deterministic test agent.
go build -o ./bin/wake     ./cmd/wake
go build -o ./bin/scripted ./agents/scripted

# 2. Declare a fleet (deterministic scheduler → reproducible).
cat > demo.json <<'JSON'
{
  "run": "demo",
  "scheduler": "deterministic",
  "agents": [
    {"name": "w1",        "argv": ["./bin/scripted", "fanin", "w1"]},
    {"name": "w2",        "argv": ["./bin/scripted", "fanin", "w2"]},
    {"name": "collector", "argv": ["./bin/scripted", "fanin", "collector"]}
  ]
}
JSON

# 3. Run it, then inspect the causal log.
./bin/wake run    demo.json     # → COMPLETED <run-id>
./bin/wake status demo.wake.d   # fleet at a glance
./bin/wake verify demo.wake.d   # chain proof + reduced state hash
./bin/wake log    demo.wake.d   # the event stream
./bin/wake replay demo.wake.d --verify   # executor-free reconstruction

# 4. Crash a run mid-flight, then resume it. The armed run is MEANT to die with
#    a nonzero exit (SIGKILL) — that is the point; don't wrap this step in `set -e`.
WAKE_CRASH_AT=supervisor.spawn-pre-welcome:2 ./bin/wake run demo.json --dir ./k
./bin/wake resume ./k/demo.wake.d   # → COMPLETED
./bin/wake verify ./k/demo.wake.d   # same state hash as the uninterrupted run

# 5. Fork an alternate timeline from the ORIGINAL run, or open the viewer.
./bin/wake fork demo.wake.d@6 --effects=ask   # forks ./demo.wake.d (step 3), not ./k
./bin/wake view demo.wake.d         # localhost, read-only, self-contained

The full command reference is in docs/manual/cli.md; the fleet-spec format in docs/manual/fleet-spec.md.

Guarantees (summary)

wake makes three machine-checkable claims, each exercised by crash-injection sweeps you can re-run yourself (scripts/phase2-sweep.sh, demo/selftest.sh) — no receipt artifact ships; the evidence is that the sweeps pass when you run them. In one breath:

  1. Replay determinism — a fresh process re-reduces the events-only log to the committed golden state hash; flipping any byte of any event breaks verification, and truncating the log yields a different hash (detectable only against a hash you remembered elsewhere); replay invokes zero effects.
  2. Crash-resume with externally witnessed effect accounting — for every crash site in a census-derived sweep, wake resume reaches the same terminal state, and a separate witness process confirms applied-exactly-once at an external witness for brokered effects.
  3. Resume equivalence for deterministic fleets — under the deterministic test scheduler, a crash-resumed run's state hash equals the uninterrupted run's.

These are exact, and their limits are stated exactly — including the power-loss caveat, the per-tier (brokered / gated / observed) scope, and one clause-3 boundary that was characterized and then closed at the root. Read the full, verbatim wording in docs/manual/guarantees.md; each clause is exercised by the test suite and the crash-sweep scripts, not asserted by prose.

Status

Experimental. The correctness spine is exercised by crash-injection sweeps you can re-run yourself (scripts/phase2-sweep.sh, demo/selftest.sh); the surfaces are a first draft.

  • First real-model live run — durability held across a double crash. A 4-agent Claude Opus 4.8 fleet (each subprocess pinned via -model claude-opus-4-8, bypass permissions, free scheduler) ran through wake building one page of wake's own one-pager. Protocol: run → SIGKILL mid-flight → resume → crash again post-reap → clean resume. Result: COMPLETED, 59 events, wake verify CHAIN_OK (state hash 992cefd4…), all 4 artifacts delivered, 0 orphaned processes. This exercises the durability spine and the corruption-evident chain end-to-end under a real model — the mechanics, not just the test doubles.

  • Broad live validation is still light — do not over-read one run. It is a single scenario. Under bypass permissions there were 0 gate events, so the human-approval / gated tier was not exercised live and remains a pending design item (it fails safe, but does not yet converge on a real CLI). Real-model runs are checked for invariant preservation, not hash-equality (a real model is nondeterministic). No brokered witness, no token metering, and power loss stay out of scope. The case-study harness script also has an open intermittent-timeout issue — the byte-identical manual protocol reproduces reliably; the wrapper needs a follow-up.

  • Two new Claude-adapter flags (added while closing the live run):

    • -model <id> — pins the model (passed through as claude --model <id>; empty = claude's configured default).
    • -workdir <dir> — sets the claude subprocess's working directory (cmd.Dir), sandboxing the agent's cwd to the fleet sandbox instead of the launch dir.

    Operational note from the live run: long prompts under high concurrency can push a deliberate model past the per-turn deadline — prefer short, direct prompts and a generous -response-timeout-ms.

  • The Codex adapter's live-model test is still PENDING HUMAN — no real Codex model has driven it. The adapters keep a three-tier honesty firewall: a labeled protocol test double (agents/fakeclaude, agents/fakecodex) — never a faked API; a credential-free real-binary leg (the real claude driven headless against a localhost mock model; the real codex binary's own generated transport schema plus a network-denied handshake); and the live-model leg. The Claude live-model leg is now exercised (above); the Codex one is not. See docs/ADAPTER_CLAUDE.md and docs/ADAPTER_CODEX.md.

  • Tested on macOS/arm64 (application-crash kill -9, not power loss — see the durability caveat in the guarantees). Linux now compiles (GOOS=linux go build ./... / go vet pass) with a /proc-based process-start identity for the orphan-fence pid-reuse guard, unit-tested against fixtures — but Linux runtime behavior (the crash sweeps, the reaper against live processes) has never been executed and remains a named follow-up.

  • CI (.github/workflows/ci.yml) runs these same machine gates — vet, build, the full test suite, docs lint, the phase-2 sweep, the demo selftest — on a macOS runner for every push; Linux stays cross-build-only there. A green CI run covers exactly those machine gates, not the live-model legs.

  • One clause-3 boundary was characterized, then closed at the root (final recorded delivery cursors are cross-agent delivery-order bookkeeping a mid-flight kill legitimately shifts; they are now excluded from the hashed state through the reviewed schema golden, pinned by red-first falsifiers plus the fleet-coupled and kill-topologies sweeps). See docs/manual/guarantees.md.

  • Design taste (CLI/viewer/docs) is self-graded and awaits a human sign-off.

  • Licensed Apache-2.0; module path is github.com/nelsonwerd/wake.

Honest bounds

  • "No shipped system composes wake's intersection" is a positioning fact, not validated demand. It means nobody else ships this, which is not the same as people asking for it. wake has no users, traction, or design-partner signal, and none is implied here.
  • The Replit incident and record-keeping obligations for high-risk AI systems (which vendors increasingly read as a pull toward cryptographically verifiable audit logs) motivate a category; they do not validate wake.
  • The durability spine and the corruption-evident chain are live-exercised (once, under a real model, across a double crash). The surfaces are a first draft, and the human-approval flow is a known non-converging design item — this README does not advertise either as proven.

Documentation

Doc What
manual/index.md Reference-manual table of contents
manual/concepts.md Log, reducer, effects, tiers, classes, epochs, cursors
manual/cli.md Every command, flag, and exit code
manual/fleet-spec.md The declarative fleet spec
manual/effects.md Effect model: tiers, P/E/R/X classes, in-doubt dispatch
manual/time-travel.md replay, fork, diff
manual/guarantees.md The three-clause guarantee, verbatim, with every caveat
manual/format-versioning.md Read-compatibility policy
manual/security.md One-operator posture, secrets warning, viewer hardening
PROTOCOL.md The wire protocol (conformance)
ADAPTER_CLAUDE.md The Claude Code adapter (-model / -workdir; live-model leg now exercised)
ADAPTER_CODEX.md The OpenAI Codex CLI adapter (live-model test human-gated)
PRIOR_ART.md Prior art and the honest wedge

License

Apache-2.0. The permissive grant plus an explicit patent license keeps wake free for anyone to use and build on; as sole copyright holder the author retains every right to relicense or build a commercial derivative. Dependencies are permissive (MIT / BSD / Apache-2.0, with one MPL-2.0 transitive) — no copyleft reaches the distributed binary.

About

Run unmodified agent fleets (Claude Code, Codex, any subprocess) inside a corruption-evident, crash-durable event log — one local Go binary. kill -9 and resume, replay without re-executing effects, fork any timeline.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors