Beyond the Ephemeral Loop: The Architecture of Durable AI Agents Earendil released @earendil-works/pi-durable at v1.1.0 on October 7, 2026, an experimental runtime that replaces the in-memory while-loop pattern of AI agents with an embedded SQLite storage engine and an operating system task scheduler. The package holds about 22,500 lines of TypeScript in src/, 72 test files, and a 263 KB design spec, and joins durable-execution offerings from Temporal, Restate, DBOS, Inngest, Cloudflare Workflows, and LangGraph checkpointers shipped across 2025 and 2026. Pi-Durable traces its lineage to Mario Zechner's @earendil-works/pi-coding-agent 1.0 terminal CLI, which relied on a human operator to restart crashed processes. On this page Beyond the Ephemeral Loop: The Architecture of Durable AI Agents AI agents built on while loops lose state when processes crash. Durable agents require an embedded database and an operating system task scheduler. Developers build AI agents as a while loop around an LLM client. You send a prompt, execute the requested tool, append the result to an in-memory array, and repeat. When a container restarts, a process crashes, or a network drops during a 45-second tool call, you lose the session. The user receives a severed socket. The database retains orphaned records. Recovery requires starting over. Earendil https://earendil.com paired the release of Pi 1.0 https://earendil.com/posts/pi-1-0/ with an experimental runtime: @earendil-works/pi-durable https://github.com/earendil-works/pi/tree/main/packages/durable . At v1.1.0 https://github.com/earendil-works/pi/blob/main/packages/durable/CHANGELOG.md released October 7, 2026 , the package holds about 22,500 lines of TypeScript in src/ , 72 test files, and a 263 KB design spec. Pi-Durable replaces the memory loop with an embedded storage engine and an operating system task scheduler. It is not alone. In 2025 and 2026, nearly every agent platform shipped some form of durable execution: Temporal https://temporal.io , Restate https://restate.dev , DBOS https://docs.dbos.dev/architecture , Inngest https://www.inngest.com/docs/durable-execution/durable-agents , Cloudflare Workflows https://developers.cloudflare.com/workflows/ , and LangGraph checkpointers https://docs.langchain.com/oss/python/langgraph/persistence . The defaults still bite. LangGraph’s InMemorySaver keeps every checkpoint in RAM, so a redeploy wipes them all. Most teams find out in production. What makes Pi-Durable worth studying is where it puts the durability: inside the process, next to the agent, in one SQLite file. 1. From Terminal Loop to Durable Engine: The Evolution of Pi The architecture of Pi-Durable reflects a concrete journey documented across two releases. Pi originated as an interactive terminal CLI. Created by Mario Zechner https://mariozechner.at at Earendil https://earendil.com , @earendil-works/pi-coding-agent https://github.com/earendil-works/pi/tree/main/packages/coding-agent version 1.0 started as an antidote to bloated developer environments. As detailed in Pi Agent: The Minimal Harness That Became My Multi-Tool Glue https://kondasamy.com/blog/2026/pi-agent-multi-tool-workflow/ , the design embraced radical subtraction: no native subagents, no plan mode, no permission prompts, and a prompt under 1,000 tokens. That original runtime ran inside a terminal interface powered by @earendil-works/pi-tui https://github.com/earendil-works/pi/tree/main/packages/tui with four built-in tools read , write , edit , bash , appending messages to a JSONL session tree https://jsonlines.org/ . If the process died, a human operator restarted the command-line interface and re-prompted the model. The operator acted as the crash recovery system. @earendil-works/pi-durable https://github.com/earendil-works/pi/tree/main/packages/durable addresses autonomous server workloads. When an agent runs background triage, executes multi-step deployments, or supports team channels, you cannot rely on a human watching the terminal to restart broken processes. This transition did not discard Pi’s minimalist foundation. As shown in Harness Engineering: Stop Blaming the Model, Fix the Environment https://kondasamy.com/blog/2026/harness-engineering-reliable-ai-agents/ , reliable agent behavior requires engineering the operating context rather than expanding prompts. Pi-Durable moved that boundary into an embedded runtime. 2. The Single Mutation Line: Storage Precedes Visibility Standard agents publish before they persist. An agent streams text over a WebSocket: “I cancelled your subscription and credited your balance.” The process runs out of memory before executing the backing Stripe call. The customer reads the promise, but the transaction never occurred, and the in-memory transcript disappeared. Pi-Durable prevents this race condition through a single mutation line . In Pi-Durable, state changes pass through atomic storage commits: - Transcript entries pi.user , pi.assistant , pi.tool-result - Task state transitions pending , running , waiting , terminal - Document mutations tracked as Chord https://github.com/earendil-works/pi/tree/main/packages/chord JSON deltas - Queued inputs in the conversation inbox The harness commits state to disk before streaming tokens to users. If any storage call throws, the Session fails and closes itself: every later call and every pending wait rejects with SessionFailed . Nothing retries. A half-written session is worse than a stopped one. Cloudflare reached the same rule from the other side. A Durable Object’s output gate https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/ holds every outgoing message and response until the storage writes before it are confirmed. If the write fails, the message never leaves. Pi-Durable applies that rule to tokens, tool output, and UI state. js import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node"; import { Harness } from "@earendil-works/pi-durable"; // Open the session over SQLite WAL const harness = await Harness.open await openNodeSqliteStorage "./agent.sqlite" , { models, registry }, context ; const root = await harness.root context ; // Submitting work returns a durable submission handle const submission = await root.submit { type: "input", content: "Refactor auth middleware to use JWT", requestId: "job-1042" // Exactly-once deduplication key }, context ; // If the worker crashes here, the next process reopens storage and resumes const settled = await submission.wait context ; Anchoring user output in a storage commit removes network race conditions. A client reconnecting after a socket drop resumes from the committed database state. What “Committed” Means on Each Backend “Committed” is only as strong as the storage under it. Pi-Durable ships four backends, and they make different promises: | Backend | Import | Survives process crash | Survives power loss | |---|---|---|---| | Memory | MemoryStorage | No | No | | SQLite | storage/sqlite/node | Yes | Newest commit may be lost | | JSONL | storage/jsonl/node | Yes | Yes, with { fsync: true } | | Durable Object | storage/sqlite/cloudflare | Yes | Yes Cloudflare replicates writes | The SQLite backend runs in WAL mode https://www.sqlite.org/wal.html with synchronous = NORMAL . That is a deliberate trade. In WAL mode, a commit appends pages to a log file instead of rewriting the database, so readers never block the writer. With NORMAL , SQLite skips the fsync on each commit and syncs only at WAL checkpoints by default, every 1,000 pages . A kill -9 loses nothing. A pulled power cord can lose the last commit. For a coding agent on a laptop, that is the right call. For a payment agent, pick JSONL with fsync: true or a Durable Object. Cloudflare introduced SQLite-backed Durable Objects https://blog.cloudflare.com/sqlite-in-durable-objects/ in September 2024 and made them generally available in April 2025, with up to 10 GB per object and 30 days of point-in-time recovery. One Durable Object per conversation gives every agent its own database and its own single writer. One more constraint: one process owns a storage at a time. There is no cross-process locking. Point two workers at the same SQLite file and nothing stops both schedulers from running the same tasks. 3. Document State: Bases, AST Splice Deltas, and Fork Pruning Agent state cannot live in freeform transcript prose alone. Complex workflows demand structured data: task lists, review diffs, active files, and billing ledgers. Pi-Durable uses Chord https://github.com/earendil-works/pi/tree/main/packages/chord to store typed JSON documents next to transcripts. Writing full JSON snapshots on every turn exhausts disk space, while storing raw diffs slows down read queries over time. The storage engine balances this trade-off by alternating between bases and operational deltas. Storage writes changes as two record types: - Bases: Full JSON copies written at creation, during migrations, or when checkpointWhen returns true. - Deltas: Compact Chord operations Op , such as array splices "p", "items" , 1, 0, "fix build" and value replacements “s”, “text” , “Done.” . The engine provides two history modes: 1. history: "latest" : Storage deletes older deltas when a new base commits. Used by pi.live and pi.inbox to bound disk usage. 2. history: "rewindable" : Storage preserves historical bases and deltas. snapshotAsOf entryId calculates document values as of past commit points. js import { defineDoc } from "@earendil-works/pi-durable"; interface TodoState { items: string ; } const TodosDoc = defineDoc