Guides

Workflows

A workflow is a named, ordered sequence of ananke/apm commands, saved once and run together with a single command. It’s the same commands you’d type by hand — bundled so a newcomer, a CI job, or a future you doesn’t have to remember (or re-type) the sequence.

flowchart LR
    FILE["📄 .ananke/workflows/NAME.toml"] --> RUN["ananke workflow run NAME"]
    RUN --> S1["Step 1"] --> S2["Step 2"] --> S3["Step 3 …"]
    S1 -. fails, no continue_on_error .-> STOP["✗ stop, exit 1"]

Quick start

ananke workflow install-pack setup     # a built-in preset
ananke workflow show setup             # see what it does before running it
ananke workflow run setup              # init → doctor → baseline policy → git hooks

Built-in presets

PresetWhat it runs
setupinit → doctor (soft) → policy install-pack baseline → hooks install all
verify-alldoctor (soft) → verify → policy check → registry verify (soft)
registry-bootstrapregistry init → registry learn ${source} → sync — needs --set source=PATH --set namespace=NAME --set license=SPDX

“soft” steps have continue_on_error = true: diagnostics and optional subsystems don’t abort the rest of the workflow.

ananke workflow install-pack verify-all
ananke workflow run verify-all                              # same gates CI runs, one command

ananke workflow install-pack registry-bootstrap
ananke workflow run registry-bootstrap \
  --set source=./skills/graph-review --set namespace=core --set license=Apache-2.0

Writing your own

ananke workflow create release-check \
  --step "ananke verify" \
  --step "ananke policy check" \
  --step "ananke registry verify" \
  --description "What I run before tagging a release"

ananke workflow run release-check

This writes .ananke/workflows/release-check.toml — plain, deterministic TOML, meant to be committed and reviewed like any other project file:

name = "release-check"
description = "What I run before tagging a release"

[[steps]]
description = ""
command = ["ananke", "verify"]
continue_on_error = false

[[steps]]
description = ""
command = ["ananke", "policy", "check"]
continue_on_error = false

[[steps]]
description = ""
command = ["ananke", "registry", "verify"]
continue_on_error = false

You can also write the file directly — command is always an argv list, one element per word, never a shell string (no &&, |, or quoting rules to fight with).

Variables

A step’s command can reference ${name} placeholders. ${project} is always available (the --project a workflow was run with); anything else comes from --set name=value:

ananke workflow run registry-bootstrap --set source=./skills/x --set namespace=core --set license=MIT

A placeholder with nothing supplied for it is a hard error for that step — it is never passed through literally as the string ${source}. The step that referenced it fails, later steps are skipped (unless the workflow continues past failures — see below), and the run exits 1.

Failure handling

By default, workflow run stops at the first failing step and every step after it is reported as skipped. Mark a specific step continue_on_error = true (in the TOML, there’s no CLI flag for it — it’s a property of the step, not the run) to let the workflow keep going past it; the overall run still reports ok=false and exits 1 if any step failed, soft or not.

ananke workflow run setup --dry-run     # show exactly what would run, run nothing
ananke workflow run setup --json        # machine-readable step-by-step result

Reference

CommandWhat it does
ananke workflow list [--json]List workflows saved under .ananke/workflows/
ananke workflow show NAME [--json]Print a workflow’s steps
ananke workflow create NAME --step "..." [--step "..."]… [--description] [--force]Build a workflow from one or more --step commands
ananke workflow install-pack NAME [--force]Install a built-in preset (setup, verify-all, registry-bootstrap)
ananke workflow run NAME [--set K=V]… [--dry-run] [--json]Run all steps in order
ananke workflow delete NAMERemove a saved workflow

How it runs

Each step is executed exactly as if you’d typed it: subprocess.run(argv, shell=False, cwd=project) — no shell is ever invoked, so there is no shell-metacharacter or injection surface, and no PATH-dependent &&/| chaining between steps (a workflow is the chain). A step’s stdout/stderr are captured and shown only on failure (or in full under --json), so a passing run stays quiet.

What this isn’t (yet)

Workflows don’t call each other (no composition), don’t branch or loop, and have no per-step timeout override (a fixed 900s applies to every step). If you need real branching logic, write a script and add it as a single step — a workflow is a sequence, not a scripting language.

Edit this page on GitHub ↗