Skip to content

Workflows

Colony pipelines are defined as workflows — YAML state machines that control how issues move through the pipeline. Colony ships with one built-in workflow (colony-default) that covers the standard analyze → develop → review → merge lifecycle. You can replace it with a custom workflow per-tenant.

Every workflow file must satisfy schema_version: 1. The top-level keys are:

schema_version: 1
workflow:
id: my-workflow # kebab-case slug, unique identifier
name: "My pipeline" # human-readable label
version: 1 # positive integer, incremented on each change
description: "..." # optional
intake:
initial_state: new # slug of the first state issues enter
trigger_label: colony:enqueue # optional GitHub label that seeds an issue
states:
<slug>:
# ... per-state fields
operator_actions:
<slug>:
# ... per-action fields

State and action keys must be kebab-case slugs: lowercase letters, digits, and hyphens; 1–64 characters; must start with a letter or digit.

The states key is a record of slug → state definition. Each state has the following fields:

FieldRequiredDescription
typeyesState trait — see State traits
executornoWhich executor to run — see ExecutorRef
recoveryyes (if type: blocked)How the state recovers: manual or auto
labelnoGitHub label string for this state (cosmetic)
onnoOutcome → route map — see Outcome routing
transitionsnoArray of state slugs that operators can manually target from this state
hooksnoTerminal-only post-completion hooks — see Hooks

The type field controls the lifecycle semantics of a state:

TraitMeaning
activeWorker picks up a task and runs the state’s executor
blockedIssue is blocked; must declare recovery: manual or recovery: auto
awaiting-humanIssue is waiting for human input; no executor runs
terminalIssue is complete; must not declare executor or transitions

The executor field takes a reference string in one of two forms:

builtin:<name> # e.g. builtin:analyze, builtin:develop
plugin:<package>/<name> # e.g. plugin:colony-content/analyze

Built-in executors are provided by Colony itself. Plugin executors are declared by a registered plugin — see Plugins.

The on key maps executor outcome names to state transitions. Each value is either a plain slug (shorthand) or an explicit route object:

on:
success: ready-for-dev # shorthand: target state slug
escalate_to_planning:
target: planning # explicit object form
outputs: # optional metadata forwarded to the next state
upstream_outcome: scope_overflow

The key noop is reserved and must not appear in on:. The framework handles noop returns without transitioning the issue.

All target slugs in on: must reference states defined in the same workflow definition.

hooks may only be declared on terminal states. They trigger out-of-band tasks after the issue reaches the terminal state:

done:
type: terminal
hooks:
- task_type: retrospect
executor: builtin:retrospect
optional: true # if true, failure does not block the terminal transition
once_per_issue: true # if true, the hook only fires once regardless of reruns

The operator_actions key registers named actions that pipeline operators (humans or MCP tools) can trigger via slash commands. Each action has:

FieldRequiredDescription
descriptionyesHuman-readable label for the action
frameworknotrue marks this as a framework-reserved action (no from/to required)
fromyes (non-framework)Array of source state slugs from which this action is valid
toyes (non-framework)Target state slug
side_effectsnoSide effects to execute: close-pr, add-label, remove-label

Non-framework operator actions must declare both from and to. Framework actions (e.g. retry) are handled by the engine and do not require routing fields.

operator_actions:
retry:
description: "Re-enqueue current state's executor after failure."
framework: true
reimplement:
description: "Discard PR; return to development."
from: [in-review, merge-pending]
to: ready-for-dev
side_effects: [close-pr]

All from and to slugs in operator actions must reference defined states.

The schema enforces the following rules at parse time:

  • intake.initial_state must reference a defined state.
  • States of type blocked must declare recovery.
  • States of type terminal must not declare executor or transitions.
  • noop must not appear as a key in any state’s on: map.
  • hooks may only be declared on terminal states.
  • Every target in on:, transitions, and operator action from/to fields must reference a defined state.

Colony ships with colony-default, the standard analyze → develop → review → merge pipeline. It is the default workflow for all tenants unless overridden.

Key properties:

  • intake.trigger_label: colony:enqueue — adding this label to a GitHub issue seeds it into the pipeline. See First Issue for details.
  • intake.initial_state: new — issues enter the new state, where builtin:analyze runs.
  • States: new, planning, analyzing, needs-clarification, ready-for-dev, dependency-blocked, failure-blocked, changes-requested, in-review, merge-pending, human-review-ready, waiting-for-subtasks, done, paused, unlabeled.
  • Terminal state: done — triggers a retrospect hook (optional, once-per-issue).
  • Operator actions: retry (framework), reimplement, reanalyze, reopen.

To view the full YAML:

Terminal window
colony workflow show --builtin colony-default

The following is the colony-content workflow from packages/sdk/examples/plugin-content-stub/workflow/colony-content.yaml. It illustrates a lean pipeline for content/documentation issues that uses two plugin executors and omits the planning stage.

schema_version: 1
workflow:
id: colony-content
version: 1
name: "Content pipeline"
description: "Lean workflow for content/docs. No planning, no CI gating."
intake:
initial_state: new
trigger_label: colony:enqueue
states:
new:
type: active
executor: plugin:colony-content/analyze
on:
success: drafting
needs_clarification: needs-clarification
no_work_pr_open: human-review-ready
no_work_done: done
failure: failure-blocked
transitions: [drafting, needs-clarification, human-review-ready, done, failure-blocked]
drafting:
type: active
executor: plugin:colony-content/draft
on:
draft_created: review-ready
needs_clarification: needs-clarification
failure: failure-blocked
transitions: [review-ready, needs-clarification, failure-blocked]
review-ready:
type: active
executor: builtin:review
on:
approved: merge-pending
changes_requested: changes-requested
needs_rebase: review-ready
escalate_human: human-review-ready
no_pr: drafting
already_merged: done
failure: failure-blocked
transitions: [merge-pending, changes-requested, review-ready, human-review-ready, drafting, done, failure-blocked]
changes-requested:
type: active
executor: plugin:colony-content/draft
on:
draft_created: review-ready
needs_clarification: needs-clarification
failure: failure-blocked
transitions: [review-ready, needs-clarification, failure-blocked]
merge-pending:
type: active
executor: builtin:merge
on:
merged: done
reimplement_requested: drafting
escalate_human: human-review-ready
needs_rebase: review-ready
not_approved: review-ready
auto_merge_disabled: human-review-ready
failure: failure-blocked
transitions: [done, drafting, human-review-ready, review-ready, failure-blocked]
needs-clarification:
type: awaiting-human
transitions: [new, drafting]
human-review-ready:
type: awaiting-human
transitions: [drafting, done, failure-blocked]
failure-blocked:
type: blocked
recovery: manual
transitions: [new, drafting, done]
done:
type: terminal
operator_actions:
redraft:
description: "Discard draft and start over."
from: [review-ready, merge-pending, changes-requested]
to: drafting
side_effects: [close-pr]
retry:
description: "Retry the last failed step."
framework: true

This workflow uses plugin:colony-content/analyze and plugin:colony-content/draft — executors provided by the colony-content plugin. See Plugins for how to author and register a plugin.

Parse and validate a workflow YAML file against the schema. Exits 0 on success, 2 on parse or validation error.

$ colony workflow validate ./my-workflow.yaml
OK: my-workflow v1
states: 9
operator_actions: 2
content_hash: a3f1...

validate checks the Zod schema and all cross-reference constraints (target states exist, blocked states declare recovery, etc.). It does not verify that every executor outcome declared by a plugin is handled in the workflow’s on: block — that check runs at workflow-load time when the worker starts.

Print a workflow definition as YAML. Two modes:

Built-in workflow (no database required):

Terminal window
colony workflow show --builtin colony-default

Valid --builtin values: colony-default.

Stored workflow (reads from the registry database):

Terminal window
colony workflow show \
--workflow-id my-workflow \
--version 2 \
--tenant-id 42 \
[--database-url postgres://...]

All three of --workflow-id, --version, and --tenant-id are required for registry reads. The database URL is read from --database-url or the $DATABASE_URL environment variable. The command exits 2 if neither mode is fully specified.