# Workflows Workflows are multi-stage processes with team assignment, validation gates, SLA enforcement, and optional Starlark automation. They are managed in **Team Admin > Workflows**. ## Core concepts | Concept | Description | |---------|-------------| | **Definition** | A named template: stages, entry mode, staleness timeout. Created per-team or adopted from global definitions. | | **Stage** | One step in the workflow. Has a mode, audience, optional team assignment, and optional SLA. | | **Instance** | A running copy of a definition. Pins a published version snapshot and tracks accumulated stage data. | | **Assignment** | A queue entry linking an instance stage to a team member. Claim → work → complete. | | **Signoff** | An approval or rejection recorded against an instance stage (multi-party validation). | ## Entry modes | Mode | Description | |------|-------------| | `team_only` | Only authenticated team members can start instances. | | `public_link` | Anyone with the public URL can start an instance. The first stage must have `audience: public`. An `entry_token` is issued for the anonymous submitter to resume later. | Public entry URL format: ``` {origin}/api/v1/public/workflows/{workflow_id}/start ``` ## Stage modes Each stage has a **mode** that determines how it progresses: | Mode | Description | |------|-------------| | `form` | User submits structured data. Stage data is accumulated into the instance. | | `review` | Multi-party sign-off gate. Requires configured approvals before advancing. | | `delegated` | Assigned to a team member queue. The assignee claims, works, and completes. | | `automated` | Starlark hook executes without user interaction. Can chain up to 10 consecutive automated stages. | ## Stage types | Type | Description | |------|-------------| | `simple` | Linear — always advances to the next ordinal. | | `dynamic` | Conditional — evaluates branch rules against stage data to pick the next stage. | | `automated` | Combined with mode `automated` for fully scripted stages. | ## Audiences | Audience | Description | |----------|-------------| | `team` | Only authenticated team members can interact. | | `public` | Anonymous users can interact (used with `public_link` entry). | | `system` | System-generated stages, no direct user interaction. | ## Team assignment When a stage has `assignment_team_id` set, the engine creates an **assignment** record: 1. Assignment enters the queue with status `unassigned`. 2. A team member **claims** the assignment (status → `claimed`). 3. The assignee works the stage and **completes** it (status → `completed`). 4. The engine auto-advances to the next stage. A **required role** can restrict who may claim: - Set `stage_config.required_role` to a team role name (e.g. `"reviewer"`). - Only members with that role can claim the assignment. Team roles are configured in **Team Admin > Settings > Roles**. ## Signoff gates (multi-party validation) Review-mode stages can require multiple approvals before advancing. Configure via `stage_config.validation`: ```json { "validation": { "required_approvals": 2, "required_role": "approver", "reject_action": "cancel" } } ``` | Field | Description | |-------|-------------| | `required_approvals` | Minimum approve decisions needed to advance. | | `required_role` | Only members with this team role can sign off. Empty = any member. | | `reject_action` | What happens on rejection: `"cancel"` (default) cancels the instance, or a stage name to reroute. | Each signoff records: user, decision (`approve` or `reject`), optional comment, timestamp. ## SLA enforcement Two timeout mechanisms run in a background scanner (every 5 minutes): ### Per-stage SLA Set `sla_seconds` on a stage. When an instance has been in that stage longer than the threshold: - `sla_breached` flag is set in instance metadata. - A `workflow.sla_breach` WebSocket event is emitted. - The instance is **not** auto-cancelled — breaches are informational. ### Per-workflow staleness Set `staleness_timeout_hours` on the workflow definition. When an instance has not been updated for longer than the threshold: - Instance status is set to `stale`. - All open assignments are cancelled. - A `workflow.stale` WebSocket event is emitted. ## Branch rules Dynamic stages evaluate conditions against accumulated `stage_data` to determine the next stage. Rules are a JSON array on the stage: ```json [ { "field": "priority", "op": "eq", "value": "high", "target_stage": "escalation" }, { "field": "amount", "op": "gt", "value": 10000, "target_stage": "manager-review" } ] ``` First matching rule wins. If no rules match, the next ordinal stage is used. ### Operators | Op | Description | |----|-------------| | `eq` | Equal (string-normalized) | | `neq` | Not equal | | `gt`, `lt`, `gte`, `lte` | Numeric comparisons | | `exists` | Field is present in stage data | | `not_exists` | Field is absent | | `in` | Value is in a list | | `contains` | String contains substring | `target_stage` can be a stage name (case-insensitive) or a numeric ordinal. ## Publishing Workflows have a draft/publish lifecycle: 1. Edit stages and configuration in the workflow editor (draft state). 2. **Publish** creates a versioned snapshot of all stages. 3. New instances pin the latest published version. 4. Editing stages after publishing does not affect running instances. Version numbers auto-increment. The snapshot preserves the complete stage definition array at publish time. ## Starlark hooks Automated stages execute a Starlark script via the `starlark_hook` field: ``` package_id:entry_point ``` For example: `my-automation:on_review` calls the `on_review` function in the `my-automation` package. If no entry point is specified, `on_run` is used. The hook receives a context dict: ```python { "instance_id": "...", "current_stage": "...", "workflow_id": "...", "started_by": "...", "stage_data": { ... } } ``` The hook returns a dict controlling what happens next: | Key | Effect | |-----|--------| | `advance: True` | Auto-advance to the next stage | | `data: { ... }` | Merge into stage data for the next stage | | `error: "msg"` | Set instance status to `error` and halt | Up to 10 consecutive automated stages can chain before the engine stops with an error (cycle guard). See the [Starlark Reference](STARLARK-REFERENCE) for available sandbox modules.