Skip to the content.

Quick start

Docker is the recommended way to run Stageflow: pull the published image and open the console. Install Node when you want the sf command on the machine. Either way you author the stages yourself: Stageflow does not ship built-in stage types.

The image is ghcr.io/tejasghutukade/stageflow. 0.39 is the current minor tag (0.39.0 is that exact release). Each release is also tagged x.y.z and x.y.

docker run --rm --name stageflow \
  -e STAGEFLOW_ALLOW_UNAUTHENTICATED_BIND=1 \
  -p 127.0.0.1:3847:3847 \
  -v stageflow-data:/data \
  ghcr.io/tejasghutukade/stageflow:0.39 \
  sf ui

Open http://127.0.0.1:3847. Go to Settings → Providers and connect a model, then New pipeline on the Pipelines page. Pipelines you save in the console live on the stageflow-data volume, under /data.

The process inside the container binds 0.0.0.0, which is what Docker port publish needs. The -p address keeps the port on this machine, and STAGEFLOW_ALLOW_UNAUTHENTICATED_BIND=1 lets it start without a bearer. Do not publish the port on 0.0.0.0 with that flag set. Pass sf ui because the image command is sf mcp.

To browse a project that is already on the machine, mount it and register that path:

docker run --rm --name stageflow \
  -e STAGEFLOW_ALLOW_UNAUTHENTICATED_BIND=1 \
  -e STAGEFLOW_ENSURE_PROJECT_ROOTS=/project \
  -p 127.0.0.1:3847:3847 \
  -v stageflow-data:/data \
  -v "$PWD":/project \
  ghcr.io/tejasghutukade/stageflow:0.39 \
  sf ui

That project needs the same files as the Node scaffold below (stageflow.yaml, a pipeline, a task), or you create them from the console. Building the image from a git checkout, instead of pulling it, is Docker — Local try.

Node

Use this when you want sf in the shell on the machine.

npm i -g stageflow

1. Scaffold the catalog

In an empty project directory (preferably a git repo), run:

sf init

This creates:

File Purpose
stageflow.yaml Manifest — declares which directories to browse and validate
pipelines/hello.pipeline.yaml Single inline stage pipeline
tasks/hello.task.yaml Task file

Manual alternative — same shape without sf init:

stageflow.yaml

version: 1
catalog:
  pipelines:
    - pipelines
    - workshop
  tasks:
    - tasks
    - workshop
  patterns:
    pipeline: "*.pipeline.yaml"
    task: "*.task.yaml"

workshop is the scan root for pipelines saved from Workshop Author. The directory is created on the first save.

pipelines/hello.pipeline.yaml

id: hello
stages:
  - id: hello
    system_prompt: Say hello and emit a success envelope.
    model: CHANGE_ME/<provider-model>

sf init fills model from the single configured provider when one is logged in (for example openrouter/auto or anthropic/claude-sonnet-4-5). With none or more than one configured provider, it writes the loud placeholder CHANGE_ME/<provider-model> — replace it before running.

tasks/hello.task.yaml

id: hello
goal: Run the hello pipeline scaffold.

Stages are object entries with inline bodies or uses: paths — not bare string ids. Author contracts with io / verify / on_verify_fail — see YAML catalog.

2. Validate the catalog

sf validate --strict

With no flags, sf validate checks all pipelines and tasks declared in stageflow.yaml (manifest-all), plus the stages those pipelines reference. --strict promotes manifest warnings (missing manifest, empty catalog) to errors.

It does not prove provider auth or checkout paths.

3. Connect a provider

Either open the operator console:

sf ui

Go to Settings → Providers and connect a model, or use the CLI:

sf providers list
sf providers login anthropic --type api_key --api-key-env ANTHROPIC_API_KEY

See Providers for pi_home vs sf_owned credential storage.

4. Run the pipeline

sf run --pipeline pipelines/hello.pipeline.yaml --task tasks/hello.task.yaml

--pipeline and --task require filesystem paths — there is no bare-id fallback.

sf run is an HTTP client of a single global Stageflow service shared by every project on the machine — it auto-starts that service (headless, no browser) the first time anything needs it, and reuses it if sf ui/sf mcp is already running. Each stage runs in a fresh Pi session. When the stage agent finishes, it must call emit_stage_envelope once (see Envelopes). On success the pipeline completes and run state is stored under the global durable root ($STAGEFLOW_HOME, default ~/.stageflow/) — one shared store for every project, not a per-project .stageflow/ folder. See Data directory. Pipeline/task catalog resolution (stageflow.yaml, pipelines/, tasks/) still stays project-local, resolved from whichever git root you're running in.

5. Operate via the console

With sf ui running (default http://127.0.0.1:3847):

Start sf ui before running any pipeline if you want the console open: sf run (or any mutating sf runs command) auto-starts the same global service headlessly the first time it's needed, and a second process can't then bind the console to that already-occupied port. Running sf ui first — as in step 3 above — avoids this; it becomes the one running instance everything else talks to.

If a stage calls ask_operator, the run pauses until you reply in the console. See Human-in-the-loop.

CLI smoke vs MCP smoke

CLI smoke path

  1. sf init (or author the three files above)
  2. sf providers list / sf providers login …
  3. sf validate --strict
  4. sf run --pipeline pipelines/hello.pipeline.yaml --task tasks/hello.task.yaml

MCP smoke path

  1. Start a Host: sf ui or sf mcp (default http://127.0.0.1:3847)
  2. Ensure/register the catalog folder (POST /api/projects on trusted loopback, or a prior local sf run ensure) — or use seeded project_root: "examples"
  3. MCP: list_pipelines (catalog-relative paths; absolute paths → absolute_path_not_allowed) → start_run → wait_run
  4. Compare homes/providers with get_health (stageflow_home, boot_providers) and live auth via list_providers

Details: MCP. Setup skill checklist: skills/stageflow-setup/SKILL.md.

For MCP without the console, use sf mcp — see MCP.

Multi-stage pipelines

Add more stage entries to the pipeline. Use uses: for external stage files or inline system_prompt / model. Declare wiring on the source stage with route:

id: linear
stages:
  - id: clarify
    uses: ../stages/clarify.yaml
    entry: true
    route:
      - to: design-doc
  - id: design-doc
    uses: ../stages/design-doc.yaml

Canonical example: tests/fixtures/pipelines/linear-explicit.pipeline.yaml.

Multiple to: entries are unconditional fan-out — every listed target runs. See tests/fixtures/pipelines/parallel-after-clarify.pipeline.yaml and YAML catalog — route. Success vs failure uses on: on the source stage.

Headless / CI

sf validate --strict --json
sf run --pipeline pipelines/hello.pipeline.yaml --task tasks/hello.task.yaml --json

Exit codes: 0 success, 1 failure, 2 waiting on HITL. Details in CI / headless.

See also

Older catalogs: upgrading — sf migrate-yaml converts contract keys (io / verify / on_verify_fail); wiring (needs / fork / feedback_loop) is a hard cutover to route (optional STAGEFLOW_LEGACY_YAML=0 after the contract migrate).