Pi Durable
Pi includes pi-durable, an experimental agent harness that saves every step of a conversation before it shows it. PiSharp ports it as a set of .NET libraries and as an interactive mode, pisharp durable.
What durable means
Section titled “What durable means”- Every model turn, streamed partial answer, tool call and queued message is committed to storage before it appears.
- If the process dies mid-turn, reopening the session finishes that turn. The turn still ends with exactly one answer, and queued messages are not duplicated.
- A tool that was interrupted after it started is not run again unless it is declared replay-safe. The model gets an “interrupted” result instead. A replay-safe tool runs again exactly once.
- Subagents run as child conversations owned by the task that called them. A child outlives the call, so you can switch to it and keep talking.
PiSharp’s tests check these guarantees by killing a real process at checkpoints in every phase of a turn, then reopening its storage the way pisharp durable --continue does.
Try pisharp durable
Section titled “Try pisharp durable”pisharp durable is part of the PiSharp CLI from 1.2.0.1. Install or update the tool, then run it in a project folder:
dotnet tool install -g PiSharp.Cli # or: dotnet tool update -g PiSharp.Clipisharp durable # start a new durable sessionpisharp durable --continue # reopen the newest durable session for this folderpisharp durable takes one option. --continue (or -c) reopens the newest session for the current folder, and without it each run starts a new session. Any other argument fails with Unknown argument. The command is listed in pisharp --help as experimental and prints a one-line experimental notice when it starts.
It reads the same settings, credentials and models as pisharp, so providers you have signed in to work here too. The model gets the read, write, edit and bash tools, with images from read, and a subagent tool.
In a session
Section titled “In a session”| Input | What it does |
|---|---|
| A message | Sends it. While the agent is working, it steers the current turn. |
| The follow-up key | Queues the message until the agent finishes. |
/model |
Picks the model. |
/tasks |
Shows or hides running tasks. |
/agents |
Switches between the main conversation and its subagents. |
/compact [instructions] |
Compacts the conversation. |
| Escape | Aborts the turn. |
| Ctrl+D | Exits. |
Your key bindings apply, including the keys for the model selector and the thinking level.
Where sessions are stored
Section titled “Where sessions are stored”Each session is one SQLite database:
~/.pi/agent/experimental/durable-sessions/<folder hash>/<timestamp>-<id>/session.sqliteA session is locked while it is open, so two processes cannot write to it at once. If the lock is lost while the session is open (its lock directory removed, or taken over by another process), the session fails at once: nothing more is saved, the TUI says the lock was lost, and pisharp durable exits with 1. These sessions are separate from ordinary PiSharp sessions: pisharp --resume does not list them, and pisharp durable does not open ordinary sessions.
The layout and the lock are those of Pi v1.1.0’s experimental durable agent, so each finds the other’s newest session with --continue and respects the other’s lock. Pi v1.1.0 cannot resume the records PiSharp’s v1.2.0 library writes, though, so don’t continue a PiSharp session with it.
How it differs from Pi
Section titled “How it differs from Pi”- The command is PiSharp’s. Pi v1.1.0 ran its durable agent from source, not from the
picommand, and Pi v1.2.0 removed that agent. PiSharp keeps it as a PiSharp-only mode, ported from Pi v1.1.0’s agent. - The libraries follow
pi-durablev1.2.0. The storage format (SQLite schema, JSONL layout and record JSON) is upstream’s. Tests open, resume and rewrite sessions that upstream wrote, and upstream reads PiSharp’s. - Code mode scripts don’t move between Pi and PiSharp. Durable code mode records its engine’s fingerprint, and PiSharp runs scripts on Jint where Pi uses QuickJS, so neither resumes a script the other interrupted. The resume is refused rather than diverging.
- A lost lock fails the session. Pi’s agent ends its process when its session lock is lost; PiSharp fails the session instead, so the TUI can say why before it exits with 1. Either way nothing more is saved.
- Images use SkiaSharp. Upstream resizes images with Photon compiled to WebAssembly. PiSharp applies the same rules through the image codec its main
readtool uses. - No Cloudflare adapters. The Cloudflare Durable Object storage and image processor are not ported.
Libraries
Section titled “Libraries”Three NuGet packages, versioned with the rest of PiSharp:
| Package | Contents |
|---|---|
PiSharp.Durable |
The harness, sessions, conversations, tasks, and in-memory and JSONL storage |
PiSharp.Durable.Sqlite |
SQLite storage, through Microsoft.Data.Sqlite and SQLitePCLRaw’s e_sqlite3 native library |
PiSharp.Durable.Tools |
The local execution environment, the coding tools, tool_search and durable code mode |
Every public type is marked [Experimental("PISHARP_DURABLE001")], so the compiler reports an error until you opt in by suppressing that diagnostic:
<PropertyGroup> <NoWarn>$(NoWarn);PISHARP_DURABLE001</NoWarn></PropertyGroup><ItemGroup> <PackageReference Include="PiSharp.Durable" Version="1.2.0.1" /> <PackageReference Include="PiSharp.Durable.Sqlite" Version="1.2.0.1" /> <PackageReference Include="PiSharp.Durable.Tools" Version="1.2.0.1" /></ItemGroup>PiSharp.Durable.Sqlite brings the e_sqlite3 build for each platform, and the packages carry their license notices under licenses/. samples/Durable.Chat is a small chat app that runs on a real model, and samples/Durable.Examples ports upstream’s examples.
Known issues
Section titled “Known issues”- JSONL storage keeps the records it wrote in memory, so a long session on JSONL grows (about 400 MiB where Node holds 1 MiB in one benchmark). SQLite storage, which
pisharp durableuses, does not. See durable-benchmarks.md. pisharp durable’s edit cards differ slightly from interactive mode’s.
Status
Section titled “Status”Decision 0005 records the scope, the differences from Pi, the port status and the decision to release it as experimental. durable-port-map.json maps every upstream file to its C# counterpart. The 1.2.0.1 release notes cover what shipped. Upstream’s pi-durable README and specification describe the design.
Feedback is welcome in GitHub issues.