Migrating to Fabric Harness 6
Upgrade custom persistence adapters, clients, and persistent agents to the version 6 durable runtime contract.
Fabric Harness 6 is a coordinated major for @fabric-harness/sdk, @fabric-harness/node,
@fabric-harness/client, and @fabric-harness/cli. Upgrade those packages together. Adapter
packages have independent versions; use the versions released from the same certified commit.
Conversation stream stores
Custom ConversationStreamStore implementations must persist and return:
formatVersion: 1inConversationStreamMeta;- a stable
incarnationfor one stream generation; - the same incarnation in every producer claim and append fence;
- optional fold checkpoints fenced by incarnation and format version.
Generate a new incarnation only when a deleted stream is recreated. Reject appends from an older
incarnation. Run defineConversationStreamStoreContractTests from
@fabric-harness/sdk/testing/contracts against the adapter.
The HTTP and client protocols now emit stream_checkpoint updates. When reset is true, discard
the previous projection and resume from the supplied offset; the React store does this
automatically.
Submission stores
Custom AgentSubmissionStore implementations must implement the turn-boundary joining methods:
claimJoinableSubmissions();finalizeJoinedSubmission();revertJoiningSubmission();listJoinedSubmissions();settleJoinedSubmission().
Joining transitions are ownership-fenced and atomic. Use
defineSubmissionStoreContractTests to prove FIFO order, adoption, recovery, and settlement.
Client deadlines
Client HTTP requests now default to a 90-second deadline. For a deliberately longer synchronous compatibility call, set an explicit budget:
const fabric = createFabricClient({
baseUrl: process.env.FABRIC_URL!,
requestTimeoutMs: 10 * 60_000,
});Prefer asynchronous admission followed by wait(), read(), or updates() for durable work.
Set requestTimeoutMs: 0 only when an external transport already enforces a bounded deadline.
Persistent-agent changes
Declare submission durability statically in createAgent()'s second argument. The host reads this
policy before render, so it still applies when rendering or worker recovery fails:
export default createAgent(
() => {
useModel('anthropic/claude-sonnet-4-6');
return 'Handle the durable request.';
},
{ durability: { maxAttempts: 5, timeoutMs: 2 * 60 * 60_000 } },
);A string uid can no longer be combined with initialData. Use uid: null for create-only
admission, or send the existing uid without creation data.
useAgentStart() callbacks run concurrently. Work requiring ordering belongs in one callback.
Their state writes and appended signals commit atomically after every callback settles, while appended
signals are flattened in callback declaration order. Concurrent writes to the same state key follow
callback scheduling, so keep dependent or conflicting writes in one callback. Start and finish
callbacks receive signal, harness, and log.
Dynamic Native-loop model changes now resolve the provider owning the newly selected model. Hosts
with custom model routing should supply modelProviderResolver; a deliberately fixed
modelProvider remains fixed unless a resolver is configured. Return { provider, model } from a
custom resolver when the provider expects a normalized model id rather than the rendered
provider/model reference.
Static createAgent() policy remains authoritative across hook refreshes. Custom persistent hosts
must preserve the static definition when they re-render dynamic capabilities; dropping it can remove
approval and capability constraints and is unsupported.