> Fetch the index of every Tonbo docs page as Markdown at https://tonbo.dev/llms.txt

# Concepts: Pi Durable

Last updated 29 October 2026

Read this before you run [Pi Durable](https://github.com/earendil-works/pi/blob/main/packages/durable/README.md) on Tonbo: it names what the Harness keeps, how another machine resumes it, and why one process runs it at a time.

Pi Durable on Tonbo is Pi’s own `SqliteStorage`, unmodified. The difference is that its SQLite file is a Tonbo database, so the conversation is not owned by the machine that runs it.

## How it differs from Pi’s own storage

|  | `MemoryStorage` | SQLite on this disk | A Tonbo database |
| --- | --- | --- | --- |
| A commit resolves | In memory | On this disk | Once two of three replicas, each in its own zone, hold it |
| The process dies | The conversation is gone | The next process on this machine resumes it | The next process on any machine resumes it |
| The machine is lost | The conversation is gone | The conversation is gone | The next process on any machine resumes it |

## The conversation

Pi Durable commits an agent’s conversation, its model turns and its tool calls, to its storage as it goes. On Tonbo that storage is one database, named when you open it, such as `harness-1`: give each Harness a database of its own (see [Concepts](https://tonbo.dev/docs/databases/concepts.md) for what a database is).

## A turn and when it is durable

Every Pi transaction resolves only once `synced()` did, so a turn the Harness has recorded is durable: Tonbo holds it, in two of three replicas in different zones. From Pi 1.2, a long outage makes a Harness call wait rather than reject; on Pi 1.0 and 1.1 it rejects with Pi’s `StorageRejected` (see [backlog_full](https://tonbo.dev/docs/reference/nodejs/pi.md#backlog-full)). A reset rejects it (see [Resets in a Harness](https://tonbo.dev/docs/reference/nodejs/pi.md#resets)).

## Resume

`harness.resume()` continues any run the last process left unfinished. A new process, on this machine or another, opens the database by name, the local copy rebuilds from Tonbo where its disk has none, and `resume()` continues the run. Record a tool call’s effect outside the process, such as an email, before making it, so a resumed run does not repeat it (see [Run side effects once](https://tonbo.dev/docs/databases/side-effects.md)).

## One writer

One process runs a Harness at a time: the last one to open its database. The one before it is refused from then on: its next Harness call rejects with `UrsulaResetError`, action `stop`, and it should stop and alert rather than open the database again, which would take it back from the new process. Run one instance per database (see [Rules: one writer](https://tonbo.dev/docs/databases/rules/one-writer.md)).

## How it reaches your program

`openUrsulaPiStorage("harness-1")` opens the database by name with your API key and hands Pi its `SqliteStorage`; `Harness.open()` runs on it as on any storage, and `harness.close()` closes it too (see [the Pi Durable quickstart](https://tonbo.dev/docs/getting-started/quickstarts/pi.md)).

```text
  MACHINE A                               MACHINE B, later
  +------------------------------+        +------------------------------+
  |  the Harness takes a turn    |        |  opens "harness-1" by name   |
  |  --commit--> the local copy  |        |  harness.resume(): the run   |
  |  it resolves once Tonbo      |        |  continues from every turn   |
  |  holds it                    |        |  A recorded                  |
  +--------------+---------------+        +--------------+---------------+
                 |                                       ^
                 v                                       |
  TONBO, in the database's region: two of three zones hold every turn

  A, if it still runs once B opens: its next call rejects with
  action stop, and A stops
```

A turn resolves only once two of three replicas, each in its own zone of the region, hold it, which is why a process on another machine that opens the same database by name and calls `harness.resume()` continues from every turn the Harness recorded (see [Guarantees](https://tonbo.dev/docs/databases/how-it-works.md)).
