SODA's pipeline is fully configurable. You can add, remove, or reorder phases; swap models per phase; scope tools per phase; and add conditional logic to skip phases based on ticket metadata. This guide walks you through building a custom pipeline from scratch.
| Name | Phases | Use case |
|---|---|---|
default |
triage → plan → implement → verify → review → submit → monitor | Full pipeline for standard tickets |
quick-fix |
implement → verify → submit | Small, well-understood fixes |
docs-only |
plan → implement → submit | Documentation changes (Sonnet) |
soda pipelines # list all available pipelines
soda run 42 # use the default pipeline
soda run 42 --pipeline quick-fix
soda run 42 --pipeline docs-onlysoda pipelines new my-pipeline # creates phases-my-pipeline.yaml in the current directory
soda pipelines new my-pipeline --global # creates ~/.config/soda/phases-my-pipeline.yamlA pipeline file is a list of phase definitions. Each phase specifies its tools, timeout, model, and (optionally) conditional logic.
Minimal pipeline (3 phases):
phases:
- name: implement
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 25m
- name: verify
tools: [Read, Glob, Grep, Bash]
timeout: 8m
- name: submit
tools: ["Bash(git:*)", "Bash(gh:*)"]
timeout: 3msoda run 42 --pipeline my-pipelineSODA resolves the pipeline by checking .pipelines/my-pipeline.yaml first (if
pipelines_path is configured), then phases-my-pipeline.yaml in the current
directory, then ~/.config/soda/phases-my-pipeline.yaml, then embedded defaults.
phases:
- name: string # phase identifier; used in logs, state files, and artifacts
type: string # "corrective", "post-submit", "parallel-review", "polling"
# omit for a normal forward phase
prompt: string # prompt template path (e.g. "prompts/implement.md")
# omit to use the auto-resolved embedded default for this phase name
model: string # per-phase model override
# omit to use the global model from soda.yaml
tools: [string] # allowed tools list passed to Claude Code as --allowed-tools
timeout: duration # phase timeout (e.g. "25m", "3m")
condition: string # Go template expression; phase is skipped when it evaluates to "false"
# (see Conditional phases cookbook below)
depends_on: [string] # phase names that must complete before this phase runs
feedback_from: [string] # upstream phases whose output is injected as rework feedback
retry:
transient: int # retries for transient API errors (default: 2)
parse: int # retries when output fails JSON schema validation (default: 1)
semantic: int # retries when output is valid but semantically wrong (default: 1)| Tool | What it allows |
|---|---|
Read |
Read files |
Write |
Write files |
Edit |
In-place edits |
Glob |
File pattern matching |
Grep |
Content search |
Bash |
Unrestricted shell |
Bash(git:*) |
Git subcommands only |
Bash(gh:*) |
GitHub CLI only |
Bash(glab:*) |
GitLab CLI only |
Bash(ls:*) |
Directory listing only |
Bash(go test:*) |
Go test invocations only |
Use the condition field to skip a phase based on ticket metadata. The
condition is a Go template expression evaluated against pipeline state; the
phase is skipped when the expression evaluates to the string "false".
Available template variables mirror the PromptData struct — see
docs/configuration.md for the full list.
The most useful ones for conditions are:
| Variable | Type | Example values |
|---|---|---|
{{.Complexity}} |
string | "low", "medium", "high" |
{{.TicketType}} |
string | "bug", "feature", "docs" |
{{.Artifacts.Triage}} |
JSON string | triage output (parsed by template funcs) |
When triage classifies a ticket as low complexity, skip the planning phase —
the implementation is straightforward enough to go straight to code.
- name: plan
condition: '{{ ne .Complexity "low" }}'
tools: [Read, Glob, Grep, "Bash(git:*)"]
timeout: 8mDocumentation changes rarely need code review from specialist agents. Skip the
review phase when the ticket type is docs.
- name: review
condition: '{{ ne .TicketType "docs" }}'
type: parallel-review
timeout: 12m
reviewers:
- name: go-specialist
prompt: prompts/review-go.mdSpecialist AI harness review is expensive. Reserve it for complex tickets where prompt engineering is most likely to be the failure mode.
- name: review
type: parallel-review
reviewers:
- name: go-specialist
prompt: prompts/review-go.md
- name: ai-harness
prompt: prompts/review-ai-harness.md
condition: '{{ eq .Complexity "high" }}'Quick fixes don't need continuous PR monitoring — just submit and move on. Omit the monitor phase entirely from the pipeline definition.
phases:
- name: implement
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 25m
- name: verify
tools: [Read, Glob, Grep, Bash]
timeout: 8m
- name: submit
tools: ["Bash(git:*)", "Bash(gh:*)"]
timeout: 3m
# monitor phase omitted — pipeline ends after submitUse fast, cheap models for triage and submit; reserve the most capable model for implement and review.
phases:
- name: triage
model: claude-sonnet-4-20250514 # fast and cheap for classification
tools: [Read, Glob, Grep, "Bash(git:*)", "Bash(ls:*)"]
timeout: 3m
- name: plan
model: claude-sonnet-4-20250514
tools: [Read, Glob, Grep, "Bash(git:*)"]
timeout: 8m
- name: implement
# no model override — uses global model (e.g. Opus) from soda.yaml
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 25m
- name: verify
# no model override
tools: [Read, Glob, Grep, Bash]
timeout: 8m
- name: submit
model: claude-sonnet-4-20250514 # no heavy reasoning needed for submission
tools: ["Bash(git:*)", "Bash(gh:*)"]
timeout: 3mSet the global model in soda.yaml:
model: claude-opus-4-20251101 # used for phases with no per-phase overrideThe corrective patch phase can use a cheaper model for targeted fixes, falling back to the global model for full implement escalation.
- name: patch
type: corrective
model: claude-sonnet-4-20250514 # fast targeted fixes
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 8mThis is the default pipeline's approach — Sonnet for quick targeted fixes, Opus reserved for full implement sessions.
Different reviewers can use different models:
- name: review
type: parallel-review
reviewers:
- name: go-specialist
prompt: prompts/review-go.md
# no model override — uses global model
- name: ai-harness
prompt: prompts/review-ai-harness.md
model: claude-sonnet-4-20250514 # cheaper for harness review
- name: sre
prompt: prompts/review-sre.md
model: claude-sonnet-4-20250514Skips triage, plan, review, and monitor. Assumes you know what to fix. Use when you've diagnosed the problem and want to automate the mechanical work.
phases:
- name: implement
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 15m
retry:
transient: 2
parse: 1
semantic: 0 # fail fast — no semantic retry on implement
- name: verify
tools: [Read, Glob, Grep, Bash]
timeout: 8m
corrective:
phase: patch
max_attempts: 1
on_exhausted: stop
- name: patch
type: corrective
model: claude-sonnet-4-20250514
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 8m
- name: submit
tools: ["Bash(git:*)", "Bash(gh:*)"]
timeout: 3mWhen to use: Bug fixes where you've already diagnosed the problem. API changes with obvious call-site updates. Dependency upgrades with known migration paths.
Uses Sonnet throughout (docs don't need Opus). Skips triage and all testing/review phases.
phases:
- name: plan
model: claude-sonnet-4-20250514
tools: [Read, Glob, Grep, "Bash(git:*)"]
timeout: 5m
- name: implement
model: claude-sonnet-4-20250514
tools: [Read, Write, Edit, Glob, Grep, Bash]
timeout: 10m
- name: submit
model: claude-sonnet-4-20250514
tools: ["Bash(git:*)", "Bash(gh:*)"]
timeout: 3mWhen to use: README updates, changelog entries, docstring improvements, configuration reference updates. Any change where the test suite doesn't cover correctness of the output.
The pipeline-architect agent is a design-only Claude Code agent that proposes
a custom pipeline configuration based on your project and requirements. It
analyzes your tech stack and suggests phases, reviewers, timeouts, and model
selection calibrated to your codebase.
Install the SODA plugin first:
soda plugin installThen, in a Claude Code session:
@pipeline-architect I need a pipeline for reviewing and merging dependency
updates. Run tests, check for breaking changes, and submit without full review.
The agent outputs a complete phases-<name>.yaml you can copy into your
project and run immediately with soda run <ticket> --pipeline <name>.
Note: The pipeline-architect agent only designs pipelines — it does not execute them. It will not write any files.
SODA resolves named pipelines in this order (first found wins):
pipelines_pathdirectory (.pipelines/<name>.yaml— flat naming)phases_pathfromsoda.yaml(default pipeline only)- Current working directory (
./phases-<name>.yaml) - User config directory (
~/.config/soda/phases-<name>.yaml) - Embedded defaults (compiled into the binary)
The pipelines_path directory uses flat naming: fast.yaml, docs-only.yaml,
default.yaml. The CWD and user config directory use the phases-<name>.yaml
convention.
Migration note: Projects using
phases-<name>.yamlin the working directory continue to work unchanged. The.pipelines/directory is an optional higher-priority location — runsoda initto scaffold it, then move your pipeline files into.pipelines/using flat names (e.g.phases-fast.yaml→.pipelines/fast.yaml).
For the full phases.yaml field reference including rework routing, corrective
routing, parallel review, and polling configuration, see
docs/configuration.md. For per-phase
details — purpose, structured output, cost data, and failure modes — see
docs/phases.md.