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.
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.
canInteract
boolean
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
deployDefinitions(): Promise<DeployDefinitionsResult>
Validates, versions, and stores definitions.
verifyDeployedDefinitions(): Promise<VerifyDeployedDefinitionsResult>
Audits deployed effect names against registered handlers.
Drive instances directly
startInstance(): Promise<OperationResult>
Starts an instance and enters its initial stage.
getInstance(): Promise<WorkflowInstance>
Fetches an instance by ID.
evaluate(): Promise<WorkflowEvaluation>
Projects current state, gates, activities, and action verdicts.
availableActions(): Promise<AvailableActionsResult>
Lists current-stage actions with allowed or disabled verdicts.
fireAction(): Promise<OperationResult>
Fires a caller-driven action and continues the cascade.
editField(): Promise<OperationResult>
Changes a declared editable field and continues the cascade.
tick(): Promise<OperationResult>
Reevaluates an instance and continues any newly enabled cascade.
children(): Promise<WorkflowInstance[]>
Lists child instances spawned by a parent.
Reactive layer and document discovery
resolveActor(): Promise<ActorResolution<ClientProjectUser>>
Resolves the current client identity into durable actor provenance.
evaluateStart(): Promise<StartEvaluation>
Preflights ordered start requirements and required inputs without starting an instance.
definitionsForDocument(): Promise<DeployedDefinition[]>
Finds the latest deployed version of each definition whose subject type and start filter accept a loaded document.
instancesForDocument(): Promise<WorkflowInstance[]>
Finds in-flight instances with a live reference to a document, including unresolved child references and excluding exited-stage references.
subscriptionDocumentsForInstance(): Promise<WatchSet>
Returns the documents and perspective a reactive consumer must watch.
session(): InstanceSession
Creates a caller-driven reactive session around an instance.
Effect runtimes
drainEffects(): Promise<DrainEffectsResult>
Claims and dispatches pending effects through registered handlers.
listPendingEffects(): Promise<PendingEffect[]>
Lists every pending effect on an instance.
findPendingEffects(): Promise<PendingEffect[]>
Filters pending effects by claim state or effect name.
completeEffect(): Promise<OperationResult>
Records an effect result and continues the cascade.
commitEffectOps(): Promise<OperationResult>
Commits field state from a running effect handler and renews its claim.
Inspection and diagnostics
diagnose(): Promise<DiagnoseResult>
Explains why an instance is or is not progressing.
guardsForInstance(): Promise<MutationGuardDoc[]>
Lists mutation guards registered by an instance across its resources.
guardsForDefinition(): Promise<MutationGuardDoc[]>
Lists statically discoverable mutation guards for a deployed definition.
query(): Promise<T>
Runs GROQ against the engine workflow resource with $tag bound.
queryInScope(): Promise<T>
Runs GROQ against the instance snapshot and rendered workflow scope.
Cleanup and recovery
setStage(): Promise<OperationResult>
Forces an instance into a stage as an administrative override.
abortInstance(): Promise<OperationResult>
Hard-stops an in-flight instance.
deleteDefinition(): Promise<DeleteDefinitionResult>
Removes deployed definition versions, optionally aborting active instances.
resetActivity(): Promise<OperationResult>
Reruns or skips a terminal activity in the current stage, then continues the cascade.
Visiting agent?
Editorial Workflows includes an MCP server for inspecting, operating, authoring, validating, and deploying workflows. Ask your human to set up the MCP server.

