agent boundaries

why

live interaction and durable execution fail in opposite ways: agent state dies with the connection; a workflow's whole value is surviving crashes and waits. blending them makes each fragile — durable progress lost when a socket closes, or a realtime surface blocked behind process machinery. interaction to the agent, run-to-completion to the workflow: each boundary keeps the guarantees it is good at, with typed events crossing between.

rule

an agent is the realtime identity and interaction boundary. a workflow is the durable run-to-completion boundary. use both only when the product needs both direct interaction and durable multi-step orchestration.

agent owns

  • connections, streamed or websocket updates, messages, direct user input.
  • starting a workflow with a typed small payload.
  • sending typed approval, cancellation, or correction events to an existing workflow instance.
  • rendering or broadcasting already-persisted progress.

workflow owns

  • durable process state, retries, long waits, final status.
  • calling a typed Agent capability only when live interaction is necessary.
  • persisting the fact before announcing it to the Agent or its clients.

choose the boundary by survival requirement

requirementownerreason
live stream, presence, ephemeral selectionagent/UIexists only while a client interaction is active
user message starting/correcting durable workagent boundary then workflowagent validates the interaction; workflow owns the lasting process
retry, delay, approval wait, continuationworkflowmust survive disconnect, restart, redeploy
durable progress/status/historypersistent storeboth agent and workflow reload the same authority
immediate visual freshnessagent broadcast or query invalidationprojection after the durable write, not the write itself

decision process

shortcutfailuredirection
process state only in agent memoryreconnects/restarts lose authoritypersist canonical state; agent re-reads and broadcasts it
long operation inline in a message handlerdisconnect and request lifetime become part of business successstart a typed durable workflow with a stable reference
workflow trusts a live agent payload as currentpayload may be repeated, delayed, staleworkflow reloads the durable fact before transition
broadcasts as an event logdelivery is not guaranteed or exactly oncewrite durable record/event first; publish freshness second

good and bad

bad

onMessage = async (message) => {
this.setState({ status: "running" });
await runLongProcess(message.payload); // minutes of durable work inline
};

the durable process lives only in agent memory and the request lifetime: a disconnect loses the authority, a reconnect cannot recover the status. minutes of provider work hang on one socket — a flaky connection, redeploy, or client refresh kills or orphans the process with no way to see or resume progress; the user's only recourse is to start over and risk a duplicate effect.

good

onMessage = async (message) => {
const instance = await this.env.workflow.start(
"processWorkflow",
{ id: message.runId },
{ runId: message.runId },
);
this.broadcast({ runId: message.runId, status: "started" });
};

the agent validates the interaction, starts a typed durable workflow, and broadcasts a projection of persisted truth it can reload on reconnect. the interaction surface can crash, disconnect, or redeploy freely without touching process success; the workflow survives waits and retries the connection cannot. typed events keep the two synchronized without sharing fragile state.

verification

disconnect during an active process, restart the agent/runtime, reconnect: the interface must reload the same durable status and the workflow continue or stop on persisted facts alone. repeat a message or broadcast — it must not create a second semantic transition.

placement

Cloudflare Agent entrypoint in ~agents/, workflow entrypoint in ~workflows/: the prefix describes framework ownership, not business logic. domain service, schema, mapper, and provider adapter live under their technical-role/domain paths; the entrypoint stays a thin composition layer.

do not

  • let a websocket disconnect decide whether a durable process succeeds.
  • put the only workflow status in ephemeral Agent state.
  • use a direct Agent RPC or broadcast as a durable handoff; those calls may be repeated when the workflow retries.
  • use an agent loop as a substitute for a durable workflow when the process has distinct retry, approval, or continuation boundaries.

search pages

go to any page