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

# Activity Plan Steps

> Reference for all step kinds in a Kodexa Activity Plan, including how steps materialize at runtime and how status, timing, results, and logs are tracked.

An Activity Plan is a graph of steps. Each step is materialized when an Activity starts, then tracked independently with status, timing, result, logs, and error details.

## Step Anatomy

Every step has the same top-level shape:

```json theme={null}
{
  "slug": "route-invoice",
  "type": "SCRIPT",
  "dependsOn": ["extract"],
  "conditionExpr": "inputs.sourceSystem != 'manual'"
}
```

Each step's type-specific fields live at the **top level of the step**, alongside `slug`, `type`, `dependsOn`, etc. There is no `config:` sub-block.

| Field               | Description                                                                                                                                                                                                                                                       |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `slug`              | Unique identifier for the step inside the Activity Plan                                                                                                                                                                                                           |
| `type`              | The step type discriminator: `CREATE_TASK`, `SCRIPT`, `BRIDGE_CALL`, `EXECUTION`, `LLM`, `AGENT`, or `APPROVAL`                                                                                                                                                   |
| `dependsOn`         | Steps or step actions that must complete before this step can run                                                                                                                                                                                                 |
| `conditionExpr`     | Optional JSONata predicate that must evaluate truthy for the step to run. In a per-document plan it is evaluated per document and can read a `document` object (`document.status`, `document.statusLabel`, `document.locked`, `document.labels`, `document.path`) |
| `setDocumentStatus` | Optional. A document-status slug applied to the document family when the step completes (see [Document Status](#document-status))                                                                                                                                 |

When an Activity starts, Kodexa copies the plan's step graph into Activity-owned step rows. After that, the running Activity uses the materialized steps. Editing the Activity Plan affects future Activities, not Activities already in flight.

## Dependency Patterns

Run after another step completes:

```json theme={null}
[
  {
    "slug": "extract",
    "type": "EXECUTION"
  },
  {
    "slug": "route",
    "type": "SCRIPT",
    "dependsOn": ["extract"]
  }
]
```

Run only after a specific action:

```json theme={null}
{
  "slug": "analyst-review",
  "type": "CREATE_TASK",
  "dependsOn": ["route:review"]
}
```

Join multiple paths:

```json theme={null}
{
  "slug": "finalize",
  "type": "BRIDGE_CALL",
  "dependsOn": ["auto-approve", "analyst-review:approved"]
}
```

Use action-qualified dependencies when a step can produce more than one outcome. This keeps the graph explicit: the routing decision lives on the upstream step, and the downstream step declares which outcome it depends on.

The token after the colon (`route:review`) is the upstream action's **slug** — the stable identity declared on `scriptActions[].slug`, `promptActions[].slug`, `bridgeActions[].slug`, or a CREATE\_TASK template's action slug. Older plans use a `uuid` field on the action with the same semantic value; that is the legacy spelling of `slug` and still resolves, but new authoring should use `slug`.

## Document Status

Each document family carries a **status** (a slug such as `pending-review` or `completed`). The `setDocumentStatus` field sets that status when a step completes, and a per-document `conditionExpr` over the `document.*` context lets steps react to it — both declaratively, without writing a SCRIPT step.

### Setting status: `setDocumentStatus`

Add `setDocumentStatus` to any step to stamp the document family's status when that step completes. On a per-document step it applies to the families that completed at that step; on a non-per-document step it applies to every document family in the Activity.

```json theme={null}
{
  "slug": "mark-pending-review",
  "type": "SCRIPT",
  "dependsOn": ["extract"],
  "setDocumentStatus": "pending-review",
  "scriptBody": "return {};"
}
```

This is the first-class equivalent of calling `documents.setStatus(familyId, statusSlug)` inside a SCRIPT — prefer the field for fixed, step-completion status changes, and the script call only when the status is conditional or computed.

### Skipping on status

To skip a step based on the document's current status, gate it with a `conditionExpr` over the per-document `document.*` context. The step is not taken for matching documents, and the steps that depend on it are skipped too.

```json theme={null}
{
  "slug": "prepare-document",
  "type": "EXECUTION",
  "perDocument": true,
  "conditionExpr": "$not(document.status in [\"pending-review\", \"reviewed\", \"completed\"])",
  "moduleRef": "kodexa/prepare"
}
```

A common pattern is "skip to review": add a per-document SCRIPT **router** at the pipeline root that reads `documents.get(families[0].id).status` and returns one of two actions (e.g. `process` / `skip_to_review`). The processing pipeline depends on `router:process`, so already-processed documents are skipped; a separate root depends on `router:skip_to_review` to route them straight to the review task. (A direct `conditionExpr` on the root plus an inverse-gated second root works too.)

<Note>
  `setDocumentStatus` and the `document.*` condition context operate per document, and are only populated in per-document Activity Plans — so a status-based `conditionExpr` has no effect in a plan that is not per-document.
</Note>

## CREATE\_TASK

Use `CREATE_TASK` when the workflow needs human judgment, correction, exception handling, or approval.

```json theme={null}
{
  "slug": "analyst-review",
  "type": "CREATE_TASK",
  "dependsOn": ["route:review"],
  "taskTemplateRef": "invoice-review",
  "taskStatusSlug": "open",
  "waitForCompletion": true,
  "taskData": {
    "priority": "{{inputs.priority}}",
    "documentFamilyId": "{{inputs.documentFamilyId}}"
  }
}
```

| Step field          | Description                                                                |
| ------------------- | -------------------------------------------------------------------------- |
| `taskTemplateRef`   | Task Template used to create the Task                                      |
| `taskStatusSlug`    | Initial Task status                                                        |
| `waitForCompletion` | Whether the Activity should pause until the Task reaches a terminal status |
| `taskData`          | Data copied onto the created Task                                          |

If `waitForCompletion` is true, the Activity waits for the reviewer to complete the Task. The Task's status or action can then drive the next step.

See [Create Task Steps](/guides/activity-plans/create-task-steps) for the full human-work guide.

## SCRIPT

Use `SCRIPT` when the workflow needs custom JavaScript logic.

Good uses:

* Route based on document content or metadata
* Normalize values before review
* Assign knowledge features
* Call several Service Bridges and make a decision
* Prepare inputs for another step

```json theme={null}
{
  "slug": "route",
  "type": "SCRIPT",
  "dependsOn": ["extract"],
  "scriptActions": [
    { "slug": "review", "name": "review" },
    { "slug": "post",   "name": "post" },
    { "slug": "reject", "name": "reject" }
  ],
  "scriptBody": "return { action: inputs.needsReview ? 'review' : 'post' };"
}
```

See [Script Steps](/guides/activity-plans/script-steps) for the full scripting guide.

## BRIDGE\_CALL

Use `BRIDGE_CALL` when the workflow should call an external system as a first-class step.

Good uses:

* Validate extracted data against a system of record
* Post approved data to an ERP, CRM, claims, or lending system
* Fetch enrichment data needed by the next step
* Notify a downstream system when a workflow completes

```json theme={null}
{
  "slug": "post-to-erp",
  "type": "BRIDGE_CALL",
  "dependsOn": ["analyst-review:approved"],
  "serviceBridgeRef": "finance-erp",
  "endpointName": "post-invoice",
  "requestBody": {
    "documentFamilyId": "{{inputs.documentFamilyId}}"
  },
  "treatAsError": "$.status != 'accepted'",
  "timeoutSeconds": 30
}
```

See [Service Bridge Steps](/guides/activity-plans/service-bridge-steps) for the full bridge-step guide.

## EXECUTION

Use `EXECUTION` to run a module or automated processing component.

```json theme={null}
{
  "slug": "extract",
  "type": "EXECUTION",
  "moduleRef": "kodexa/invoice-extractor",
  "options": {
    "documentFamilyId": "{{inputs.documentFamilyId}}"
  },
  "perDocument": true,
  "maxParallel": 4
}
```

| Step field    | Description                                 |
| ------------- | ------------------------------------------- |
| `moduleRef`   | Module to run                               |
| `options`     | Module-specific options                     |
| `perDocument` | Whether to run once per document family     |
| `maxParallel` | Parallelism limit when running per document |

See [Execution Steps](/guides/activity-plans/execution-steps) for the full module execution guide.

## LLM

Use `LLM` for bounded prompt execution where the Activity Plan owns the prompt, inputs, and result mapping.

```json theme={null}
{
  "slug": "summarize-exception",
  "type": "LLM",
  "dependsOn": ["route:review"],
  "promptTemplateRef": "invoice-exception-summary",
  "promptVariables": {
    "documentFamilyId": "{{inputs.documentFamilyId}}"
  },
  "includeDocument": true
}
```

Prefer an `LLM` step for direct prompt execution. Prefer an `AGENT` step when the work requires tool use or multi-step reasoning.

See [LLM Steps](/guides/activity-plans/llm-steps) for the full prompt-step guide.

## AGENT

Use `AGENT` when a bounded part of the Activity should be delegated to an agent runtime.

Typical uses:

* Draft a routine Activity Plan or Data Form
* Investigate a document exception and propose next steps
* Assemble test cases or validation checks
* Use tools to inspect project resources before producing a result

Keep agent steps constrained. The Activity Plan should still define the process boundary, inputs, expected output, and downstream routing.

See [Agent Steps](/guides/activity-plans/agent-steps) for the full agent-step guide.

## APPROVAL

Use `APPROVAL` when a workflow must explicitly pause for authorization before continuing.

```json theme={null}
{
  "slug": "manager-approval",
  "type": "APPROVAL",
  "dependsOn": ["analyst-review:approved"],
  "approverRole": "finance-manager",
  "approvalCriteria": {
    "amountGreaterThan": 10000
  }
}
```

See [Approval Steps](/guides/activity-plans/approval-steps) for approval-gate modeling.

## Choosing Between SCRIPT and BRIDGE\_CALL

| Need                                                                   | Prefer                                |
| ---------------------------------------------------------------------- | ------------------------------------- |
| One configured external API call with clear input and output           | `BRIDGE_CALL`                         |
| Multiple calls, custom branching, or document mutation                 | `SCRIPT` using `serviceBridge.call()` |
| Pure routing or validation logic inside Kodexa                         | `SCRIPT`                              |
| External system update that should be visible as its own workflow step | `BRIDGE_CALL`                         |

Make the graph explain the business process. Use first-class steps for work operators should monitor directly. Use scripts for logic that is naturally internal to a decision.
