Editorial Workflows

Engine

The library that evaluates and commits Editorial Workflow instances.

The engine is the executable core of Editorial Workflows. It is a TypeScript library, not a hosted service: createEngine binds a Sanity client, the resource where workflow documents live, and an environment tag. The CLI, MCP server, server applications, and reactive UI layers all operate this same engine.

A definition describes a process. The engine turns it into running instances, evaluates their current state, and applies the operations that move them forward.

You may not need to call the engine directly. The CLI and MCP server wrap it for command-line and agent workflows. The reactive session, App SDK adapter, and Studio plugin operate it underneath application experiences. Initialize an engine yourself when building a custom server-side integration, worker, or runtime.

Create and use an engine

Once created, the engine exposes verbs rather than a mutable instance object:

import {createEngine, instanceDocId} from '@sanity/workflow-engine'

const engine = createEngine({
  client,
  workflowResource: {type: 'dataset', id: 'yourprojectid.workflows'},
  tag: 'production',
})

// Given a deployed definition named “article-review”, mint the retry key once
// and persist it with the job or request that owns this start.
const instanceId = instanceDocId('production')
const result = await engine.startInstance({
  definition: 'article-review',
  instanceId,
})

A caller-supplied instanceId is the idempotency and retry key for a programmatic start. Retry with the same ID to resume an interrupted create → prime → cascade sequence; replaying a settled start is a no-op. If you omit it, every call mints a new ID and a blind retry can create another instance. Reusing an ID for a different definition or explicitly selected version is rejected.

Instance writes are transactions

An instance document is a state machine, not ordinary content. Its current stage, resolved fields, history, idempotency records, pending effects, child workflows, and guards must describe one committed state.

Every state-changing verb validates first and writes nothing when rejected. Accepted changes commit the instance and its history and audit trail together, then continue the cascade until no triggered action or transition can fire.

A UI, CLI, or runtime enters through an engine verb. The engine evaluates the request, commits instance state in the Content Lake, refreshes guards, and runs the transition cascade.

Loading...

Do not patch instance documents through a Studio form, App SDK edit state, or a raw client. Those content-oriented writes can merge individual paths without the engine’s gates, history, or transaction boundary.

The read side is different. A reactive experience may evaluate against an editor’s uncommitted content, but that produces a preview projection; persisted instance state still changes only through engine verbs.

Reader-model acknowledgement

Engine 0.22 still writes model 4 documents. The deployment API accepts a numeric expectedMinReaderModel so older literals reach the runtime compatibility check, but deployment still requires exactly 4. Upgrade every engine-bearing reader before deploying, then set expectedMinReaderModel: 4. See the prerelease reader-model rollout for the required order.

Evaluation is advisory

The engine explains availability, requirements, roles, conditions, and guards so consumers can disable controls and fail early. These checks are not a security boundary: a caller can bypass the library with a raw client. Content Lake permissions are the enforcement point.

How the product layers fit together

The engine owns the domain model and transaction semantics. The store-agnostic React package drives a reactive session over it. The App SDK adapter supplies cross-resource document observation. The Studio adapter uses shared App SDK document stores, and the Studio plugin provides the Editorial Workflows interface on top of those layers. Explicit previewField projections—not Studio’s uncommitted form buffer—feed tentative field values into evaluation.

The CLI, MCP server, workers, and other server-side applications can call the engine directly.

Reference

WorkflowEvaluation

The engine and reactive session return the same read-only projection of one instance:

  • instance

    WorkflowInstance

    The evaluated instance snapshot.

  • definition

    WorkflowDefinition

    The deployed definition resolved for the instance.

  • actor

    Actor

    The actor whose identity, roles, and grants were used for this evaluation.

  • currentStage

    StageEvaluation

    The current stage with its activity and transition evaluations.

  • pendingOnYou

    ActivityEvaluation[]

    Active activities assigned to the evaluated actor.

  • True when at least one action on an active activity is allowed.

  • editableFields

    EditableFieldEvaluation[]

    Declared editable fields in the current scope, with their values, provenance, and edit verdicts.

  • fieldInsights

    FieldInsight[]

    Derived condition state for fields read by the current stage. See Evaluation insights for involvement and verified proposals.

  • autonomy

    WorkflowAutonomy

    The definition-wide projection of whether activities, stages, and the workflow can progress without a caller.

Engine methods

These methods are called on the engine instance returned by createEngine(...). Higher layers such as the CLI, MCP server, reactive adapters, and Studio plugin call the same engine surface for you.

Given a definition with a write activity and submit action, a direct engine integration typically deploys, starts, reads, and advances an instance like this:

await engine.deployDefinitions({
  expectedMinReaderModel: 4,
  definitions: [definition],
})

const {instance} = await engine.startInstance({
  definition: definition.name,
})
const instanceId = instance._id

const evaluation = await engine.evaluate({instanceId})

await engine.fireAction({
  instanceId,
  activity: 'write',
  action: 'submit',
})

await engine.tick({instanceId})

Deploy and validate a runtime

Drive instances directly

Reactive layer and document discovery

Effect runtimes

Inspection and diagnostics

Cleanup and recovery

Visiting agent?

Was this page helpful?