{"article":{"slug":"pi-durable","title":"Pi Durable","subtitle":null,"summary":"Earendil's experimental Pi Durable harness brings Pi's minimalism to long-running agents: crash-safe tasks, multi-conversation concurrency, pluggable extensions, compaction, durable documents, and multiplayer steering on JS runtimes.","content_type":"blog_post","language":"en","canonical_url":"https://earendil.com/posts/pi-durable/","author":{"name":"Earendil Engineering","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Earendil","url":"https://earendil.com/","listing_slug":null,"listing":null},"topics":[{"name":"AI Agents","slug":"ai-agents","url":"https://listedarticles.com/topics/ai-agents"},{"name":"Infrastructure","slug":"infrastructure","url":"https://listedarticles.com/topics/infrastructure"},{"name":"Open Source","slug":"open-source","url":"https://listedarticles.com/topics/open-source"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Software Engineering","slug":"software-engineering","url":"https://listedarticles.com/topics/software-engineering"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1053,"reading_minutes":5,"published_at":"2026-10-01T00:00:00.000Z","added_at":"2026-10-01T21:13:10.427Z","updated_at":"2026-10-01T21:13:10.427Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":false},"profile_url":"https://listedarticles.com/articles/pi-durable","markdown_url":"https://listedarticles.com/articles/pi-durable.md","example":false,"citation":"Earendil Engineering, Earendil. \"Pi Durable.\" 1 Oct 2026. https://earendil.com/posts/pi-durable/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://earendil.com/posts/pi-durable/"},"body_markdown":"# Pi Durable\n\nToday Earendil and the Pi community shipped Pi 1.0. This reflects our belief that after countless hours of hardening, maintenance, and active development, Pi is now a solid foundation on which to build. Pi also continues to evolve. Together with Pi 1.0, we are shipping an experimental new package called Pi Durable. Pi Durable was built specifically for long-running, durable, and malleable agents that can run anywhere.\n\n## Why Pi Durable?\n\nPi the coding agent is built to run on your (remote) machine, inside a terminal, driven by one person. If the process dies, you look at what happened and tell it to continue. That is what Pi 1.0 focuses on and excels at, and that is not changing.\n\nAt Earendil, we want to bring this technology to everyone, in whatever form fits their needs best. For that, we need a harness that runs anywhere, can be reached from different surfaces, supports infinitely long conversations, survives catastrophic internal and external failures, and lets multiple humans steer the same agents.\n\nPi Durable is that harness. It does not replace the Pi coding agent. It is a framework for building any agentic application, coding agents included. It shares not only code with the Pi coding agent, like pi-ai, but also its principles: minimalism and malleability.\n\n## What is a harness?\n\nA harness is storage plus the machinery needed to run one or more conversations with large language models in parallel. It provides the tools those models call, and the execution environments the tools run in.\n\nA conversation is an interaction between you and an agent, recorded as a transcript. The agent is the large language model together with its settings, like the thinking level, and the tools it can call. Tools do their work through an execution environment, which can be your laptop, a remote VM, or an in-memory sandbox. Everything the harness runs, from calling the model to executing a tool, is a task.\n\nLike everything in Pi, Pi Durable is built so your agent can understand it. The entire source code, without tests, is about 15,000 lines.\n\n## Long runs anywhere\n\nWe want agents to run for a long time and to be able to run anywhere, where anywhere currently means anywhere there is a JavaScript runtime.\n\nIn Pi Durable, a harness opens over a storage backend. Pi Durable ships memory, SQLite, and JSONL storage, plus a conformance suite and benchmarks for your own backend. The SQLite and JSONL storage code uses no Node APIs, so with a small adapter it runs on Bun or inside a Cloudflare Durable Object. One process owns a storage at a time, and other clients attach to that process.\n\nOn SQLite, the harness only keeps the working set in memory: the active transcripts, live tasks, and pending submissions. Everything else stays on disk until it is needed. Active transcripts are naturally bounded by the model's context window, because compaction summarizes older messages before they overflow it.\n\n## Survives crashes\n\nIn Pi Durable, every step of a run is a task that stores a checkpoint before it moves on. If the process dies, a new process opens the same storage, finds the unfinished tasks, and continues each one from its last checkpoint. A model request that was cut off is sent again; the partial answer stays in the transcript, marked as aborted. A tool call that was cut off reruns if it is safe to; otherwise the model is told it was interrupted. A `requestId` makes a submission exactly-once.\n\n## Many conversations at once\n\nOne harness runs as many conversations as you need, concurrently, all with the same guarantees. A conversation starts fresh or forks another one at any point in its transcript, and sees the parent's history up to that point without copying it. Each conversation also stores its own agent: the model, the thinking level, the selected extensions and which of their tools are active, extra instructions, and the working directory in its execution environment.\n\n## Extensions\n\nAn extension is a named bundle of system prompt sections, tools, hooks, and tasks. The application installs extensions in a registry. Each conversation selects which extensions and tools it uses, and stores only their names.\n\n- **System prompt sections** are rebuilt from the conversation's extensions before every request, so a changed section is picked up by the next request. Pi Durable records what changed in the transcript.\n- **Tools** run as durable tasks; after a crash a tool reruns only if it says that is safe. Tools can create subagent conversations that survive crashes and count their own cost.\n- **Hooks** let extensions step into tasks (model response, tool invoke, compaction), rewrite requests, block tool calls, or keep a run going. Decisions can be stored in a memo so a restart does not re-ask.\n- **Tasks** get checkpoints, timers that survive restarts, and ownership trees so aborting a task aborts what it owns bottom-up. Background tasks can outlive the current turn.\n\n## Compaction\n\nCompaction is a task like any other, and it runs while the conversation keeps going. When the context gets close to the model's limit, a background compaction summarizes the older messages, and the summary is placed at the next turn boundary. The older messages always stay in storage. `reset()` can start a new context from a handoff note while keeping history searchable.\n\n## Durable application state\n\nApplication state lives in documents: typed JSON stored next to the transcript and changed in the same atomic commits, so the state never disagrees with the transcript that produced it. Each document says what a fork starts with: the parent's value at the fork point, its current value, or a fresh one.\n\n## Malleable and multiplayer\n\nThe registry can change while conversations run. Installing an extension under a name that is already installed replaces it in one step. Conversations store extension and tool names, never code, so after a restart they pick up whatever the new process installs.\n\nEverything a UI needs is committed state, so any number of clients can attach to any conversation, join late, reconnect, and steer a running conversation or queue a follow-up.\n\n## Try it\n\nPi Durable is experimental, and the API might still change. Point your agent at `packages/durable` in a Pi checkout, or install:\n\n```bash\nnpm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord\n```\n\nFull detail, code samples, and demos are in the [original post](https://earendil.com/posts/pi-durable/).\n","body_html":"<h1 id=\"pi-durable\">Pi Durable</h1>\n<p>Today Earendil and the Pi community shipped Pi 1.0. This reflects our belief that after countless hours of hardening, maintenance, and active development, Pi is now a solid foundation on which to build. Pi also continues to evolve. Together with Pi 1.0, we are shipping an experimental new package called Pi Durable. Pi Durable was built specifically for long-running, durable, and malleable agents that can run anywhere.</p>\n<h2 id=\"why-pi-durable\">Why Pi Durable?</h2>\n<p>Pi the coding agent is built to run on your (remote) machine, inside a terminal, driven by one person. If the process dies, you look at what happened and tell it to continue. That is what Pi 1.0 focuses on and excels at, and that is not changing.</p>\n<p>At Earendil, we want to bring this technology to everyone, in whatever form fits their needs best. For that, we need a harness that runs anywhere, can be reached from different surfaces, supports infinitely long conversations, survives catastrophic internal and external failures, and lets multiple humans steer the same agents.</p>\n<p>Pi Durable is that harness. It does not replace the Pi coding agent. It is a framework for building any agentic application, coding agents included. It shares not only code with the Pi coding agent, like pi-ai, but also its principles: minimalism and malleability.</p>\n<h2 id=\"what-is-a-harness\">What is a harness?</h2>\n<p>A harness is storage plus the machinery needed to run one or more conversations with large language models in parallel. It provides the tools those models call, and the execution environments the tools run in.</p>\n<p>A conversation is an interaction between you and an agent, recorded as a transcript. The agent is the large language model together with its settings, like the thinking level, and the tools it can call. Tools do their work through an execution environment, which can be your laptop, a remote VM, or an in-memory sandbox. Everything the harness runs, from calling the model to executing a tool, is a task.</p>\n<p>Like everything in Pi, Pi Durable is built so your agent can understand it. The entire source code, without tests, is about 15,000 lines.</p>\n<h2 id=\"long-runs-anywhere\">Long runs anywhere</h2>\n<p>We want agents to run for a long time and to be able to run anywhere, where anywhere currently means anywhere there is a JavaScript runtime.</p>\n<p>In Pi Durable, a harness opens over a storage backend. Pi Durable ships memory, SQLite, and JSONL storage, plus a conformance suite and benchmarks for your own backend. The SQLite and JSONL storage code uses no Node APIs, so with a small adapter it runs on Bun or inside a Cloudflare Durable Object. One process owns a storage at a time, and other clients attach to that process.</p>\n<p>On SQLite, the harness only keeps the working set in memory: the active transcripts, live tasks, and pending submissions. Everything else stays on disk until it is needed. Active transcripts are naturally bounded by the model&#39;s context window, because compaction summarizes older messages before they overflow it.</p>\n<h2 id=\"survives-crashes\">Survives crashes</h2>\n<p>In Pi Durable, every step of a run is a task that stores a checkpoint before it moves on. If the process dies, a new process opens the same storage, finds the unfinished tasks, and continues each one from its last checkpoint. A model request that was cut off is sent again; the partial answer stays in the transcript, marked as aborted. A tool call that was cut off reruns if it is safe to; otherwise the model is told it was interrupted. A <code>requestId</code> makes a submission exactly-once.</p>\n<h2 id=\"many-conversations-at-once\">Many conversations at once</h2>\n<p>One harness runs as many conversations as you need, concurrently, all with the same guarantees. A conversation starts fresh or forks another one at any point in its transcript, and sees the parent&#39;s history up to that point without copying it. Each conversation also stores its own agent: the model, the thinking level, the selected extensions and which of their tools are active, extra instructions, and the working directory in its execution environment.</p>\n<h2 id=\"extensions\">Extensions</h2>\n<p>An extension is a named bundle of system prompt sections, tools, hooks, and tasks. The application installs extensions in a registry. Each conversation selects which extensions and tools it uses, and stores only their names.</p>\n<ul><li><strong>System prompt sections</strong> are rebuilt from the conversation&#39;s extensions before every request, so a changed section is picked up by the next request. Pi Durable records what changed in the transcript.</li><li><strong>Tools</strong> run as durable tasks; after a crash a tool reruns only if it says that is safe. Tools can create subagent conversations that survive crashes and count their own cost.</li><li><strong>Hooks</strong> let extensions step into tasks (model response, tool invoke, compaction), rewrite requests, block tool calls, or keep a run going. Decisions can be stored in a memo so a restart does not re-ask.</li><li><strong>Tasks</strong> get checkpoints, timers that survive restarts, and ownership trees so aborting a task aborts what it owns bottom-up. Background tasks can outlive the current turn.</li></ul>\n<h2 id=\"compaction\">Compaction</h2>\n<p>Compaction is a task like any other, and it runs while the conversation keeps going. When the context gets close to the model&#39;s limit, a background compaction summarizes the older messages, and the summary is placed at the next turn boundary. The older messages always stay in storage. <code>reset()</code> can start a new context from a handoff note while keeping history searchable.</p>\n<h2 id=\"durable-application-state\">Durable application state</h2>\n<p>Application state lives in documents: typed JSON stored next to the transcript and changed in the same atomic commits, so the state never disagrees with the transcript that produced it. Each document says what a fork starts with: the parent&#39;s value at the fork point, its current value, or a fresh one.</p>\n<h2 id=\"malleable-and-multiplayer\">Malleable and multiplayer</h2>\n<p>The registry can change while conversations run. Installing an extension under a name that is already installed replaces it in one step. Conversations store extension and tool names, never code, so after a restart they pick up whatever the new process installs.</p>\n<p>Everything a UI needs is committed state, so any number of clients can attach to any conversation, join late, reconnect, and steer a running conversation or queue a follow-up.</p>\n<h2 id=\"try-it\">Try it</h2>\n<p>Pi Durable is experimental, and the API might still change. Point your agent at <code>packages/durable</code> in a Pi checkout, or install:</p>\n<pre><code class=\"language-bash\">npm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord</code></pre>\n<p>Full detail, code samples, and demos are in the <a href=\"https://earendil.com/posts/pi-durable/\" rel=\"nofollow ugc noopener\">original post</a>.</p>","headings":[{"level":1,"text":"Pi Durable","id":"pi-durable"},{"level":2,"text":"Why Pi Durable?","id":"why-pi-durable"},{"level":2,"text":"What is a harness?","id":"what-is-a-harness"},{"level":2,"text":"Long runs anywhere","id":"long-runs-anywhere"},{"level":2,"text":"Survives crashes","id":"survives-crashes"},{"level":2,"text":"Many conversations at once","id":"many-conversations-at-once"},{"level":2,"text":"Extensions","id":"extensions"},{"level":2,"text":"Compaction","id":"compaction"},{"level":2,"text":"Durable application state","id":"durable-application-state"},{"level":2,"text":"Malleable and multiplayer","id":"malleable-and-multiplayer"},{"level":2,"text":"Try it","id":"try-it"}]}}