Skip to Content
DevelopDurable Stream Forks

Forking Durable Streams

A Durable Streams fork is an agent fork at an exact stream prefix. Golem copies the source agent oplog through the cut, appends a fork boundary, and continues as an independently addressable agent. The source is unchanged.

Shared prefix offsets remain valid on both branches. Reads from -1 return the shared prefix followed by that branch’s continuation in one JSON array or byte sequence. New source writes never wake or appear on the fork, and fork writes never appear on the source.

What the fork inherits

The target inherits agent state and stream history through the selected cut, stream schemas and content types, and—unless creation headers override it—the source session’s expiry policy. The selected stream’s terminal is reset at the cut, so a closed input can reopen unless fork initialization closes it again; other slots retain their cut-time state. Open output code continues on the forked agent, and open input slots receive writable fork URLs.

The target does not inherit the source’s live attachment, external HTTP producer deduplication table, post-cut tombstones, or post-cut items. Its producer table starts fresh, so the same producer tuple can be accepted independently on source and fork. Long-poll and SSE readers attach to one branch only.

External Durable Streams consumed by agent code are different: copied agent state retains the same remote URL and reader checkpoint, and copied writers retain the same producer identity and pending request. That does not fork the external service. See External Durable Streams.

Create and navigate a fork

Given this source stream:

/echo/invocations/order-7/streams/input

the fork target is:

/echo/forks/retry-a/invocations/order-7/streams/input

Read the desired prefix

Read the source and retain the opaque Stream-Next-Offset returned immediately after the prefix you want to share.

curl -i \ 'https://api.example.com/echo/invocations/order-7/streams/input?offset=-1'

Create the fork

Stream-Forked-From is the same-server path of the corresponding source slot. Stream-Fork-Offset is optional; omitting it selects the current head. The optional initial body and Stream-Closed apply only to writable slots.

curl -i -X PUT \ https://api.example.com/echo/forks/retry-a/invocations/order-7/streams/input \ -H 'Stream-Forked-From: /echo/invocations/order-7/streams/input' \ -H 'Stream-Fork-Offset: 000000000000000000000000000000000000000000000000' \ -H 'Content-Type: application/json' \ --data '["fork-only"]'

A new fork returns 201 and Location; an exact retry of a still-live target returns 200 from its immutable creation receipt, even if the source has since advanced, expired, or been deleted. A retry that changes the source, cut, initial content, terminal, or expiry policy returns 409. An expired fork target returns 404 and cannot be recreated under the same fork ID.

Continue each branch

Append to the source and fork URLs independently, then read each from -1. Both contain the selected prefix; each contains only its own later items.

Inspect provenance

GET /echo/forks/retry-a/invocations/order-7 returns a manifest with every slot and a fork object containing sourcePath, forkOffset, and subOffset. Fork provenance is intentionally not repeated as response headers.

The example offset is only a shape placeholder—always use the exact offset returned by the source.

Selecting the root agent

An explicit mount selector chooses the root agent before Durable Streams resolves sessions and named forks. Suppose instance is an optional query selector and the selected phantom UUID is dc7f9909-2975-42b3-9635-2f5ba7c73782:

curl -i -X PUT \ 'https://api.example.com/echo/forks/retry-a/invocations/order-7/streams/input?instance=dc7f9909-2975-42b3-9635-2f5ba7c73782' \ -H 'Stream-Forked-From: /echo/invocations/order-7/streams/input' \ -H 'Content-Type: application/json'

This forks order-7 from the selected phantom, not from the original agent. The source header is still a path only, as required by the Durable Streams fork protocol. It inherits the target URL’s selected root; do not put the query selector in Stream-Forked-From. Cross-root source references are not supported. With a path selector, retain the same selector segment in source and target paths.

Returned Location and stream URLs retain the canonical selector. For example, the fork URL above retains ?instance=dc7f9909-2975-42b3-9635-2f5ba7c73782; following that link stays within the same root. Other Durable Streams controls such as offset can be added to the query normally.

The public fork name retry-a is not a phantom UUID. Golem derives the fork’s UUID from the exact root identity and public name. Two roots using retry-a and order-7 therefore address different forks. A fork-of-fork still resolves both public fork names within the same selected root namespace.

If you already know a Durable Streams fork’s actual phantom UUID, selecting it on a non-/forks/ URL addresses that exact agent and can read its published sessions, provided the component, constructor parameters, method and slot match. /forks/<that-uuid> does something different: it treats the UUID text as a public fork name and derives another phantom. A further named fork from a directly selected phantom uses that phantom as its new root namespace.

SDK agent self-forks also copy agent state, but do not automatically publish inherited Durable Streams sessions. Durable Streams fork creation separately publishes the exported sessions and creation receipt. Selecting an SDK fork UUID does not replace this publication step, and root PUT creation/reattachment is not the same operation as fork PUT export/retry. Existing cuts, receipts, retries and stream protocol behavior are unchanged by root selection.

Cuts and sub-offsets

Stream-Fork-Offset retains the prefix through that cursor. Stream-Fork-Sub-Offset adds that many subsequent JSON messages or bytes. JSON sub-offsets can cross internal storage batches; byte sub-offsets must remain within the next protocol data boundary. A byte fork may therefore preserve a partial packed byte batch. Invalid or beyond-head cuts return 400.

Statuses and limits

  • 403 — initial content or closure was supplied for a read-only output slot.
  • 409 — conflicting retry, soft-deleted source/target, or max_forks_per_session reached.
  • 413 — copied oplog prefix or initial body exceeds its limit.
  • 429 — per-agent fork rate exceeded; honor Retry-After when present.

The worker-service settings and defaults are documented in Operating Durable Streams. A deleted fork slot remains tombstoned and cannot be recreated.

Fork support is part of every Durable Streams route. Route customization can disable external writes and deletion, but it cannot disable fork creation. On a read-only slot, forking the existing prefix is still allowed; supplying initial content or closure is not.