Durable Execution

Purpose and Scope

Durable execution is Flue’s answer to a practical problem in autonomous work: useful agent operations can outlive a browser tab, HTTP response, server process, deployment, or worker instance. The concept page defines durability as safe recovery when running work is disrupted by restart, deployment, lost connection, or unexpected failure. It also makes an important distinction between continuing agents and finite workflows. This page focuses on the agent side of that model: persistent agent instances, their canonical conversation stream, durable submissions, leases, recovery decisions, and what application code must do to avoid duplicated external effects.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

A durable Flue agent is not just a stateless request handler around a model call. It is a continuing, stateful context with one canonical conversation stream per persistent agent instance. Sessions choose conversations from that stream, and later operations rebuild model context from the same durable records used by recovery and clients. That design means the transcript, model-visible history, tool outcomes, compaction records, topology, and recovery facts all share one source of truth instead of being split across a live response and an unrelated replay log.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

Relevant Source Files

  • apps/docs/src/content/docs/concepts/durable-execution.md — The first-party concept page for durable agents. It defines the durable execution problem, canonical conversation streams, persistence requirements, Cloudflare Durable Object behavior, Node.js persistence notes, and conservative recovery semantics for interrupted submissions.

Durable Agent Model

Direct prompts and asynchronous dispatch(...) inputs are documented as operations inside an agent instance, not workflow runs. That distinction matters when designing an application boundary. A prompt sent over HTTP and an input dispatched asynchronously both enter the same agent-owned continuity model, while application-owned ingress such as webhooks or chat messages belongs in routing before it becomes an agent operation. Once accepted, the input participates in the agent’s ordered state rather than being owned by the original caller connection.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

The concept page’s flow can be read as a contract: input is appended into the agent’s canonical stream, the operation completes, and a later input rebuilds context from those durable records to continue the conversation. In practice, the durable stream is the event history that both runtime recovery and clients reason from. It records model-visible messages, assistant output, tool calls and tool results, compaction, topology, and recovery facts. Attachment bytes are deliberately separated into an immutable attachment store and referenced from canonical records, so large or binary payloads do not become a mutable second transcript.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

agent input → canonical conversation stream → operation completes

later input → rebuilds context → continues the conversation

Persistence, Submissions, and Leases

Flue separates durable conversation state from operational coordination state. The canonical stream is the durable transcript and recovery record. Mutable submission claims and leases remain operational state rather than becoming a second conversation. A submission is the accepted unit of work being processed for an agent operation; a lease or claim is the runtime’s coordination mechanism for deciding who is currently processing that work. This separation helps keep future model context deterministic while still allowing the runtime to coordinate work safely during failures and restarts.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

For application-controlled persistence, the documentation instructs projects to create src/db.ts or .flue/db.ts and default-export a PersistenceAdapter. That adapter is the hook used by Node-target applications to persist durable records outside process memory. Without a database file, Node.js behavior is process-local, so durable recovery across process restarts depends on wiring an adapter. The concept page points readers to the Database guide for setup and the Data Persistence API for the storage contracts, which are the next references to use when selecting or implementing an adapter.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

Cloudflare Execution Flow

On Cloudflare, generated agents use one Durable Object per agent instance. Durable Object SQLite stores the canonical stream, attachment bytes, and accepted submissions. Direct HTTP prompts and asynchronous dispatch(...) inputs enter the same ordered queue, which means the platform binding enforces the same single-agent ordering model regardless of how work was submitted. The client that submits a prompt observes the work, but the accepted backend operation does not depend on the HTTP connection remaining open.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

direct HTTP prompt ─────────────────────┐
                                        ├→ durable queue → canonical stream
dispatch(...) input ────────────────────┘

This is the core event-streaming implication: the connection is a view onto durable work, not the owner of the work. If a response closes after Cloudflare accepts a prompt, processing can continue on the backend. Clients can later reconnect to the canonical agent stream from a durable offset. That offset-based model is what lets UIs, SDK clients, and long-running consumers resume observation without asking the model to start over simply because a network connection disappeared.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

Recovery Semantics

After interruption, Flue decides what to do next from the canonical conversation stream alone. Already-completed output is recognized as complete. Usable partial output can continue from durable deltas. Completed tool results are reused rather than repeated. A tool call that has no durable result is represented as interrupted with an unknown outcome instead of being run again automatically. If no output was durably persisted before the interruption, recovery may re-dispatch the provider once, which the documentation describes as consistent with at-least-once execution.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

The conservative rule is intentional because model and tool activity can cause external side effects. A tool call may have created a ticket, sent a message, charged a card, or updated a database before the runtime lost confirmation. Automatically replaying that tool call could duplicate the external effect. Flue therefore records the uncertainty in the conversation rather than pretending the call did not happen. Application tools that mutate outside systems should use application-owned idempotency keys when repeated effects would be harmful.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

When recovery cannot complete the work, the submission is terminalized and its conversation is settled to a deterministic rest state. The documented terminal cases include exhausting durability.maxAttempts, exceeding the processing timeout, or an abort settling a crash-interrupted submission. Tool calls without confirmed outcomes receive explicit interrupted-error results and are never re-executed as part of terminalization. Interrupted partial streams are completed as aborted, and a terminal advisory records the reason with interrupted calls as structured metadata, keeping the settled turn visible to future model context.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

System-to-Code Mapping

ConceptPublic behavior documented hereSource
Persistent agent instanceOwns one canonical conversation stream used by sessions, recovery, and clientsapps/docs/src/content/docs/concepts/durable-execution.md
Canonical conversation streamStores model-visible messages, assistant output, tool calls and results, compaction, topology, and recovery factsapps/docs/src/content/docs/concepts/durable-execution.md
AttachmentsStored separately as immutable bytes and referenced from canonical recordsapps/docs/src/content/docs/concepts/durable-execution.md
Submissions and leasesOperational coordination state, not a second transcriptapps/docs/src/content/docs/concepts/durable-execution.md
Cloudflare Durable ObjectOne Durable Object per agent instance; Durable Object SQLite stores stream, attachments, and accepted submissionsapps/docs/src/content/docs/concepts/durable-execution.md
ReconnectionClients reconnect to the canonical stream from a durable offsetapps/docs/src/content/docs/concepts/durable-execution.md
Interrupted tool callsUnknown outcomes are represented as interrupted rather than automatically replayedapps/docs/src/content/docs/concepts/durable-execution.md

Design Guidance and Next Steps

When building against this model, treat the canonical stream as the agent’s durable memory and the submitted connection as only one observer. Route provider webhooks or chat messages through Flue routing, then hand accepted work to an agent operation. Persist state with a PersistenceAdapter when running on Node.js and requiring recovery beyond process lifetime. For mutating tools, design idempotency at the application boundary because Flue deliberately avoids blind replay when an external effect might already have happened.

Sources: apps/docs/src/content/docs/concepts/durable-execution.md

Read the Database guide next if you need to wire src/db.ts or .flue/db.ts. Read the Data Persistence API when implementing or evaluating an adapter. Read the Cloudflare target documentation when deploying durable agents on Durable Objects, because platform configuration and migrations determine where the canonical stream, attachments, and accepted submissions live in production.