BuildRiot
Sign in

Article

How to test OpenCode session recovery on Cloudflare Durable Objects

Cloudflare’s experimental OpenCodeHarness documents session recovery after eviction, but external tool effects need a separate test. This guide proposes an interruption after a remote commit, then checks stored state, resumed execution, and the destination’s ledger.

An illustration shows terminal windows and configuration files progressing through a session interruption, saved server state, resumed execution, and a destination ledger recording a commit.
Illustration: BuildRiot (AI-generated)

Key takeaway

A restored conversation does not prove that an interrupted tool completed safely. Developers need to distinguish submission deduplication from protection against repeated external changes before trusting an agent with consequential work.

Target the gap after an external commit

Cloudflare announced experimental OpenCodeHarness on October 12, 2026, embedding OpenCode 2.0 in a plain Durable Object. It requires Agents SDK 0.28.0 or later, @opencode/sdk@2, and @opencode/plugin@2. Cloudflare assigns the model loop, transcript, tools, and session recovery to OpenCode; Lifecycle supplies storage and durable jobs. To test recovery, consider an agent that creates a remote issue before its host disappears without receiving the receipt. The experiment must distinguish three outcomes: the conversation persisted, execution resumed, and the external action happened the intended number of times. Sources: Cloudflare

The research checked on October 14, 2026, supports a proposed experiment, not a verdict on exactly-once external effects. No eviction test was run, and the reviewed material supplies no confirmed force-eviction command. The fetched source entry point exports interfaces rather than exposing the recovery implementation or a test suite. OTF’s October 13, 2026, walkthrough provides guidance but no measured interruption trace or duplicate-effect count. Treat the procedure below as a test design whose reset mechanism must be established before execution. Sources: Cloudflare, OTF

Separate stored state from completed work

Cloudflare’s reference says sessions, messages, and durable events use the object’s SQLite database, with an opencode_ prefix on tables and indexes. Active sessions have heartbeat jobs, and an alarm wakes the object after eviction or a crash. An unused OpenCode host closes after 30 seconds without work or event subscriptions and reopens on demand. Keep that idle-host behavior separate from an interruption during an active tool call. The latter tests how execution handles unfinished or uncertain work. Sources: Cloudflare

Durable Object storage is private, transactional, and strongly consistent, according to Cloudflare; in-memory state can disappear during eviction or ordinary deployments. Those database properties do not by themselves coordinate a transaction with a remote issue service. OpenCode’s Workerd profile also replaces unavailable local filesystem and process services. Embedding the loop therefore does not establish that a desktop checkout or shell survives alongside it. The table below separates documented facilities from the observations needed to assess recovery. Sources: OpenCode, Cloudflare

Table

Documented recovery facilities and proposed checks

FacilityDocumented behaviorProposed check
SQLite persistenceStores sessions, messages, and durable eventsCompare records across interruption
Heartbeat jobsAn alarm wakes the object after eviction or a crashObserve activation before reconnecting
Submission identityoperationId deduplication is session-scopedResubmit the same operation
Durable replayOmits uncommitted live text deltasCompare durable cursor and transcript
Point-in-time recoveryRestores database contents within the previous 30 daysDistinguish database restoration from task continuation
Each facility addresses a different part of the proposed recovery test.Sources: Cloudflare

Build an observable tool and a controlled pause

Start in a disposable namespace and record the environment before introducing faults. Capture exact package versions, the lockfile, source commit, Wrangler version, compatibility date, and deployed Worker version. Include the model identifier and settings, plus the object, session, and operation identities. Keep those records with each trial’s evidence. This gives later comparisons a stable reference and helps distinguish a recovery problem from an environment change.

Use a separate test service with an append-only build ledger or mock issue-creation API. Give every logical action a key, record each request attempt, and count committed effects separately. After committing an entry, have the service signal the test controller and withhold its response. This creates a known acknowledgement gap; overwriting a file with identical contents could conceal repeated execution. Record evidence independently of shutdown hooks because OpenCode’s documentation says eviction can happen without cleanup. Sources: OpenCode

  1. Run an uninterrupted baseline and match the receipt to one committed ledger entry.
  2. Pause the service after its commit but before it returns the receipt.
  3. Interrupt the host using a verified runtime-reset facility and record the mechanism.
  4. Keep the client quiet for a predetermined interval while observing object activations externally.
  5. Reconnect to the original object and session, then reconcile the operation with the ledger.
  6. Repeat with destination-side uniqueness enforcement on the logical action key.

Observe recovery before reconnecting

Once a reset mechanism is established, label local runtime resets and controlled deployed restarts as separate conditions. Record the exact mechanism for every trial so the results identify what was interrupted. A client reconnect immediately afterward could supply activity that conceals a failed autonomous wake-up. Observe external telemetry first, then reconnect after the predetermined quiet interval. That ordering targets Cloudflare’s documented alarm-based recovery path. Sources: Cloudflare

Treat a client disconnect as a separate control, not proof that the execution host disappeared. Cloudflare distinguishes aborting a wait, which stops the wait, from aborting a session, which can interrupt work. OTF also recommends testing object restart and client disconnect separately and reconnecting to the same object. Run the proposed matrix below against the same observable tool and preserve traces for every trial. Include two successive interruptions to test whether recovery can make progress after another failure. Sources: Cloudflare, OTF

Table

Proposed interruption and control matrix

ConditionWhat to assess
No interruptionTool and observation setup
Before remote commitCompletion of unfinished work
After commit, before responseRepeated effects after an uncertain outcome
After durable tool-result recordingPreservation of completed progress
Client disconnect onlyTransport loss versus execution loss
Same operation submitted againSubmission deduplication
Two successive interruptionsRecovery after another interruption
These conditions define an experiment, not observed harness results.

Reconcile SQLite, durable events, and the ledger

Discover the deployed schema before assuming internal table names. The query below lists tables and indexes so inspection can follow the actual database structure. Use the results to identify session records, operation state, durable events, and job state. Capture snapshots before interruption and after recovery, alongside activation identifiers and deployment versions. Keep inspection outside the critical timing window where possible so observation does not disturb the intended pause.

SELECT type, name, tbl_name, sql
FROM sqlite_schema
WHERE type IN ('table', 'index')
ORDER BY type, name;

Cloudflare says messages() returns active context after compaction, while history() returns the full transcript. Durable replay uses session.log() and event.durable.seq, excluding uncommitted live text deltas. Record the last durable cursor before interruption, any durable tool result, and the final operation outcome. Cloudflare defines done as answered; unanswered covers failure, interruption, withdrawal, or absence. Plugin tools may appear under the execute wrapper, so account for that representation when examining events. Match these records to external receipts rather than accepting the assistant’s final message as proof of a committed action. Sources: Cloudflare

Count attempts and effects separately

Repeat the experiment with the destination atomically enforcing uniqueness on the logical action key and returning the original receipt for repeats. A repeated request with one committed effect differs from two committed mutations. Cloudflare’s operationId deduplicates submissions within a session and returns accepted: false on reuse. OTF recommends application-level task IDs and API deduplication, which can complement that submission control. Suppressing a retry without resolving its uncertain outcome could instead leave requested work incomplete. Sources: Cloudflare, OTF

For each condition, report trial counts, successful completions, unresolved operations, tool attempts, committed effects, missing transcript records, and additional model usage. Separate restart-to-first-progress from restart-to-completion, and publish raw traces and failures. Report three distinct outcomes: session restored, execution resumed, and effects counted. Keep reliability claims proportional to the sample. Before expanding deployment, examine which identifiers survive recovery, how interrupted tools are resolved, and what happens when retries are exhausted. Repeat critical cases across an SDK or schema upgrade to check recovery against changed state.

Attribution

Sources

  1. 1CloudflareRun OpenCode 2.0 on Cloudflare with the Agents SDKSource published (UTC)
  2. 2CloudflareOpenCode · Cloudflare Agents docs
  3. 3OpenCodeCloudflare | OpenCode
  4. 4CloudflareAccess Durable Objects Storage
  5. 5CloudflareOpenCode harness source entry point
  6. 6OTFHow to run OpenCode 2.0 on Cloudflare and recover after Durable Object evictionSource published (UTC)

Read the original source for full details and context.

Report a problem

Links, dates or what you expected. Do not include passwords or private data.

More on AI

All AI stories
EditorialSource: Firebase

Google adds QueryData preview to Firestore with MongoDB compatibility

Google announced QueryData support for Firestore with MongoDB compatibility on October 12, 2026. [1] Google says the feature lets developers build data agents that query database content through conversational language. [1] Its documentation says QueryData translates natural-language questions into MongoDB-compatible Query Language (MQL) queries, using developer-supplied context sets with database-specific information. [2] The feature is in preview, with potentially limited support. [2]

Published

EditorialSource: Oracle

Oracle adds managed MCP server support for OCI Database Services

Oracle added managed MCP server support for OCI Database Services on October 13, 2026, according to its release notes. The interface lets MCP-compatible AI agents and applications inspect database resources through read-only operations; it cannot modify those resources. It supports four services: Base Database Service, Exadata Database Service on Cloud@Customer, Exadata Database Service on Dedicated Infrastructure and Exadata Database Service on Exascale Infrastructure. Clients connect through generated endpoints using Streamable HTTP, while OCI IAM authenticates clients and enforces existing access policies. Customers can choose which resource categories to expose and enable or disable servers.

Published