> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pinework.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflow

> A workflow is a stored program of agent and gate steps. Each start makes a workflow run that dispatches one run per step.

A workflow is a JavaScript program that runs agent steps and gate steps in order. A stored workflow has an `flw_` id, but commands address it by its `name`. Each start makes a workflow run with an `flr_` id. For the steps, see [Run a workflow](/guides/run-a-workflow).

## States

A workflow run has one `status`.

| State | Meaning | Ends here |
| - | - | - |
| `running` | The program is running or waiting on a step, a question or a check wait. | No |
| `completed` | The program finished and reported success. | Yes |
| `failed` | The program reported failure, the engine refused the start, or a person cancelled a stalled run. | Yes |
| `stalled` | A finished step's result did not reach the program. A question waits on a person. | No |

| From | To | Trigger |
| - | - | - |
| None | `running` | `workflow start`, or a GitHub fire of an automation with a `workflow` |
| `running` | `completed` | The program finishes and reports `completed`. |
| `running` | `failed` | The program reports `failed`, or the engine refuses the start. |
| `running` | `failed` | It started over 10 minutes ago. No step, question or check wait was open or changed in the last 10 minutes. |
| `running` | `stalled` | A step's run ended over 2 minutes ago and 3 resends did not move the program. |
| `stalled` | `running` | A person answers the stall question with retry. |
| `stalled` | `failed` | A person answers the stall question with cancel. |

Each step has a `state` derived from timestamps. It is not stored.

| Step `state` | Meaning |
| - | - |
| `dispatched` | The step's run has not ended. |
| `waiting` | The run ended. Pinework has not sent its result to the program yet. |
| `resumed` | Pinework sent the result. The program has not moved on yet. |
| `done` | The program took the result and moved on. |

A retired workflow cannot start. Its past runs still show and in-flight runs still finish.

## Fields

The workflow run, from `GET /api/v1/workflows/runs/:workflowRunId`:

<ResponseField name="id" type="string" required>Workflow run id, `flr_` plus 16 characters.</ResponseField>
<ResponseField name="object" type="string" required>Always `workflow_run`.</ResponseField>
<ResponseField name="workflow" type="string" required>Name of the workflow it runs.</ResponseField>
<ResponseField name="status" type="string" required>`running`, `completed`, `failed` or `stalled`.</ResponseField>
<ResponseField name="input" type="object" required>The inputs it started with.</ResponseField>
<ResponseField name="summary" type="string">Closing summary. Null until the program sets one.</ResponseField>
<ResponseField name="task" type="object">The task it is tied to, with `id` and `title`. Null when there is none.</ResponseField>
<ResponseField name="parkedQuestion" type="object">Open question with `id`, `prompt`, `options` and `askedAt`. Null when nothing waits on a person.</ResponseField>
<ResponseField name="parkedChecks" type="object">A wait on a branch's pull request checks, with `branch`, `deadlineAt` and `checks`. Null when not waiting.</ResponseField>
<ResponseField name="startedAt" type="string" required>ISO 8601.</ResponseField>
<ResponseField name="completedAt" type="string">ISO 8601. Null while running or stalled.</ResponseField>

<ResponseField name="steps" type="object[]" required>
  One row per dispatched step, in order.

  <Expandable title="step">
    <ResponseField name="stepOrdinal" type="integer" required>Position in the run, from 0.</ResponseField>
    <ResponseField name="state" type="string" required>`dispatched`, `waiting`, `resumed` or `done`.</ResponseField>
    <ResponseField name="label" type="string">Step label. Null when unset.</ResponseField>
    <ResponseField name="phase" type="string">Phase name. Null when unset.</ResponseField>
    <ResponseField name="run" type="object" required>The run it dispatched, with `id`, `status`, `error` and `exitReason`.</ResponseField>
    <ResponseField name="agent" type="object" required>The agent, with `id`, `name` and `handle`.</ResponseField>
    <ResponseField name="resumeAttempts" type="integer" required>How many times Pinework resent the result.</ResponseField>
    <ResponseField name="pendingApproval" type="object">Approval the step waits on. Null when none.</ResponseField>
    <ResponseField name="gate" type="object">For a gate step, `argv`, `exitCode`, `output`, `cwd` and `ranArgv`. Null for an agent step.</ResponseField>
    <ResponseField name="dispatchedAt" type="string" required>ISO 8601.</ResponseField>
    <ResponseField name="advancedAt" type="string">When the program moved on. Null until then.</ResponseField>
  </Expandable>
</ResponseField>

`POST /api/v1/workflows/runs` returns the same object with `taskId` in place of `task`, and no `steps`.

The workflow, from `GET /api/v1/workflows/records/:name`:

<ResponseField name="id" type="string" required>Workflow id, `flw_` prefix.</ResponseField>
<ResponseField name="name" type="string" required>`meta.name` from the program, lower\_snake\_case.</ResponseField>
<ResponseField name="title" type="string" required>`meta.title`.</ResponseField>
<ResponseField name="description" type="string">`meta.description`. Null when unset.</ResponseField>
<ResponseField name="inputs" type="object[]" required>Declared inputs, each with `key`, `label`, `kind` and `required`.</ResponseField>
<ResponseField name="toolPermissionMode" type="string" required>`ask` or `full`. The default for each run.</ResponseField>
<ResponseField name="source" type="string" required>The program text.</ResponseField>
<ResponseField name="version" type="integer" required>Starts at 1. Each update adds 1.</ResponseField>
<ResponseField name="author" type="object">Author agent, with `id`, `name` and `handle`. Null when a person created it.</ResponseField>
<ResponseField name="retiredAt" type="string">Retire time. Null while live.</ResponseField>
<ResponseField name="createdAt" type="string" required>ISO 8601.</ResponseField>
<ResponseField name="updatedAt" type="string" required>ISO 8601.</ResponseField>

`workflow list` rows also cover built-in programs. Those rows have a null `id` and `version`. Each row adds `lastRun` and `runCount`.

## CLI

| Command | Does |
| - | - |
| `workflow catalog` | List the built-in programs and the inputs each needs. |
| `workflow list` | List this workspace's workflows, built-in ones included. |
| `workflow get <name>` | Show one workflow with its program source. |
| `workflow create --file <program.js>` | Save a workflow. The name comes from the program's `meta`. |
| `workflow update <name> --file <program.js>` | Replace the program and bump `version`. In-flight runs keep the old program. |
| `workflow delete <name>` | Retire a workflow. |
| `workflow start <name>` | Start a run. Pass `--input key=value` per input, `--mode ask\|full` and `--task`. |
| `workflow runs list` | List workflow runs. Filter with `--status`. |
| `workflow runs get <flr_…>` | Show one workflow run with its steps. |

```bash theme={null}
pinework workflow catalog
pinework workflow start single_agent_step --input agentId=agt_3hR7pV2nQ8sLk5Wd \
  --input prompt="List the open pull requests by age." --mode ask --task PIN-1042
pinework workflow runs list --status stalled
pinework workflow runs get flr_Q2w9Lm4Xc7Rt1Bz8
```

## API

| Method | Path | Does |
| - | - | - |
| `POST` | `/api/v1/workflows/runs` | Start a run. Body: `workflow`, `input`, `taskId`, `toolPermissionMode`. |
| `GET` | `/api/v1/workflows/runs` | List runs. Query: `status`, `workflow`, `limit`, `cursor`. |
| `GET` | `/api/v1/workflows/runs/:workflowRunId` | Retrieve one run with its steps. |
| `GET` | `/api/v1/workflows/catalog` | List the built-in programs and their inputs. |
| `GET` | `/api/v1/workflows/source?workflow=<name>` | Read a built-in program's source. |
| `GET` | `/api/v1/workflows/records` | List this workspace's workflows with run activity. |
| `POST` | `/api/v1/workflows/records` | Save a workflow. Body: `source`. |
| `GET` | `/api/v1/workflows/records/:name` | Retrieve one workflow and its program. |
| `PATCH` | `/api/v1/workflows/records/:name` | Replace the program and bump `version`. Body: `source`. |
| `DELETE` | `/api/v1/workflows/records/:name` | Retire a workflow. Retiring twice returns the same object. |

`toolPermissionMode` null means the workflow's default. A stored workflow's steps default to its author agent. With no author, they default to the agent that started it.

## Errors

| Code | HTTP | When | What to do |
| - | - | - | - |
| `validation_error` | 400 | The workflow is retired, a required input is missing, or `input.taskRef` and `taskId` disagree. | Read the message. Run `workflow get <name>` for the inputs. |
| `workflow_name_taken` | 409 | A workflow with that `meta.name` exists. | Use `workflow update`. |
| `workflow_name_mismatch` | 400 | The program's `meta.name` differs from the name you update. | Create a new workflow and retire the old one. |
| `workflow_syntax` | 400 | The program does not parse. | Fix the syntax error in the message. |
| `workflow_import` | 400 | The program has an import. | Remove it. |
| `workflow_banned_global` | 400 | The program uses a banned global, such as `fetch`, `setTimeout` or `process`. | Use the step API instead. |
| `workflow_meta_missing` | 400 | The program exports no `meta`. | Export a `meta` object. |
| `workflow_meta_not_literal` | 400 | `meta` is not a plain literal. | Write `meta` as an object literal. |
| `workflow_meta_invalid` | 400 | `meta` fails its schema. | Fix the field the message names. |
| `workflows_not_configured` | 503 | This deployment has no workflows engine. | Contact the operator. |
| `workflows_catalog_unavailable` | 502 | The engine did not answer the catalog call. | Retry later. |
| `workflow_source_unavailable` | 502 | The engine did not answer the source call. | Retry later. |

An unknown workflow name or run id returns `404 resource_not_found`. See [API errors](/reference/api#errors) for the shared codes.

## Limits

* A program's `source` is at most 200,000 characters.
* A workflow `name` is at most 128 characters.
* A program declares at most 32 inputs.
* A gate step's timeout is 1 to 3,600 seconds.
* A step result is resent up to 3 times before the run stalls.
* A list page holds 1 to 100 runs, 25 by default.

<CardGroup cols={2}>
  <Card title="Run a workflow" href="/guides/run-a-workflow">
    Start a workflow and watch each step.
  </Card>

  <Card title="Run" href="/reference/run">
    The run each step dispatches.
  </Card>

  <Card title="Automation" href="/reference/automation">
    Start a workflow from a GitHub event.
  </Card>

  <Card title="Question" href="/reference/question">
    How a stalled or parked workflow asks a person.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.