Vercel releases durable-harness to resume coding agents after failures
Vercel releases an open-source harness that makes existing coding-agent setups resumable after failures. Adapters support Vercel or self-hosted infrastructure without tying execution to one runtime.

TL;DR
- Coding-agent sessions can recover after crashes: Vercel's durable-harness supports Pi, OpenCode, Codex and Claude Code, with logged results preserving completed work.
- Self-hosting is supported alongside Vercel, according to the launch post; the open-source package remains experimental.
- Claude Code and Codex require an extra sandbox because they were not designed for embedding, according to the launch discussion.
- Interrupted tools have their own recovery contract: badlogicgames emphasized mid-tool continuation, while Vercel's documentation specifies explicit replay policies.
An interrupted refund can return as an uncertain outcome, the sharpest detail in the replay contract. A virtual workspace offers a bash-compatible shell without network access or real node and python binaries. Even self-hosted Claude Code and Codex still execute inside Vercel Sandbox.
Turn logs and queue recovery
Vercel's October 19 announcement extends the durability infrastructure behind eve, fx and Workflow SDK to existing harnesses. Eve and fx already support durable execution; the new adapters add it around other harnesses without changing their internals.
Each turn uses a Workflow SDK backend called a World:
- The log records intents and outcomes for model calls and tool calls.
- A queue message backs the turn. If its function dies, the queue assigns recovery to another function.
- The replacement reads the log to distinguish completed, interrupted and unstarted work.
- Finished calls return their recorded results without executing again. Completed model calls therefore avoid a second token bill during recovery.
Claude Code transcripts, Codex rollouts and OpenCode event-store records are also mirrored into the log, allowing a replacement function or sandbox to reconstruct the harness's session state.
A browser disconnect leaves the agent running; reconnecting catches the client up from the log.
Tool replay policies
Continuing tools mid-execution was one requirement badlogicgames raised before launch. Interrupted calls follow two documented policies:
replay: 'safe': Pi runs the interrupted call again. Claude Code, Codex and OpenCode tell the model that repeating it is safe.replay: 'never': Every harness waits for the intent to be persisted before starting. After an interruption, the model is told the action may have happened, allowing it to check the external state. That invocation is not automatically executed twice.
Vercel uses order lookups and CI checks as replay-safe examples, and refunds and PR comments as examples that must not be blindly repeated.
Logging also has two modes:
durability: 'on': Replay-safe calls can start without waiting for their intent to reach the log. This is the default fordurable-harness/pi.durability: 'strict': Every call waits for the log. Claude Code, Codex and OpenCode default to this mode, though their factories also accept'on'.
The replay policy governs recovery of an invocation. An interrupted external side effect can still require a state check by the model.
Virtual files and Sandbox Drives
Agents get three workspace configurations, with different persistence and execution boundaries:
virtual(): Files live in the session log. Thejust-bashshell operates on a virtual filesystem isolated from the function's files, processes and environment. File changes commit with the tool result, so an interrupted call leaves no partial changes.virtual({ durable: false }): The same virtual tools use in-memory scratch files, cleared at the end of each turn.sandbox(): Tools run in a session-specific Vercel Sandbox, with/workspaceon a Drive that outlives functions and sandboxes. Interrupted commands can leave partial changes on that Drive.
The virtual workspace holds about 500 files. Each write adds a log event, and recovery reads the history back, making workspace size part of recovery cost.
Claude Code and Codex always run inside Vercel Sandbox, including when the controlling server is self-hosted. Their own tools are enabled with builtins: true; the tools operate on the session's Drive.
60-second queue handover
Pi's durable-harness/pi adapter and OpenCode initially drive a turn inside the chat request, then hand it to the queue route after up to 60 seconds. A command still running at that boundary is stopped and is not rerun, according to the workspace documentation.
An early dependency install, build or slow sandbox startup can hit that boundary. Vercel documents agent.chatRoute({ drive: 'queue', ... }) as the workaround: the queue route drives the whole turn using the plan's maximum duration.
The docs attribute this limitation to Vercel Queues and say a fix is forthcoming.
World backends and Postgres
Filesystem-dependent state was an early complaint about cloud harnesses. Backend portability comes from the Workflow SDK's World contract:
Vercel deployments use Vercel's World. Other environments default to a local World that stores files under .workflow-data, unless another backend is selected.
The documented Postgres setup requires Node.js 22 or later, @workflow/world-postgres 5.0.4 or later, and database bootstrapping. These variables select the backend:
On a custom server, getWorld() starts queue consumption and recovers sessions left mid-turn. Without startup initialization, recovery begins when the first request reaches an agent.
Self-hosting has several concrete boundaries:
- Long-lived worker: The Postgres World consumes its queue in a persistent process, so it cannot run inside Vercel Functions.
- Session ownership: Several servers can share a database, but only one drives a session at a time. A superseded worker's next write is rejected.
- App isolation: Startup recovery scans open sessions. Apps sharing a database can end up executing one another's sessions; a different job prefix does not isolate them.
- Security: The reference Postgres World does not authenticate its routes or encrypt its data, and the docs say it is not tuned for scale.
The environment-variable selection applies to durable-harness. Libfx selects its backend separately and takes an explicit world() adapter for another World.
Typed session documents
Plans, to-do lists and forms can live beside the conversation as typed JSON documents. Their persistence follows the session log:
- Definition:
defineDoc()gives a document a kind, schema version and initial value. - Tool updates: Edits through
io.docscommit together with the tool result. A throwing or interrupted call leaves the document unchanged. - App updates:
agent.sessions.doc()reads state;updateDoc()retries against a newer revision after a conflict. PassingexpectRevisionproduces aDocConflictinstead. - UI streaming: Chat routes can stream document values and revisions independently of assistant messages.
- Limits: Each document holds at most 64 KB of JSON. Schema changes use a version and migration function.
Documents are invisible to the model unless tools or prompt configuration expose them. Claude Code's and Codex's built-in tools do not see them.
The persistent virtual workspace uses this mechanism too: its file tree is a document, and file edits commit with tool results.
Agent Runs traces
Recovered turns remain in the same Agent Runs trace, preserving the interruption and continuation within one session view.
fx0 HTML artifacts
Vercel also open-sourced an HTML artifact builder running on libfx. Its fx0 project page describes the implementation:
- Each requested page becomes a single HTML file.
- A Vercel Function streams model and tool steps to the browser, while the chat persists as a libfx session in a Workflow World.
- Agent instructions live in
lib/agent.ts; tools live inlib/tools.ts.
The demo originally included Vercel Sandbox, which its author removed for simplicity.
The libfx HTML artifact builder generating an interactive dashboard.