Agent harness engineering | October 25, 2026

Pi 1.0 is stable. Your agent's recovery path is not.

Pi 1.0 keeps the interactive coding harness small. Pi Durable adds committed execution state and restart recovery in a separate experimental package. That split is the useful design lesson: durability is a contract for state, effects, replay, and operators - not a checkbox attached to saved chat history.

Pi 1.0Pi Durable experimentalReplay safetyCrash injectionSources checked Oct 25

A durable agent is a recovery protocol, not a longer memory

An interactive coding agent can recover from a lost process by reopening a transcript and asking the model to continue. That is useful, but it is not enough for an agent that sends messages, changes tickets, charges cards, deploys services, or coordinates work over hours. After a crash, the important question is not “What did the model say?” It is “Which intent, state transition, and external effect crossed a durable boundary?”

Pi's October release makes this distinction unusually visible. Earendil calls Pi 1.0 a hardened, minimal, extensible harness and lists codemode, native MCP support, deferred tool loading, cache warming, virtual models, and transcript-aware prompt and tool changes. Long-running work lives in a separate package, Pi Durable, which the documentation labels experimental. The stable CLI and the durable substrate share principles, but they do not offer the same compatibility promise.

The practical rule is simple: adopt Pi 1.0 because the interactive harness fits your workflow. Adopt Pi Durable only after you can define recovery semantics for every effectful tool. A database that remembers an unfinished task cannot decide whether retrying “send invoice” will create a duplicate. The application owns that decision.

The release is popular enough to copy and young enough to punish assumptions

The Pi repository showed roughly 117,628 GitHub stars and 373 open issues when checked on October 25. The October 1 launch reached 1,689 points and 610 comments on Hacker News. These numbers demonstrate attention, not reliability, but they make architectural misunderstandings consequential: developers will build extensions and services against whichever boundary they think “Pi” represents.

The community has already located the confusing seam. A focused Reddit discussion about Pi Durable drew 136 points and 56 comments; the highest-rated reaction said the description was complicated enough to require an AI explanation. Another commenter offered the clearest operational distinction: base Pi preserves sessions and tool history, while Pi Durable also tracks execution state so unfinished work can resume after restart. That is the difference this article makes testable.

Recent research reinforces the need to test the whole runtime. An October preprint evaluated 66 model-harness configurations and found that model rankings changed across harnesses and tasks. In one reported result, GPT scored higher under Pi than under another harness on Terminal-Bench 4 at less than a quarter of the cost per task. The useful conclusion is not “Pi wins.” It is that model, harness, and workload form one system and must be evaluated together.

Treat Pi 1.0 and Pi Durable as two product surfaces

DecisionPi 1.0 coding harnessPi Durable
Primary jobInteractive terminal agent and malleable coding harness.Substrate for long-running, restartable agent applications.
Release posture1.x stable release line with documented features and fixes.Experimental; API may change without notice.
State modelConversation, tool history, extensions, model and UI state.Immutable entries, typed documents, atomic commits, durable tasks and checkpoints.
Restart promiseResume a user-driven coding session.Reopen storage and schedule unfinished task phases.
Tool riskUser supervises most effects in the terminal loop.Host must declare replay behavior and reconcile external effects.
Choose it whenA developer wants a small agent they can inspect and extend.A service must survive eviction, crash, sleep, handoff, or delayed work.
Do not assume“Stable” means every extension remains source-compatible.Persisted state produces exactly-once business actions.

This separation protects both designs. Stuffing durable orchestration into the interactive CLI would expand the trusted surface and change the mental model for every user. Treating the durable package as a transparent storage adapter would hide the application work required for idempotency, migrations, operator controls, and failure policy.

Build the recovery path around one committed line of truth

Pi Durable documents one atomic commit line: either a transaction stores all of its entries, documents, and task changes, or none of them. Conversations are immutable-entry transcripts. Documents hold typed state. Tasks are state machines that checkpoint at each step. A submitted input is durably admitted before generation begins, and a repeated request ID returns the existing submission instead of creating another.

client request + requestId
          │
          ▼
 durable admission ───── duplicate request lookup
          │                         │
          ▼                         └── return existing submission
 atomic commit: intent + task + state
          │
          ▼
 tool phase ──► external system ──► effect receipt
     │                 │                  │
     │ crash           └── idempotency key / read-back
     ▼                                    │
 reopen storage ─► inspect checkpoint ────┘
          │
          ├── replay safe tool
          ├── return interrupted result
          ├── park crash loop
          └── require operator reconciliation

“Nothing is shown before its commit is stored” is valuable because UI output cannot outrun the authoritative record. It is not a universal distributed transaction. The storage commit and a third-party API call still occupy different systems. A crash can occur after a provider accepted the action but before the harness recorded the response. The recovery contract must cover that gap.

Persisted sleeps and host wakeups are part of the same contract. The documentation separates a waiting phase from the later delivery phase because work after a wait must not run in the pre-wait phase on replay. On an evictable host such as a Durable Object, the host arms alarms and calls resume(); a missing wakeup can strand correct state forever.

Classify tools by effects before setting replay to safe

Pi Durable commits a tool's intent before execute(). If the process dies during the call, a tool marked replay: "safe" can run again. A tool without that declaration returns an interrupted result rather than silently repeating. That default is the right pressure: the developer must prove replay safety instead of assuming it.

Tool classExampleRecovery ruleRequired evidence
Pure/read-onlyRead a file, query a versioned dataset.Replay if the input and source version are recorded.Arguments, source identity, version, result hash.
Idempotent writeUpsert by stable business key.Replay with the same idempotency key.Key, provider receipt, read-back of final state.
Reversible writeCreate a draft ticket.Reconcile first; replay only if absent.Search predicate, created ID, rollback command.
Irreversible effectSend email, release payment, publish artifact.Do not blind-replay; query provider or require human recovery.Provider event ID, delivery state, approval, disposition.
Non-deterministic compositeCodemode script calling several tools.Journal nested results and require identical call path on replay.Sandbox fingerprint, script version, call keys, nested receipts.

Nested calls need the same discipline. Pi Durable can reconnect a replayed caller to prior nested calls by position or explicit key. Its documentation still warns that a replay-safe caller with external effects needs its own idempotency. A deterministic script is not the same as a transaction across the services it invokes.

Make recovery policy visible in code

The following skeleton is intentionally stricter than a demo. It uses persistent storage, a client request ID, a stable external idempotency key, an explicit replay declaration, and a provider read-back. Adapt names to the current experimental API and pin the exact package versions tested by your team.

const chargeInvoice = defineTool({
  name: "charge_invoice",
  description: "Charge one approved invoice exactly once",
  parameters: InvoiceCharge,
  replay: "safe", // safe only because the provider key is stable
  async execute({ invoiceId, approvedAmount }, api) {
    const effectKey = `invoice:${invoiceId}:v1`;

    const existing = await payments.findByIdempotencyKey(effectKey);
    if (existing) return receipt(existing, "reconciled");

    const created = await payments.charge({
      invoiceId,
      amount: approvedAmount,
      idempotencyKey: effectKey
    });

    const verified = await payments.get(created.id);
    return receipt(verified, "created");
  }
});

const submission = await conversation.submit({
  type: "input",
  content: approvedInstruction,
  requestId: `case:${caseId}:release:v3`
}, context);

The comment is part of the control: replay is safe because of a property outside the harness. If the payment provider ignores idempotency keys, the declaration becomes false. Store the provider's key and receipt in the case record, not only in model-facing text. Give operators a reconciliation action that can query the provider without issuing another charge.

Codemode deserves its own acceptance tests. The durable implementation journals each nested result before handing it back to the sandbox, then reruns the script deterministically after restart. It aborts recovery if the script takes a different path, the sandbox fingerprint changes, the codemode version changes, or the deadline passes. Pin those inputs and treat upgrades as migrations.

Upgrade the package boundary, not just the version number

Pi 1.0 removed experimental harness exports from @earendil-works/pi-agent-core. GitHub issue 10360 shows the concrete outcome: a subagent extension imported the former ./node path and failed after upgrade. The resolution was not to restore the old surface; the extension needed to import the durable package.

  1. Inventory imports. Search extensions for pi-agent-core/node, harness/*, storage, session, compaction, prompt, telemetry, and experimental subpaths.
  2. Classify the product surface. Keep ordinary loop integrations on agent core. Move long-running sessions and task state to Pi Durable deliberately.
  3. Pin and compile. Pin Pi, Pi Durable, extensions, codemode, and storage adapter versions. Compile the whole extension graph before rollout.
  4. Migrate stored state. Test a copy of real storage. Treat missing or unmigratable task definitions as visible blocked work, never as an empty queue.
  5. Replay production-shaped tasks. Include queued input, an in-flight nested tool, compaction, a provider retry, a sleeping task, and an extension reload.
  6. Keep rollback honest. A package downgrade is not safe if the new process already wrote state the old code cannot read. Test both code rollback and data compatibility.

Version 1.4.0 release notes illustrate why this must be continuous. Codemode worker admission, model configuration, summaries, classifiers, and provider behavior continued to change after 1.0. Stable numbering narrows the promise; it does not freeze every dependent integration.

Crash the system at every effect boundary

A happy-path restart test proves very little. Add deterministic failpoints around the storage commit and external effect, then assert business outcomes rather than internal callbacks.

for (const failpoint of [
  "before_intent_commit",
  "after_intent_commit",
  "before_provider_call",
  "after_provider_accept_before_receipt",
  "after_receipt_commit",
  "before_final_answer_commit"
]) {
  startHarness({ failpoint });
  submitSameRequestId();
  await processCrash();

  restartHarness();
  await resumeOrPark();

  assert(acceptedRequests === 1);
  assert(externalIrreversibleEffects <= 1);
  assert(evidenceExplainsDisposition());
}
Acceptance testPass condition
Duplicate client retrySame request ID returns the original submission and does not enqueue new work.
Crash after provider acceptanceRecovery reconciles by external key or parks for review; it never blind-replays.
Replay-safe nested callSame key reattaches to the existing call and returns its committed result.
Changed script or sandboxRecovery stops with an explicit incompatibility error instead of choosing a new path.
Deterministic crash loopTask parks at the configured restart limit and appears in operator inspection.
Missing extensionTask remains blocked with a reason until compatible code is installed or a human aborts it.
Host eviction during sleepStored wake time re-arms correctly; work resumes once and not early.
Read-only observerOpening a view cannot recover, mutate, or schedule tasks.

Measure recovery time, parked-task count, duplicate-prevention hits, unreconciled effects, stale-definition blocks, and operator interventions. Do not reduce readiness to benchmark task success. The second October preprint is useful here: its central premise is that runtime semantics are part of the policy an agent must follow. Your acceptance suite should make those semantics observable.

Design the failure modes before the first background task

FailureWhy it mattersControl
Transcript-only recoveryThe model sees history but the host cannot prove which effect occurred.Commit task state and external receipts separately from prose.
Replay-safe by optimismA retry duplicates an email, ticket, deployment, or payment.Require idempotency proof or interrupt-and-reconcile behavior.
Torn application stateTranscript, document, and task checkpoint disagree.Update related durable records in one atomic commit.
Silent migration driftPending tasks resume under incompatible code or schemas.Version task definitions, sandbox fingerprints, tools, and migrations.
Crash loopAutomatic recovery burns cost and keeps failing at the same instruction.Restart limit, parked state, breaker, retry/abort controls.
Worker saturationParallel codemode or subagent calls fail or starve unrelated work.Bound concurrency, queue admission, deadlines, and backpressure metrics.
Provider ambiguityA resumed task chooses a different provider or model behavior.Persist exact provider/model choice; fail on unresolved ambiguity.
Missing wakeupCorrectly stored work never runs again.Arm host alarms before runnable work and keep a recovery heartbeat.

Run a bounded durability pilot

  1. Choose one workflow with a valuable long wait but no irreversible effect for the first week.
  2. Pin the exact Pi, Pi Durable, codemode, extension, storage, provider, and model versions.
  3. Define stable request IDs and tool-effect keys before accepting work.
  4. Classify every tool as read-only, idempotent, reversible, irreversible, or composite.
  5. Store intent, checkpoint, external receipt, and human disposition as separate evidence.
  6. Add failpoints on both sides of every storage commit and external call.
  7. Prove crash-loop parking, blocked-definition visibility, read-only observation, and wakeup recovery.
  8. Observe cost and correctness for a week before introducing write tools.
  9. Add one reversible write with read-back reconciliation; test duplicates under load.
  10. Require an operator gate before any irreversible tool can enter the durable graph.

The exit criterion is not “the demo resumed.” It is an evidence packet showing that every accepted request reached one explainable disposition, every external effect was unique or reconciled, every incompatible task stopped visibly, and an operator could recover without asking the model to guess what happened.

FAQ

Is Pi Durable part of the stable Pi 1.0 contract?

No. Earendil shipped it alongside Pi 1.0, but its documentation explicitly labels it experimental and warns that the API changes without notice.

Does persisted chat history make an agent durable?

No. It helps reconstruct context. Durable execution also needs admitted requests, task checkpoints, atomic state changes, safe effect recovery, wakeup scheduling, migration behavior, and operator evidence.

Can Pi Durable guarantee exactly-once external actions?

Not for arbitrary tools. Use provider idempotency keys where available. Otherwise reconcile external state before retrying or require a human decision. “Exactly once” is an end-to-end property, not a storage setting.

When should a normal Pi user adopt the durable package?

When work must survive process loss without a user manually reconstructing it: long waits, scheduled tasks, multi-step services, or background workflows. An interactive coding session that a developer supervises may not need the extra state machine and migration burden.

What should a production pilot prove?

Crash the process before and after each commit and effect. Prove no duplicate irreversible action, no lost accepted request, deterministic resume or safe parking, visible incompatibility, bounded restart loops, and a complete recovery record.

Sources and verification notes

Sources were checked October 25, 2026. Product behavior is grounded in Earendil and repository documentation; community metrics are attention signals; research papers are preprints. X and YouTube were unavailable in the unattended last30days environment, and Google Trends/Autocomplete requests timed out, so no demand claim is made.

  1. Earendil - Pi 1.0 announcement, October 1, 2026.
  2. Earendil Works - Pi repository, MIT license and live project metadata.
  3. Pi Durable documentation, experimental API, commits, tasks, replay, recovery, and storage.
  4. Pi release notes, versions 1.0.0 through 1.4.0.
  5. Cloudflare - Run the Pi Durable harness on the Agents SDK, October 2, 2026.
  6. GitHub issue 10360 - Pi 1.0 removed harness subpaths break a subagent extension.
  7. Finding the Right Fit: Model-Harness Interactions across Agent Tasks, preprint submitted October 1, 2026.
  8. Harness Policy Distillation: Aligning Agent Policies with Runtime Semantics, preprint submitted October 14, 2026.
  9. Hacker News discussion - Pi 1.0.
  10. r/PiCodingAgent - Pi Durable architecture discussion, October 19, 2026.

Related guides: Infinity continuation contracts, persistent agent session authority, execution receipts, progressive tool discovery, and coding-agent model routing evaluation.