> For AI agents: the complete Sanity documentation index is available at [https://www.sanity.io/docs/llms.txt](https://www.sanity.io/docs/llms.txt).

# Workflow CLI command reference

Every Workflows CLI command with its flags, selectors, JSON output, and exit behavior, for deploying definitions and driving instances.

`@sanity/workflow-cli` deploys workflow definitions, inspects instances, and recovers stuck runs from a terminal or a CI job. This page lists every command with its arguments, flags, output, and exit behavior. For the setup every command here assumes, installing the CLI, authenticating, and writing `sanity.workflow.ts`, see [Configure and deploy workflow definitions](https://www.sanity.io/docs/workflows/deploy-definitions).

Run a command with `npx @sanity/workflow-cli <command>`. That form needs no install and uses the copy in your project when one is there. The package ships a single binary named `sanity-workflows`, so a project-local install runs the same commands as `sanity-workflows <command>`. Every command id also nests under the `workflows` topic, which is what lets a host CLI mount the package and surface the same command as `<host> workflows <command>`. Definition commands use the plural `definitions` topic and generation uses `blueprints generate`; `definition` and `blueprint` are accepted as aliases.

**npm**

```shell
# Deploy the definitions in one deployment, start a run, then move it along
npx @sanity/workflow-cli deploy --deployment production
npx @sanity/workflow-cli start article-review --deployment production
npx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6
npx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 --activity write --action submit
```

**pnpm**

```shell
# Deploy the definitions in one deployment, start a run, then move it along
pnpm dlx @sanity/workflow-cli deploy --deployment production
pnpm dlx @sanity/workflow-cli start article-review --deployment production
pnpm dlx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6
pnpm dlx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 --activity write --action submit
```

**yarn**

```shell
# Deploy the definitions in one deployment, start a run, then move it along
yarn dlx @sanity/workflow-cli deploy --deployment production
yarn dlx @sanity/workflow-cli start article-review --deployment production
yarn dlx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6
yarn dlx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 --activity write --action submit
```

**bun**

```shell
# Deploy the definitions in one deployment, start a run, then move it along
bunx @sanity/workflow-cli deploy --deployment production
bunx @sanity/workflow-cli start article-review --deployment production
bunx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6
bunx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 --activity write --action submit
```

## Select a deployment, a partition, or an instance

Three flag names appear across the CLI and they do not mean the same thing on every command. `--deployment` and `--partition` are always mutually exclusive, and every command that accepts both rejects the pair. Commands that take an instance id need neither, because an instance id is globally unique and carries its own partition.

| Commands | `--deployment` | `--partition` |
| --- | --- | --- |
| `deploy` | The one deployment to deploy. | Every deployment carrying the partition. A partition is an environment group, so this is a fan-out, not a picker. |
| `start`, `definitions diff`, `definitions delete` | The one deployment to act on. | The deployment carrying the partition, while the partition names exactly one. |
| `abort`, `set-stage`, `reset-activity`, `fire-action`, `diagnose` | Narrows where the instance is looked up. Optional. | Narrows where the instance is looked up. Optional. |
| `list`, `show`, `tail`, `definitions list`, `definitions show` | Not accepted. | A query filter, which also narrows which resources are searched. |
| `nuke` | The deployment to reset, or with `--instance`, which deployment to look the instance up in. | The partition to reset, while it names exactly one deployment. Not valid with `--instance`. |
| `blueprints generate` | Not accepted. The command covers the whole config. | Not accepted. The command covers the whole config. |

The `deploy` row is the one that surprises people. On `start`, `definitions diff`, and `definitions delete`, `--partition` resolves to exactly one deployment and errors when it cannot. On `deploy` it deploys every deployment carrying the partition instead. On the instance-keyed commands it is only a narrower: it limits which resources are searched, and never has to resolve to one deployment.

> [!NOTE]
> Using tag in config or scripts
> `--tag`, `--all-tags`, and a deployment `tag` in `sanity.workflow.ts` still work and print a deprecation warning on stderr. If your config or scripts use them, rename each to `partition` (`--partition`, `--all-partitions`) and keep the same value. See [Deployments, partitions, and resources](https://www.sanity.io/docs/workflows/deployments-and-resources).

With no selector at all, a command that needs one deployment falls back to the sole deployment when the config declares exactly one. When several are declared, an interactive terminal prompts for one and a non-interactive shell fails with `Multiple deployments configured — pass --deployment or --partition.` (`deploy` adds `, or --all-partitions to deploy every deployment` to that message.) Read commands need no selector in any case: without one, they span every distinct resource the config mentions.

An instance id looks like `prod.wf-instance.a1b2c3d4e5f6`. When the id carries a leading partition segment the CLI probes the resources under that partition first and falls back to the full fan-out on a miss, so the prefix is a speed hint and never a requirement. If several deployments hold the same id, an interactive terminal asks you to pick one; with `--json` or in a non-interactive shell the command fails, lists each candidate as `name (dataset)`, and asks for `--deployment`.

### Find the config

Every command that reads `sanity.workflow.ts` looks in the directory you run it from, then in each parent directory, and uses the first config it finds. Pass `--path` with a config file, or with a directory to start that search from. `blueprints generate` writes, and `deploy` checks, the generated Blueprint files next to the config file, not in the directory you ran the command from.

### Read a resource without a config

The read commands `list`, `show`, `tail`, `diagnose`, `definitions list`, and `definitions show` can read one resource you name, with or without a config. Pass `--project-id` and `--dataset` (`-p` and `-d`) together for a dataset, or `--media-library-id` for a media library. The CLI then loads no config and reads only that resource, so these flags cannot be combined with `--deployment` or `--path`. `--partition` still filters. Commands that write always act through a deployment in `sanity.workflow.ts`.

**npm**

```shell
npx @sanity/workflow-cli definitions list --project-id YOUR_PROJECT_ID --dataset production
npx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 -p YOUR_PROJECT_ID -d production
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli definitions list --project-id YOUR_PROJECT_ID --dataset production
pnpm dlx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 -p YOUR_PROJECT_ID -d production
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli definitions list --project-id YOUR_PROJECT_ID --dataset production
yarn dlx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 -p YOUR_PROJECT_ID -d production
```

**bun**

```shell
bunx @sanity/workflow-cli definitions list --project-id YOUR_PROJECT_ID --dataset production
bunx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 -p YOUR_PROJECT_ID -d production
```

## Read the output as JSON

`--json` is available on `start`, `fire-action`, `list`, `show`, `diagnose`, `definitions list`, `definitions show`, and `definitions validate`. The other commands have no JSON mode. Rows from `list` and `definitions list` carry the partition in a `partition` field. One payload convention runs across all of them:

- Write commands emit the operation envelope, where `instanceId` carries the document `_id`.
- `show` commands print the fetched document exactly as stored.
- List commands print the row view of the table, each row annotated with the `resource` it came from, under a top-level `truncated` flag.

List commands treat `--json` as all-or-nothing across resources. The rendered path tolerates a resource the token cannot read, notes the failure in place, and prints the rest; the JSON path rejects the whole read instead, so a script never mistakes a partial listing for a complete one.

## Exit codes

Every command exits `0` on success. The CLI sets two other codes itself, and hands anything it does not recognize to oclif, which prints a stack trace and chooses its own.

| Code | When |
| --- | --- |
| `0` | The command completed. A write that found nothing to change also exits `0` and says so. |
| `1` | The failure path the CLI owns: no `sanity.workflow.ts`, an invalid config, no matching deployment, definition, or instance, contradictory flags, a rejected engine write, a refused destructive command, a rejected auth token, or a reader-floor acknowledgement that does not cover the submitted definitions. Also the exit for a multi-target run in which at least one target failed. `blueprints generate --check` also exits `1` when the generated runtime differs from the files on disk or needs manual fixes. |
| `130` | You interrupted an interactive prompt with Ctrl+C. This is the Unix 128 + SIGINT convention. |
| `2` | The command line could not be parsed: an unknown command or flag, a missing or unexpected argument, or a flag value of the wrong type. The CLI prints the error and the command's usage. |

Multi-target runs are deliberately tolerant. `deploy --all-partitions` continues past a deployment that failed, prints a summary naming each failure, and exits `1`; deploys are idempotent, so re-running is safe. `list` and `definitions list` do the same across resources. A run with a single target rethrows instead of summarizing, and an authentication rejection stops any run at once, because a dead token is never local to one target.

## Commands

Each entry names the command, one representative invocation, and its complete argument and flag contract. Arguments are positional and shown in upper case; flags marked required have no default the command can fall back to.

### deploy: validate, diff, and ship definitions

`deploy` validates the definitions in the selected deployment, then writes them to the resource that the `workflowResource` of that deployment names. Validation runs offline before any network write, so a run spanning several deployments cannot leave a partial deploy behind a broken batch. Definitions are content-addressed: deploying an unchanged definition creates no new version, which is what makes re-running a failed deploy safe.

When `workflows.blueprint.ts` exists beside the config, deploy checks generated-runtime alignment for the whole config before token resolution or writes. Drift and missing handlers stop deployment. `--check` and `--dry-run` include this check; `--only`, `--deployment`, and `--partition` do not narrow it. There is no bypass flag. Without a generated tree, deploy reports runtime needs and continues.

Before writing, `deploy` also checks for a likely lost partition. When it would deploy to the `default` partition of a workflow resource whose definitions all live in other partitions, it warns and names those partitions. In an interactive terminal it then asks whether to continue, and answering no exits before anything is written. A `--dry-run` or a non-interactive run prints the warning and continues.

Without a generated tree, deploy prints one summary line per selected deployment, counting the effect drains, heartbeats, and start watchers it needs. Pass `--verbose` for the full report. `--dry-run` runs every check a real deploy runs before its first write, including the reader-floor acknowledgement and the project role check, so it fails on any batch the deploy would reject.

On `deploy` alone, `--partition` deploys every deployment carrying the partition rather than resolving to one. A deploy that creates new definition versions also shares those documents with Sanity by default in every environment; `--no-share-defs` opts out for one run.

**npm**

```shell
# Validate offline, diff against what is deployed, then deploy
npx @sanity/workflow-cli deploy --check --deployment production
npx @sanity/workflow-cli deploy --dry-run --deployment production
npx @sanity/workflow-cli deploy --deployment production
```

**pnpm**

```shell
# Validate offline, diff against what is deployed, then deploy
pnpm dlx @sanity/workflow-cli deploy --check --deployment production
pnpm dlx @sanity/workflow-cli deploy --dry-run --deployment production
pnpm dlx @sanity/workflow-cli deploy --deployment production
```

**yarn**

```shell
# Validate offline, diff against what is deployed, then deploy
yarn dlx @sanity/workflow-cli deploy --check --deployment production
yarn dlx @sanity/workflow-cli deploy --dry-run --deployment production
yarn dlx @sanity/workflow-cli deploy --deployment production
```

**bun**

```shell
# Validate offline, diff against what is deployed, then deploy
bunx @sanity/workflow-cli deploy --check --deployment production
bunx @sanity/workflow-cli deploy --dry-run --deployment production
bunx @sanity/workflow-cli deploy --deployment production
```

**sanity-workflows deploy(--deployment, --partition, --all-partitions, --dry-run, --check, --only, --verbose, --share-defs / --no-share-defs): Rendered output only**

Validate, diff, and deploy the definitions in the selected deployment to the resource it binds.

Parameters:
- **--deployment** (string): Deployment name, the unique identity of one deployment in the config. Mutually exclusive with --partition.
- **--partition** (string): Workflow environment partition, for example prod or test. On deploy this deploys every deployment carrying the partition, not one, because a partition is an environment group. Mutually exclusive with --deployment.
- **--all-partitions** (boolean): Deploy every deployment in the config. Default false. Mutually exclusive with --deployment and --partition.
- **--dry-run** (boolean): Validate, then diff each definition against the deployed version and print the diff. Writes nothing. Default false.
- **--check** (boolean): Validate the definitions and stop. Never contacts the dataset and never resolves a token, so it runs offline and unauthenticated. Default false. Combining it with --dry-run fails with Pass either --check or --dry-run, not both.
- **--only** (string): Limit deploy, check, or dry-run to one definition by name. Every targeted deployment must declare it; a name no deployment declares fails with No definition named "<name>". before any deployment picker runs.
- **--verbose** (boolean): When no generated runtime sits beside the config, print the full report of the Sanity Functions the selected deployments need instead of the one-line-per-deployment summary. Default false.
- **--share-defs / --no-share-defs** (boolean): Share the definition documents this deploy newly creates with Sanity: the full document verbatim, plus the project and dataset it was deployed to. Never content documents, instances, or your auth token. Sharing is the default in every environment, CI, non-TTY, and DO_NOT_TRACK included. A failed share warns and never fails the deploy.

### blueprints generate: generate an experimental runtime

`blueprints generate` derives Sanity Functions from the workflow definitions in your config and writes them beside the config. It is experimental and not ready for production use. For setup, file ownership, deployment order, and current limits, see [Try the generated runtime](https://www.sanity.io/docs/workflows/generate-functions).

The command covers every deployment and accepts no deployment or partition selector. Each deployment must be a named export from the config under its own `name`. Generation validates definitions, checks the exports and required dependencies, and reports the runtime needs before writing files.

The runtime-needs report describes each drain and start-watcher trigger, the heartbeat’s separate workflow-tick and effect-recovery scopes, and its recovery budget. It warns about creates-only watchers, unrestricted subject types, and filters whose dependencies require observing every update. Review those warnings before deploying the generated Functions.

**npm**

```shell
npx @sanity/workflow-cli blueprints generate
npx @sanity/workflow-cli blueprints generate --check
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli blueprints generate
pnpm dlx @sanity/workflow-cli blueprints generate --check
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli blueprints generate
yarn dlx @sanity/workflow-cli blueprints generate --check
```

**bun**

```shell
bunx @sanity/workflow-cli blueprints generate
bunx @sanity/workflow-cli blueprints generate --check
```

**sanity-workflows blueprints generate(--check): Rendered output only**

Generate runtime files, or compare the current files with the generated result.

Parameters:
- **--check** (boolean): Default false. Render the expected files in memory and compare them with disk. Write nothing. Exit 0 when the tree matches, or 1 when files or wiring need attention.

Generation rewrites generated modules, creates missing handler stubs, and preserves existing handlers. It reports orphaned handlers, case collisions, and Blueprint wiring that needs manual changes. It deletes nothing.

With `--check`, a missing file reports `missing` and an edited generated file reports `differs`. Orphaned handlers or registries, case collisions, and unresolved Blueprint wiring also fail the check. A missing handler fails even if the other generated files match.

A stale function directory also fails the check. That is a directory under the generated `functions/` tree whose `index.ts` carries the generator's header but which the current definitions no longer produce, such as the directory left behind when a deployment is renamed. `blueprints generate` lists it for you to remove, and `deploy` prints a warning naming it and continues. A directory whose `index.ts` has no generator header is yours and is never reported.

`deploy` also runs the alignment check when `workflows.blueprint.ts` exists beside the config. Keep `blueprints generate --check` in CI when you want a standalone check without a definition deployment. After upgrading the generator, regenerate, review preserved handlers, deploy definitions, then redeploy Functions.

### start: create an instance from a deployed definition

`start` creates a workflow instance from a definition already deployed under the selected deployment. Supply a value for each field the definition declares with `initialValue: {type: 'input'}` using `--field name=value`. Values are parsed as JSON and fall back to a plain string, so a reference field takes a JSON object carrying the global id and type of the document.

If the engine creates and primes the instance but its first auto-advance fails, `start` reports the run as started rather than failed, because the instance exists. It settles on the next `tick`, or you can re-run with `--instance-id` set to the reported id, which resumes the earlier attempt instead of creating a duplicate.

Runtime-supplied refs, such as a `--field` subject or a release ref, may target the deployment's `workflowResource` or any resource it binds in `resourceAliases`, in another dataset or another project. Anything else fails with `RefResourceUndeclaredError`. To start a workflow on content in another resource, bind that resource even when no definition references the alias. The CLI reaches each bound resource with the same token and API host, so that login must be a member of every bound project. Instance commands such as `fire-action`, `abort`, and `diagnose` use the bindings of the deployment that owns the instance.

**npm**

```shell
npx @sanity/workflow-cli start article-review \
  --deployment production \
  --field subject='{"id":"dataset:YOUR_PROJECT_ID:production:article-1","type":"article"}'
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli start article-review \
  --deployment production \
  --field subject='{"id":"dataset:YOUR_PROJECT_ID:production:article-1","type":"article"}'
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli start article-review \
  --deployment production \
  --field subject='{"id":"dataset:YOUR_PROJECT_ID:production:article-1","type":"article"}'
```

**bun**

```shell
bunx @sanity/workflow-cli start article-review \
  --deployment production \
  --field subject='{"id":"dataset:YOUR_PROJECT_ID:production:article-1","type":"article"}'
```

**sanity-workflows start NAME(NAME, --deployment, --partition, --version, --field, --instance-id, --json): `{instanceId, definition, version, currentStage, completedAt}` with `--json`**

Start a workflow instance from a deployed definition, seeding its input-sourced fields.

Parameters:
- **NAME** (string): The workflow definition name, as declared by defineWorkflow.
- **--deployment** (string): Deployment name, the unique identity of one deployment in the config. Mutually exclusive with --partition.
- **--partition** (string): Workflow environment partition, for example prod or test. Selects the deployment to act on while the partition names exactly one; a partition spanning several fails and asks for --deployment. Mutually exclusive with --deployment.
- **--version** (integer): Definition version to start from. Defaults to the highest deployed version.
- **--field** (string[]): Initial value for one declared input-sourced field, as name=value. Repeatable. Each value is JSON-parsed and falls back to a plain string; reference kinds take a JSON object with a global document reference id and a document type.
- **--instance-id** (string): Start under this instance id. The id is the idempotency key of the start: passing the id of a start that failed partway resumes it, and an already-settled start replays as a no-op. Omit it to mint a fresh id.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.

### fire-action: resolve an activity, or list what can be fired

`fire-action` fires one action on one activity of the current stage of an instance. Omit `--action` and it lists every action on that stage instead, each marked fireable or not with the reason it is disabled and the params it takes. Passing `--action` without `--activity` fails and asks for the activity.

The write is attributed to whoever the configured token authenticates. There is no impersonation flag, and the engine resolves the acting identity from the token rather than from anything you pass. Firing an action on an activity that is no longer active changes nothing and says so.

**npm**

```shell
# List what can be fired right now
npx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6

# Fire one action
npx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 \
  --activity write --action submit --param note='ready for review'
```

**pnpm**

```shell
# List what can be fired right now
pnpm dlx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6

# Fire one action
pnpm dlx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 \
  --activity write --action submit --param note='ready for review'
```

**yarn**

```shell
# List what can be fired right now
yarn dlx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6

# Fire one action
yarn dlx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 \
  --activity write --action submit --param note='ready for review'
```

**bun**

```shell
# List what can be fired right now
bunx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6

# Fire one action
bunx @sanity/workflow-cli fire-action prod.wf-instance.a1b2c3d4e5f6 \
  --activity write --action submit --param note='ready for review'
```

**sanity-workflows fire-action INSTANCEID(INSTANCEID, --activity, --action, --param, --deployment, --partition, --json): `{instanceId, activity, action, changed, cascaded, currentStage, ranOps}` with `--json`**

Fire an action to resolve a waiting activity, or list the actions available on the current stage of the instance.

Parameters:
- **INSTANCEID** (string): The workflow instance id.
- **--activity** (string): The activity the action belongs to. Required to fire; omit --action to list instead.
- **--action** (string): The action to fire. Omit it to list the actions available on the instance.
- **--param** (string[]): An action param as key=value. Repeatable. Values are JSON-parsed and fall back to a plain string; the engine validates each against the declared type of the param.
- **--deployment** (string): Narrows the instance search to the resource that deployment targets. Never required: an instance id is globally unique. The partition still comes from the loaded instance, not from this flag. Mutually exclusive with --partition.
- **--partition** (string): Narrows the instance search to the resources deployed under that partition. Never required. Mutually exclusive with --deployment.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.

### list: find instances

`list` lists workflow instances, in-flight only unless you pass `--include-completed`. Without `--partition` it spans every distinct resource the config mentions, and prints a banner per resource when it spans more than one. `--partition` here is a query filter, not a deployment selector: it filters rows and narrows which resources are searched.

When the read spans several resources, one the token cannot read is noted in place, the rest still render, and the run exits `1`. `--limit` caps rows per resource at 50 by default; the output says when a page was clipped.

To find work assigned to a person or offered to their roles, pass `--assignment-user`, repeat `--assignment-role` for their project roles, and select the `held` and `routed` states. Replace `ACCOUNT_USER_ID` with the person’s account-global user ID, not a project membership ID. Replace `editor` with a project role they hold.

**npm**

```shell
npx @sanity/workflow-cli list --partition prod \
  --assignment-user ACCOUNT_USER_ID \
  --assignment-role editor \
  --assignment-state held --assignment-state routed \
  --json
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli list --partition prod \
  --assignment-user ACCOUNT_USER_ID \
  --assignment-role editor \
  --assignment-state held --assignment-state routed \
  --json
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli list --partition prod \
  --assignment-user ACCOUNT_USER_ID \
  --assignment-role editor \
  --assignment-state held --assignment-state routed \
  --json
```

**bun**

```shell
bunx @sanity/workflow-cli list --partition prod \
  --assignment-user ACCOUNT_USER_ID \
  --assignment-role editor \
  --assignment-state held --assignment-state routed \
  --json
```

Each JSON row includes `assignment: {unrouted, routed, held}` counts for active activities in the current open stage. `held` counts direct assignments to that person; `routed` counts unassigned work offered through their supplied roles. `unrouted` counts work with neither a person nor a role selected. These counts do not mean the person can perform an action. Without `--json`, the same counts appear in the `assignment u/r/h` column.

**npm**

```shell
npx @sanity/workflow-cli list --definition article-review --failed --partition prod
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli list --definition article-review --failed --partition prod
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli list --definition article-review --failed --partition prod
```

**bun**

```shell
bunx @sanity/workflow-cli list --definition article-review --failed --partition prod
```

**sanity-workflows list(--partition, --include-completed, --failed, --definition, --document, --assignment-user, --assignment-role, --assignment-state, --limit, --json, --project-id, -p, --dataset, -d, --media-library-id): `{instances, truncated}` with `--json`**

List workflow instances across the resources the config mentions.

Parameters:
- **--partition** (string): Workflow environment partition, for example prod or test. A query filter that also narrows which resources are searched. Omit it to span every resource the config mentions.
- **--include-completed** (boolean): Include completed and aborted instances. Default false, which lists in-flight instances only.
- **--failed** (boolean): Only instances with at least one activity in the failed status, in any stage. Default false.
- **--definition** (string): Only instances of this workflow definition, matched against the definition field of the instance.
- **--document** (string): Only instances that reference this document. Takes a resource-qualified global document reference, for example dataset:YOUR_PROJECT_ID:production:article-1.
- **--assignment-user** (string): Account-global user ID for viewer-scoped assignment filtering and counts.
- **--assignment-role** (string): A literal project role held by the viewer. Repeat for multiple roles. Requires --assignment-user; role aliases do not add inbox ownership.
- **--assignment-state** (string): Include unrouted, routed, or held activities. Repeat for multiple states. Requires --assignment-user. Routed means offered through a supplied role; held means assigned directly to the supplied user.
- **--limit** (integer): Maximum rows to return per resource. Default 50.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.
- **--project-id, -p** (string): Project ID of a dataset to read instead of the config. Requires --dataset. Not valid with --deployment, --path, or --media-library-id.
- **--dataset, -d** (string): Dataset to read instead of the config. Requires --project-id.
- **--media-library-id** (string): Media library to read instead of the config. Not valid with --project-id, --dataset, --deployment, or --path.

### show: read one instance in full

`show` prints the stages of one instance, the activities in each with their status, and any pending effects. History is left out unless you pass `--include history`, because it grows without bound. `--json` always carries the complete stored document regardless of `--include`.

For an in-flight instance, rendered output also evaluates current state and explains faults such as missing references. If evaluation fails, `show` warns and displays stored state with reference availability unknown. Completed and aborted instances, and `show --json`, are displayed without this evaluation.

`show` locates the instance by fanning out across every resource the config mentions, so it takes no deployment selector. An id no resource holds exits `1`.

**npm**

```shell
npx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 --include history
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 --include history
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 --include history
```

**bun**

```shell
bunx @sanity/workflow-cli show prod.wf-instance.a1b2c3d4e5f6 --include history
```

**sanity-workflows show INSTANCEID(INSTANCEID, --partition, --include, --json): The complete instance document with `--json`**

Show the state, activities, and pending effects of one workflow instance.

Parameters:
- **INSTANCEID** (string): The workflow instance document id.
- **--partition** (string): Workflow environment partition, for example prod or test. A query filter that also narrows which resources are searched. Omit it to span every resource the config mentions.
- **--include** (string[]): Extra sections for the rendered output. Repeatable. The only accepted value is history.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.

### tail: stream new history entries

`tail` subscribes to one instance and prints each new history entry as it lands in the dataset. It runs until you stop it: Ctrl+C or SIGTERM unsubscribes and exits `0`. A dropped subscription exits `1` rather than hanging.

`tail` prints the timestamp and type of each entry, not its payload. Read the payload with `show --include history` or `show --json`. There is no `--json` mode on `tail`.

**npm**

```shell
npx @sanity/workflow-cli tail prod.wf-instance.a1b2c3d4e5f6
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli tail prod.wf-instance.a1b2c3d4e5f6
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli tail prod.wf-instance.a1b2c3d4e5f6
```

**bun**

```shell
bunx @sanity/workflow-cli tail prod.wf-instance.a1b2c3d4e5f6
```

**sanity-workflows tail INSTANCEID(INSTANCEID, --partition): Rendered output only**

Stream new history entries on a workflow instance as they land in the dataset.

Parameters:
- **INSTANCEID** (string): The workflow instance id to tail.
- **--partition** (string): Workflow environment partition, for example prod or test. A query filter that also narrows which resources are searched. Omit it to span every resource the config mentions.

### diagnose: explain why an instance is not progressing

`diagnose` classifies an instance as progressing, waiting, blocked, stuck, completed, or aborted, explains why, and lists the remediations the engine considers available. A waiting result distinguishes an action available to this caller, a manual action unavailable to this caller, and automation. Unassigned work has no selected holder; it is not automatically actionable. The command reads state without writing it.

A stuck verdict identifies the primary cause in `diagnosis.cause`. The command also shows current transition conditions and available recovery operations:

| Cause | Meaning |
| --- | --- |
| `document-missing` | A required or currently needed content reference is unavailable. The evidence identifies the field and reference. |
| `failed-effect` | An effect failed and blocks its activity. |
| `hung-effect` | An effect was claimed but no outcome was recorded. |
| `failed-activity` | An activity is in a failed state. |
| `no-transition-fires` | Activities have resolved, but no exit transition condition is true. |
| `transition-unevaluable` | Every activity is resolved, but an exit transition reads data that is missing or unreadable (GROQ `null`), so it holds the stage, even when a transition declared after it is satisfied. Once the data is written, the next `tick` or commit checks the transitions again, and the instance moves on only if one is then satisfied. No remediation applies. |

Missing-reference details distinguish content that was deleted, cannot be read, or exists outside the workflow perspective when the checks establish that distinction. A failed read does not prove deletion. Existing activity and effect faults retain their recovery operations. See [When referenced content is deleted](https://www.sanity.io/docs/workflows/cookbook-handle-deleted-subject) for repair guidance.

**npm**

```shell
npx @sanity/workflow-cli diagnose prod.wf-instance.a1b2c3d4e5f6
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli diagnose prod.wf-instance.a1b2c3d4e5f6
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli diagnose prod.wf-instance.a1b2c3d4e5f6
```

**bun**

```shell
bunx @sanity/workflow-cli diagnose prod.wf-instance.a1b2c3d4e5f6
```

**sanity-workflows diagnose INSTANCEID(INSTANCEID, --deployment, --partition, --json): `{instanceId, stage, diagnosis, remediations, transitions}` with `--json`**

Explain whether a workflow instance is progressing, why it is not, and what would unstick it.

Parameters:
- **INSTANCEID** (string): The workflow instance id.
- **--deployment** (string): Narrows the instance search to the resource that deployment targets. Never required: an instance id is globally unique. The partition still comes from the loaded instance, not from this flag. Mutually exclusive with --partition.
- **--partition** (string): Narrows the instance search to the resources deployed under that partition. Never required. Mutually exclusive with --deployment.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.

### abort: hard-stop an in-flight instance

`abort` stops an in-flight instance where it stands. Pending effects are cancelled, the stage guards it holds are removed, and the instance is marked terminal in its current stage. It deletes nothing and moves the instance to no other stage.

Aborting an instance that is already terminal changes nothing and reports when it terminated. Abort before deleting: `nuke --instance` refuses an in-flight instance precisely so its effects and children are cleaned up first.

**npm**

```shell
npx @sanity/workflow-cli abort prod.wf-instance.a1b2c3d4e5f6 \
  --reason 'superseded by relaunch'
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli abort prod.wf-instance.a1b2c3d4e5f6 \
  --reason 'superseded by relaunch'
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli abort prod.wf-instance.a1b2c3d4e5f6 \
  --reason 'superseded by relaunch'
```

**bun**

```shell
bunx @sanity/workflow-cli abort prod.wf-instance.a1b2c3d4e5f6 \
  --reason 'superseded by relaunch'
```

**sanity-workflows abort INSTANCEID(INSTANCEID, --reason, --deployment, --partition): Rendered output only**

Abort an in-flight workflow instance: cancel pending effects, remove stage guards, and mark it terminal where it stands.

Parameters:
- **INSTANCEID** (string): The workflow instance id.
- **--reason** (string): Free-text reason, recorded on the history entry for audit.
- **--deployment** (string): Narrows the instance search to the resource that deployment targets. Never required: an instance id is globally unique. The partition still comes from the loaded instance, not from this flag. Mutually exclusive with --partition.
- **--partition** (string): Narrows the instance search to the resources deployed under that partition. Never required. Mutually exclusive with --deployment.

### set-stage: force an instance into a stage

`set-stage` moves an instance to any stage its pinned definition declares, ignoring the declared transitions and their conditions. This is the administrative override the engine provides.

It is not a full bypass. The enter lifecycle of the target stage still runs, so auto-activities start and stage guards reconcile, and the cascade that follows the move can advance the instance onward immediately. Omit `--to` on an interactive terminal to pick from the stages the pinned definition declares; the picker marks the current stage and offers every declared stage. A non-interactive shell fails asking for `--to`. Moving an instance to the stage it is already in changes nothing, and a terminal instance never moves.

**npm**

```shell
npx @sanity/workflow-cli set-stage prod.wf-instance.a1b2c3d4e5f6 \
  --to review --reason 'unblock for demo'
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli set-stage prod.wf-instance.a1b2c3d4e5f6 \
  --to review --reason 'unblock for demo'
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli set-stage prod.wf-instance.a1b2c3d4e5f6 \
  --to review --reason 'unblock for demo'
```

**bun**

```shell
bunx @sanity/workflow-cli set-stage prod.wf-instance.a1b2c3d4e5f6 \
  --to review --reason 'unblock for demo'
```

**sanity-workflows set-stage INSTANCEID(INSTANCEID, --to, --reason, --deployment, --partition): Rendered output only**

Force a workflow instance into a stage regardless of its declared transitions and filters.

Parameters:
- **INSTANCEID** (string): The workflow instance id to move.
- **--to** (string): Target stage name. Any stage the pinned definition of the instance declares is accepted. Omit it on an interactive terminal to pick from a list.
- **--reason** (string): Free-text reason, recorded on the history entry for audit.
- **--deployment** (string): Narrows the instance search to the resource that deployment targets. Never required: an instance id is globally unique. The partition still comes from the loaded instance, not from this flag. Mutually exclusive with --partition.
- **--partition** (string): Narrows the instance search to the resources deployed under that partition. Never required. Mutually exclusive with --deployment.

### reset-activity: re-run or skip a failed activity

`reset-activity` returns a failed activity to `active` so it can run again. Pass `--skip` to mark it `skipped` instead, which is what lets an exit transition gated on that activity fire without the work being done. Both forms continue the workflow cascade.

The activity must be in the current stage of the instance, named exactly as the definition declares it. An activity already at the target status changes nothing, and a terminal instance never resets.

**npm**

```shell
# Re-run it
npx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review

# Or bypass it so the exit transition can fire
npx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review --skip
```

**pnpm**

```shell
# Re-run it
pnpm dlx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review

# Or bypass it so the exit transition can fire
pnpm dlx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review --skip
```

**yarn**

```shell
# Re-run it
yarn dlx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review

# Or bypass it so the exit transition can fire
yarn dlx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review --skip
```

**bun**

```shell
# Re-run it
bunx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review

# Or bypass it so the exit transition can fire
bunx @sanity/workflow-cli reset-activity prod.wf-instance.a1b2c3d4e5f6 legal-review --skip
```

**sanity-workflows reset-activity INSTANCEID ACTIVITY(INSTANCEID, ACTIVITY, --skip, --deployment, --partition): Rendered output only**

Reset a failed activity on an in-flight instance, back to active to re-run it or skipped to bypass it.

Parameters:
- **INSTANCEID** (string): The workflow instance id.
- **ACTIVITY** (string): The activity name, within the current stage of the instance.
- **--skip** (boolean): Mark the activity skipped instead of returning it to active. Default false.
- **--deployment** (string): Narrows the instance search to the resource that deployment targets. Never required: an instance id is globally unique. The partition still comes from the loaded instance, not from this flag. Mutually exclusive with --partition.
- **--partition** (string): Narrows the instance search to the resources deployed under that partition. Never required. Mutually exclusive with --deployment.

### definitions list: list deployed definitions

`definitions list` lists the definitions deployed in every resource the config mentions, ordered by name with the newest version first, and counts the instances each has and how many are still in flight.

`--partition` filters rows and narrows which resources are searched; omit it to span them all. When the read spans several resources, one that fails is noted in place, the rest still render, and the run exits `1`.

**npm**

```shell
npx @sanity/workflow-cli definitions list --partition prod
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli definitions list --partition prod
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli definitions list --partition prod
```

**bun**

```shell
bunx @sanity/workflow-cli definitions list --partition prod
```

**sanity-workflows definitions list(--partition, --limit, --name, --json, --project-id, -p, --dataset, -d, --media-library-id): `{definitions, truncated}` with `--json`**

List the workflow definitions deployed in the resources the config mentions.

Parameters:
- **--partition** (string): Workflow environment partition, for example prod or test. A query filter that also narrows which resources are searched. Omit it to span every resource the config mentions.
- **--limit** (integer): Maximum definitions to return per resource. Default 100.
- **--name** (string): Filter to a single workflow definition name, for example article-review.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.
- **--project-id, -p** (string): Project ID of a dataset to read instead of the config. Requires --dataset. Not valid with --deployment, --path, or --media-library-id.
- **--dataset, -d** (string): Dataset to read instead of the config. Requires --project-id.
- **--media-library-id** (string): Media library to read instead of the config. Not valid with --project-id, --dataset, --deployment, or --path.

### definitions show: read one deployed definition

`definitions show` prints one deployed definition, its latest version unless `--version` names one. It reads what is stored in the Content Lake, not what your `sanity.workflow.ts` currently declares.

It refuses every ambiguity rather than choosing. A name deployed under several partitions inside one dataset fails and lists the partitions; a name held by several datasets fails and lists the resources. Pass `--partition` to resolve either.

**npm**

```shell
npx @sanity/workflow-cli definitions show article-review --partition prod --version 2
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli definitions show article-review --partition prod --version 2
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli definitions show article-review --partition prod --version 2
```

**bun**

```shell
bunx @sanity/workflow-cli definitions show article-review --partition prod --version 2
```

**sanity-workflows definitions show NAME(NAME, --partition, --version, --json): The complete deployed definition document with `--json`**

Show one deployed workflow definition as it is stored.

Parameters:
- **NAME** (string): The workflow definition name.
- **--partition** (string): Workflow environment partition, for example prod or test. A query filter that also narrows which resources are searched. Omit it to span every resource the config mentions.
- **--version** (integer): A specific deployed version. Defaults to the latest.
- **--json** (boolean): Emit structured JSON on stdout instead of the rendered view.

### definitions diff: compare in-code against deployed

`definitions diff` diffs one definition as authored in your `sanity.workflow.ts` against the version deployed to the selected deployment, the latest unless `--version` names one. Nothing deployed under that name is a legitimate result and renders as a create.

It takes exactly one definition name, where `deploy --dry-run` diffs every definition in the deployment. Use `definitions diff` when you want one answer and `deploy --dry-run` when you want the whole batch. There is no `--json` mode.

### definitions validate: check definition JSON files

`definitions validate` checks workflow definitions written as JSON files, without a config, a login, or network access. Each file holds one definition or an array of them, in authoring shape or as stored content read back from a deploy. Pass several files to check a parent and its child workflows together. The command prints one line per valid definition and exits non-zero with every problem listed, path-prefixed, when any definition is invalid. `--json` prints the same `{valid, results}` report as the MCP `workflows_validate_definition` tool.

It checks shape, cross-field rules, and GROQ syntax. `deploy` runs further checks: duplicate names, spawn dependencies, resource bindings, project roles, and the reader-model acknowledgement. A file that cannot be read, is not valid JSON, or does not hold definition objects stops the command with a text error, even with `--json`.

**npm**

```shell
npx @sanity/workflow-cli definitions validate review.json
npx @sanity/workflow-cli definitions validate parent.json child.json --json
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli definitions validate review.json
pnpm dlx @sanity/workflow-cli definitions validate parent.json child.json --json
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli definitions validate review.json
yarn dlx @sanity/workflow-cli definitions validate parent.json child.json --json
```

**bun**

```shell
bunx @sanity/workflow-cli definitions validate review.json
bunx @sanity/workflow-cli definitions validate parent.json child.json --json
```

**npm**

```shell
npx @sanity/workflow-cli definitions diff article-review --deployment production
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli definitions diff article-review --deployment production
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli definitions diff article-review --deployment production
```

**bun**

```shell
bunx @sanity/workflow-cli definitions diff article-review --deployment production
```

**sanity-workflows definitions diff NAME(NAME, --deployment, --partition, --version): Rendered output only**

Diff an in-code workflow definition against the version deployed to the selected deployment.

Parameters:
- **NAME** (string): The workflow definition name. It must be declared by the selected deployment; a name it does not declare fails and lists the ones it does.
- **--deployment** (string): Deployment name, the unique identity of one deployment in the config. Mutually exclusive with --partition.
- **--partition** (string): Workflow environment partition, for example prod or test. Selects the deployment to act on while the partition names exactly one; a partition spanning several fails and asks for --deployment. Mutually exclusive with --deployment.
- **--version** (integer): The deployed version to diff against. Defaults to the latest.

### definitions delete: remove a deployed definition

`definitions delete` deletes every deployed version of a definition, or one version with `--version`. Orphaned guard documents are removed only when the delete takes the last remaining version. Deleting one version while others survive leaves them in place.

It refuses while any non-terminal instance is pinned to a targeted version. `--cascade` aborts those instances first and then deletes; the instances are aborted in place and are never deleted, so their history survives. To remove instance documents as well, abort them and then use `nuke`.

**npm**

```shell
npx @sanity/workflow-cli definitions delete article-review \
  --deployment production --cascade --reason 'workflow retired'
```

**pnpm**

```shell
pnpm dlx @sanity/workflow-cli definitions delete article-review \
  --deployment production --cascade --reason 'workflow retired'
```

**yarn**

```shell
yarn dlx @sanity/workflow-cli definitions delete article-review \
  --deployment production --cascade --reason 'workflow retired'
```

**bun**

```shell
bunx @sanity/workflow-cli definitions delete article-review \
  --deployment production --cascade --reason 'workflow retired'
```

**sanity-workflows definitions delete NAME(NAME, --deployment, --partition, --version, --cascade, --reason): Rendered output only**

Delete a deployed workflow definition, optionally aborting the instances still pinned to it.

Parameters:
- **NAME** (string): The workflow definition name.
- **--deployment** (string): Deployment name, the unique identity of one deployment in the config. Mutually exclusive with --partition.
- **--partition** (string): Workflow environment partition, for example prod or test. Selects the deployment to act on while the partition names exactly one; a partition spanning several fails and asks for --deployment. Mutually exclusive with --deployment.
- **--version** (integer): Delete only this deployed version. Defaults to every version.
- **--cascade** (boolean): Abort every non-terminal instance pinned to the targeted versions, then delete. Default false, which refuses the delete while any such instance exists.
- **--reason** (string): Free-text reason, recorded on each cascade-abort history entry.

### nuke: delete engine-owned documents

`nuke` deletes engine-owned documents. With `--deployment` or `--partition` it deletes every instance, definition, and guard under the partition of that deployment, across the workflow resource and every resource its aliases bind. With `--instance <id>` it deletes one terminal instance plus its guards. Content documents are never touched, and a single-instance delete refuses any id whose `_type` is not a workflow instance.

This is a development reset for a dataset holding engine documents the versioned upgrade framework cannot yet migrate. Because it deletes raw documents rather than reading them through the engine, it can clear data an older engine wrote that the current one cannot interpret, which `definitions delete` cannot do. It is not an operational tool, and there is no undo.

`nuke` always prints a dry-run plan of exactly what it will delete, including under `--force`. Without `--force`, partition mode then asks you to type back every `project.dataset` target space-separated, and instance mode asks a single yes-or-no. A shell that cannot prompt fails rather than blocking. `--instance` refuses an in-flight instance with `Instance is in-flight — abort it first, then delete.` Partition mode also refuses when another deployment shares the partition and a swept resource, because guard ids embed only the partition and the sweep could not tell the two apart.

**npm**

```shell
# Reset one development environment, after reviewing the printed plan
npx @sanity/workflow-cli nuke --deployment plugin-dev

# Delete one finished instance and its guards
npx @sanity/workflow-cli nuke --instance plugin-dev.wf-instance.a1b2c3d4e5f6
```

**pnpm**

```shell
# Reset one development environment, after reviewing the printed plan
pnpm dlx @sanity/workflow-cli nuke --deployment plugin-dev

# Delete one finished instance and its guards
pnpm dlx @sanity/workflow-cli nuke --instance plugin-dev.wf-instance.a1b2c3d4e5f6
```

**yarn**

```shell
# Reset one development environment, after reviewing the printed plan
yarn dlx @sanity/workflow-cli nuke --deployment plugin-dev

# Delete one finished instance and its guards
yarn dlx @sanity/workflow-cli nuke --instance plugin-dev.wf-instance.a1b2c3d4e5f6
```

**bun**

```shell
# Reset one development environment, after reviewing the printed plan
bunx @sanity/workflow-cli nuke --deployment plugin-dev

# Delete one finished instance and its guards
bunx @sanity/workflow-cli nuke --instance plugin-dev.wf-instance.a1b2c3d4e5f6
```

**sanity-workflows nuke(--deployment, --partition, --instance, --force): Rendered output only**

Delete engine-owned documents for a whole deployment partition, or one terminal instance and its guards.

Parameters:
- **--deployment** (string): The deployment name to reset. With --instance, narrows which deployment the instance is looked up in when its partition spans several.
- **--partition** (string): The deployment partition to reset, while it names exactly one deployment. Not valid with --instance, which reads its partition from the instance id.
- **--instance** (string): Delete one terminal instance by id, plus its guard documents, instead of a whole partition. The instance must already be completed or aborted.
- **--force** (boolean): Skip the confirmation prompt, for scripts and CI. Default false. The plan still prints.

## Related reading

- [Configure and deploy workflow definitions](https://www.sanity.io/docs/workflows/deploy-definitions) sets up the CLI and the config every command here reads.
- [Definitions, instances, and stages](https://www.sanity.io/docs/workflows/definitions-and-instances) explains what a version, an instance, and a cascade are.
- [Activities and actions](https://www.sanity.io/docs/workflows/activities-and-actions) explains what `fire-action` and `reset-activity` operate on.
- [Effects and runtimes](https://www.sanity.io/docs/workflows/effects-and-runtimes) explains the queued work `diagnose` reports as a failed or hung effect.
- [Run Workflows with Sanity Functions](https://www.sanity.io/docs/workflows/sanity-functions) covers what advances an instance when nobody is at a terminal.
- [History and audit trail](https://www.sanity.io/docs/workflows/history-and-audit-trail) covers what `tail` streams and what `show --include history` prints.

