research/durable-agent-runtime/analysis.md
hermes 686d02755f durable-agent-runtime: add pi-durable deep dive + crash/replay experiments
- new pi-durable.md: architecture (session/entry/document/task/submission),
  effect-sandwich semantics, structured concurrency, storage backends,
  maturity/adoption, taxonomy placement, implications for hermes-vm
- empirical tests on @earendil-works/pi-durable 1.3.0 (Node 22.22.2):
  kill -9 mid-phase (memo vs plain), kill -9 mid-tool (safe vs unsafe),
  SQLite schema; noted cold-open waitForTask race and the main-vs-1.3.0
  version gap (sleepUntil/onWake/restartLimit/sleeping not published)
- taxonomy: durable harness library added as a new primitive family
- sources + next-steps updated
2026-10-20 13:20:24 +00:00

5.6 KiB

Analysis — Durable Agent Runtime

Part of durable-agent-runtime/index Harness/loop analysis moved to harness-engineering/index (2026-08-11).

The primitive families

Family Example Compute primitive Where state lives Cold start Hibernation
Durable objects celld (Deno) V8 isolate running Worker bundles Per-object SQLite, replicated to S3 Fast (isolate) Idle cells hibernate
Actors rivet Lightweight process (Node/Bun/Deno) In-memory + SQLite/BYO DB ~20ms Actors hibernate when idle
VM sandboxes hypeman, E2B Firecracker/Cloud Hypervisor/QEMU microVM VM disk (snapshot for standby) ~30s VM / sub-30ms from snapshot standby = snapshot to disk
Durable harness library pi-durable (2026) Node process or Cloudflare Durable Object Immutable transcript + documents + task checkpoints in SQLite/JSONL/DO storage Reopen + reconcile (ms) Task sleeps end the invocation; host alarm wakes (onWake on main, not in 1.3.0)
Collaborative substrate Radicle COBs Signed, CRDT-like Git commit DAGs Git objects (replicated, self-certifying) Instant (local git) Repos persist; nodes sync on demand

(Harness libraries — nanocodex, Codex, pi — moved to harness-engineering/index.)

The industry convergence: compute is disposable, state is durable elsewhere.

  • Amp orbs: ephemeral E2B sandbox + durable thread on Amp Server (PostgreSQL). Sandbox destroyed on archive; conversation survives.
  • celld: nodes are replaceable; the S3 bucket is the durable source of truth. Object = its own SQLite DB → sharding and blast-radius containment by construction, no consensus.
  • rivet: actor state in-memory for 0ms reads, persisted for durability; runs indefinitely, sleeps when idle.
  • hypeman: standby = snapshot VM to disk, restore in milliseconds — VM-level hibernation.

The two hard problems everyone solves

  1. Cold start latency — the gap between "VM ~30s" and "actor ~20ms" is closed with snapshots (E2B, hypeman standby, celld/rivet hibernation) or pre-provisioned pools. This is why orbs can feel local despite being remote.
  2. State checkpointing & recovery — thread JSONL (Amp), SQLite replication (celld), actor state persistence (rivet), VM disk snapshots (hypeman). Everything is replayable; nothing is lost on compute failure.

Where pi-durable fits (2026-10-20)

@earendil-works/pi-durable is not a new substrate; it is a durable harness library that runs on an existing one. It commits the loop's own state — immutable transcript entries, typed documents, per-phase task checkpoints, idempotent submissions — and resumes on reopen. The substrate can be a Node process with SQLite/JSONL or a Cloudflare Durable Object; tools execute through a pluggable ExecutionEnv, so a VM sandbox (hypeman/E2B) can sit underneath without the harness knowing.

Its semantics sharpen the "compute disposable, state durable" thesis: the harness process is disposable too, but phases are at-least-once, not exactly-once. External effects repeat on rerun unless memoized or idempotent; tools declare replay: "safe" to rerun, otherwise the model gets an interrupted result. Only submission admission is exactly-once (requestId). That is a useful, honest contract to compare against Temporal-style durable execution and against our own kanban/session design. Full write-up: durable-agent-runtime/pi-durable.

What this means for hermes-vm (our stack)

Already have (the "durable compute host" layer):

  • Persistent remote dev VM (hermes-vm), systemd services, kanban DB, session DBs, herdr panes, tailscale.
  • herdr = the "shared tmux + durable agent loop" half of an orb, already built.

Genuine gaps (the "environment contract" layer):

  • Per-repo .agents/setup-style bootstrap + AGENTS.md per repo — cheap, ~90% of the reliability win.
  • Idempotent dev-server script + ports metadata file + /__dev-style auth bypass for our apps.
  • Event-driven wake: Forgejo webhooks → kanban task (self-hosted equivalent of Amp's event-driven orbs).
  • Formalize tailscale serve as per-repo portals.

Not worth building on a single box:

  • A distributed durable-object layer (celld) or actor platform (rivet) — solves multi-node, multi-region, scale-to-zero billing problems we don't have. One VM = one durable host.
  • An E2B-style per-thread VM fleet — same reason. NixOS already gives cheaper isolation: nix develop, rootless podman (already enabled via modules/dev/containers.nix), worktrees, NixOS containers/systemd-nspawn if stronger isolation is ever needed.

Interesting but optional:

  • hypeman — if we ever want real per-task VM isolation with snapshot/standby on our own box, hypeman is the lean OSS option (multi-hypervisor, OCI images, ms restore). Watch it; don't adopt yet.

Verdict

Build the environment contracts (setup hooks, AGENTS.md, dev-server skills, event wake) on the existing durable host. Do not build the sandbox platform or a distributed state layer. herdr + systemd + kanban + tailscale already provide the durability; the missing piece is making the environment "assume an agent and tell it where the light switches are."

If we ever build a long-running, multi-client agent service (as opposed to cron-driven one-shot tasks), pi-durable is the closest reference implementation: one SQLite-backed Session per service, tools on NodeExecutionEnv, views for clients. For the Rust-core direction, treat its spec as the design input and reimplement only the commit/task/ownership semantics we actually need.