Steps

The complete step vocabulary the engine executes: names, order, phase, enforcement, skip rules, artifacts, and the skill each step dispatches. These names are what ai-conductor inline --from <step> accepts.

There are 24 step names: 20 sequential steps in ALL_STEPS and 4 out-of-band steps in OUT_OF_BAND_STEPS. validation and build_verification are step groups wrapping existing steps, not steps themselves — neither can be passed to --from.

Tables on this page are source-ordered (the order of ALL_STEPS), not alphabetized. The order of that array is the flow.

Enforcement levels

Enforcement is a property of the engine’s step definition, not of the skill’s frontmatter. It decides whether the step can be skipped and whether it can be disabled by config.

Level Can be skipped Can be config-disabled Used by
advisory Yes Yes memory, explore, complexity, architecture_diagram, architecture_review, and all four out-of-band steps
gating No Only with configDisableAllowed prd, stories, conflict_check, plan, coherence_check, acceptance_specs, build_review, test_suite, manual_test, prd_audit, architecture_review_as_built, finish
structural No Never — the flag is ignored entirely worktree, build, rebase
mechanical — — Nothing. The level is declared in the type union but no step definition uses it.

Skippability is exactly enforcement !== 'gating'. Tier and track skips (below) are a separate mechanism and apply to gating steps too. For what a gate is and why it fails closed, see gates.

Sequential steps

The 20 steps of ALL_STEPS, in execution order. “Skips” lists tier and track exclusions; see Tier skips and Track skips.

# Step Phase Enforcement Prerequisites Skips Dispatches
0 worktree SETUP structural — — /conduct worktree
1 memory UNDERSTAND advisory — — /memory
2 explore DECIDE advisory — — /explore
3 complexity DECIDE advisory explore — /conduct complexity
4 prd DECIDE gating explore track technical /prd
5 architecture_diagram DECIDE advisory complexity tier S /architecture-diagram
6 architecture_review DECIDE advisory architecture_diagram tier S /architecture-review
7 stories DECIDE gating architecture_review — /stories
8 conflict_check DECIDE gating stories tier S /conflict-check
9 plan DECIDE gating conflict_check — /plan
10 coherence_check DECIDE gating plan tier S /coherence-check
11 acceptance_specs BUILD gating plan tier S /writing-system-tests
12 build BUILD structural plan — /pipeline
13 test_suite BUILD gating build — engine-native
14 build_review BUILD gating test_suite — engine-native
15 manual_test SHIP gating test_suite tier S /manual-test
16 prd_audit SHIP gating manual_test — (runs at every tier and on both tracks; trivially passes when a feature has no acceptance criteria to grade) /prd-audit
17 architecture_review_as_built SHIP gating prd_audit — (runs at every tier; individual checks are conditional on tier and artifact presence, see gates) /architecture-review --as-built
18 rebase SHIP structural architecture_review_as_built — native; /rebase only on conflict
19 finish SHIP gating rebase — /finish

Per phase: SETUP 1, UNDERSTAND 1, DECIDE 9, BUILD 4, SHIP 5.

test_suite is the sole engine-native BUILD verifier. Static wiring reachability is retired. build_review currently runs only its optional testQuality rubric. The engine freezes the base/HEAD source and active feature artifacts, then derives established test regions and concrete uncertain candidates from changed declarations, current-feature-owned Covers bindings introduced or updated after the review base, and relevant shared setup or helper evidence. An unchanged bare marker remains owned by the feature that landed it; a coincidentally matching active-plan ordinal cannot make it current authority. Only a Covers marker in a real comment binds; Covers: text inside a string or template literal is test data, not a marker. The engine does not make every title in a changed marked file a review target. A candidate’s file can be selected for conservative counterfactual execution without making unchanged sibling tests quality targets.

Enabled testQuality with no established targets or concrete candidates is a valid empty-scope PASS: it does not dispatch its reviewer or counterfactual preflight. An enabled security rubric still reviews the diff and participates in the joined verdict. This preserves production-only refactors and pure moves/renames as non-coverage work; the aggregate suite and CI remain responsible for broad regression execution. For each concrete candidate, the normal reviewer returns one source-bound scope resolution: resolved, out-of-scope, or indeterminate. An indeterminate candidate preserves any otherwise valid findings but creates a derived scope-incomplete fault. It follows the existing bounded mechanical-fault and explicit reduced-coverage recovery path rather than inventing a test-insensitive finding or silently passing. See stalled or stuck feature.

Retiring a step safely

Step retirement has two phases: first remove the step’s machinery while retaining its name as a deprecated no-op; only in a later, separate change may the name be deleted, after no live state or consumer configuration can reference it. This preserves in-flight conduct-state.json, configured step keys, historical artifacts, and downstream prerequisites while operators receive an observable deprecation notice. See adr-2026-08-11-deprecated-no-op-step-retirement.

Two steps are checkpoints (isCheckpoint: true) — the engine pauses for the operator after them in default and interactive mode: build and manual_test.

build is the first loopGate step, which makes index 12 the boundary between the front (DECIDE-ish, one-way) region and the gate loop. Everything from build to finish is a loop gate and can be re-entered when a downstream gate kicks back. The kickback targets — the steps a blocking gate can send work back to — are prd, architecture_review, stories, and plan.

Repository-local self-host tail

This repository adds two configured SHIP gates without changing the static ALL_STEPS index: rebase → maintain-documentation → release-disposition → finish. release-disposition is gating, writes the authoritative structured metadata inside its project-owned region on the retained SHIP draft PR, and records only its completion evidence in .pipeline/release-disposition-pass. The later finish step preserves every project-owned region while supplying the reader-facing PR body.

Each region is owned by one configured custom SHIP step and carries opaque body bytes. The engine prepares a missing region before its owner runs, captures the owner’s non-empty result after success, and restores captured regions after PR-body authoring. See the template-region contract.

Before FINISH begins publication, it also checks every configured custom step that occurs earlier in the resolved flow and declares both enforcement: gating and a completion_artifact. Each such step must be done and have a fresh regular-file marker for the current run. A blocked publication names all unsatisfied custom step keys; advisory and structural custom steps, steps without a completion marker, and steps after FINISH are not FINISH publication prerequisites.

Both configured gates read the retained SHIP PR, which the engine adopts at SHIP-phase entry. If that PR is a reused needs-remediation halt placeholder, the engine makes it presentable whenever that identity is resolved — at adoption, at the pre-finish snapshot, or at the finish-time restore — so a SHIP step scheduled ahead of finish never reads a remediation placeholder. A lighter clear also runs once at the start of every dispatch, regardless of phase, so a resumed BUILD step is not left holding the placeholder either. The draft→ready flip remains finish-only. See running the daemon.

Out-of-band steps

These have full step definitions and are dispatchable, but hold no slot in the sequential loop. --from cannot start at them; the engine invokes them itself when a condition fires.

Step Phase Enforcement Prerequisites Dispatches When it runs
bootstrap UNDERSTAND advisory — /bootstrap Prelude, before the loop
assess UNDERSTAND advisory — /assess Prelude; short-circuited when bootstrap_mode is new
remediate SHIP advisory prd_audit /remediate When a SHIP gate blocks (a prd_audit FIXABLE grade or the as-built review’s BLOCKED verdict), or on a build stall
attribution_verify SHIP advisory — engine-native Out-of-band commit-attribution audit

They exist as definitions because getStepDefinition throws Unknown step: <name> without one, and the daemon turns that throw into a .pipeline/HALT. Config-declared custom steps resolve from a third table that buildStepRegistry populates, consulted after these two — see configuration.

The validation group

validation is a StepGroup over three members already present in ALL_STEPS, in this order: manual_test, prd_audit, architecture_review_as_built. It does not remove, replace, or reorder them, and it does not change their state keys.

The group only fans out when all of these hold:

  1. The step belongs to a group.
  2. The run mode is auto. Interactive and default mode never engage the group.
  3. The entry step’s own prerequisite gate passes.
  4. More than one member is dispatchable. A width-1 group degrades silently to the serial path.

Fan-out width is capped by the validation_concurrency config key (default 4, which covers the three-member group in a single wave; see configuration). Branches never write conduct-state.json or .pipeline/gates/* — only the loop thread does, after every branch settles.

The build verification group

test_suite is the sole BUILD verifier. It runs after build and before build_review. After a BUILD repair, it reuses a matching content fingerprint or derives a fresh suite result. Reuse does not consume retry or kickback budget.

Tier skips

Tier S skips 6 steps. Tiers M and L skip none.

Tier Steps skipped
S architecture_diagram, architecture_review, conflict_check, coherence_check, acceptance_specs, manual_test
M none
L none

Tier S additionally disengages the land-time coherence gate entirely.

Steps that are not tier-skippable at any tier include the whole BUILD spine — build, build_review, test_suite — plus plan, stories, prd, rebase, finish, prd_audit, and architecture_review_as_built. The latter two used to tier-skip at S; they now run at every tier, with only their individual checks (as-built) or applicability (whether any acceptance criterion changed, prd_audit) conditional — see gates.

A skipped step is marked skipped, which satisfies downstream prerequisites. The chain never breaks because of a skip.

Where the tier comes from

Three separate paths resolve a feature’s tier, and each has its own fallback. They are not reconciled with one another — the path in play decides which fallback you get.

Path Where the tier is read When no tier is found
Daemon dispatch .docs/complexity/<slug>.md on the base-branch tree, via the Tier: <S\|M\|L> line; a dated slug falls back once to the date-stripped stem when that stem is unambiguous M — the daemon’s own fallback for an absent or garbled marker, logged once per slug with the paths tried
ai-conductor inline --interactive, and the default run mode The persisted tier, else the complexity step’s assessment, confirmed by the operator L, when the assessment fails and there is no prompt to fall back on

The marker file is the only durable carrier. A tier chosen in an interactive run reaches a later daemon build only if the complexity step committed .docs/complexity/<slug>.md under the plan stem — or under its date-stripped form, the one relaxation the daemon allows (undated-stem fallback) — because that file is the only thing the daemon looks at. To pin a tier for a daemon build, commit the marker. See artifacts for the marker’s format.

Track skips

The track split touches exactly one step plus one land-gate layer.

Difference product technical
prd (index 4) Runs Skipped — no product requirements to spec
prd_audit (index 17) Runs — stories’ acceptance criteria are the audit key on both tracks; PRD FRs are context only when a PRD exists Runs
Land-time coherence fr layer Required Not required; the layer degrades away

Everything else is identical on both tracks. The track is decided in explore and recorded in .docs/track/<slug>.md, which the daemon reads with the same undated-stem fallback as the tier marker. A missing track resolves to product, so nothing is track-skipped when the track is unknown.

Other skip mechanisms

Mechanism Rule Steps affected
skipWhenSkipped Skip when a named upstream step ended skipped, for any reason The mechanism (shouldSkipForUpstreamSkip) still exists but no current step definition declares it — architecture_review_as_built dropped its use when it stopped mirroring architecture_review’s tier-S skip
Bootstrap mode bootstrap_mode: new skips the step with a mode_skip event assess only
configDisableAllowed Opt-in to steps.<name>.disable: true. Config validation rejects disabling any other gating or structural built-in manual_test only
when: Per-step conditional expression in config. It has the same authority boundary as config disable: advisory steps and the opted-in built-in are allowed; other gating and structural steps are rejected Advisory steps and manual_test

Step artifacts and gate behavior

Each step’s completion gate reads evidence from disk. The engine recomputes verdicts from that evidence rather than trusting an agent’s self-report. Committed artifacts live under .docs/; uncommitted run evidence lives under .pipeline/. See artifacts for file-by-file detail.

Step Evidence Committed What satisfies the gate
worktree — — Prerequisites only; no artifact check
memory — — Prerequisites only
explore — — Prerequisites only. Notes are ephemeral; the track marker is written but is not a completion glob
complexity — — Prerequisites only
prd .docs/specs/*.md yes At least one matching file
architecture_diagram .docs/architecture/*.md yes At least one matching file
architecture_review .docs/decisions/architecture-review-*.md, .docs/decisions/adr-*.md yes At least one matching file
stories .docs/stories/**/*.md yes At least one matching file. The verdict layer additionally requires this feature’s stories doc to carry ### Happy Path and ### Negative Path(s) sections, each with at least one Given/When/Then bullet, and no Status: DRAFT
conflict_check .docs/conflicts/*.md yes At least one matching file
plan .docs/plans/*.md yes At least one matching file. The verdict layer additionally requires every story unit in this feature’s plan to be covered by at least one task, and fails when the feature’s plan cannot be resolved among several
coherence_check .docs/coherence/*.md yes At least one matching file, named with the plan’s filename stem
acceptance_specs spec files in the project’s test dirs, plus .pipeline/acceptance-specs-red.json specs yes, evidence no At least one spec file and RED evidence proving the feature’s own specs ran and failed. A spec that was skipped, deselected, or hit a collection error does not establish RED
build .pipeline/task-status.json no No .pipeline/halt-user-input-required marker, every task completed or skipped, and a clean working tree whenever the status probe establishes one. The post-rebase closure applies the same conjunct: a reapplied autostash blocks BUILD until the named paths are committed or discarded. An absent or failed probe fails open to the legacy behavior. Task status is re-seeded and re-derived on each evaluation, so forged rows fail
build_review .pipeline/build-review.json no A fresh, valid effective PASS from the enabled rubric set (currently only testQuality, off by default — an empty enabled set is a vacuous PASS). An enabled test-quality rubric with a valid empty typed scope also passes without a reviewer or counterfactual dispatch. Missing, prior-session, malformed, unresolved findings, or uncovered scope-incomplete/infrastructure faults all block. Raw outcomes and valid findings remain recorded; effective dispositions control routing.
test_suite .pipeline/test-suite-evidence.json no A live re-inspection returning CURRENT. File presence alone can never satisfy this gate
manual_test .pipeline/manual-test-results.md no The latest attempt section has no FAIL rows and is fresh. WARN rows record unavailable browser capability without blocking. After a recorded FAIL, HEAD must have moved before a later FAIL-free attempt is accepted
prd_audit .pipeline/prd-audit.md no Fresh audit with exactly one graded verdict row — PASS, FIXABLE, PLAN_GAP, or OVER_SCOPE — for every acceptance criterion across the feature’s stories; a FIXABLE row must name its owning plan task. A no-owner finding belongs in ## Findings without an owning criterion as one unique NC.<n> OVER_SCOPE row; an outside-visible finding blocks until the operator decides it, and that decision binds to its evidence summary. A missing, invalid, or duplicate row blocks with a diagnostic. Verdict rows are read only from the ## Verdict Table section when the report carries that heading, so a narrative table elsewhere (e.g. a prior-cycle history table) cannot be read as a current verdict; a report without the heading is scanned whole. An unresolvable or unreadable criterion set blocks fail-closed
architecture_review_as_built .pipeline/architecture-review-as-built.md no A standalone Verdict: line — optionally decorated as a Markdown heading, such as ### **Verdict: APPROVED** ### — reading APPROVED, APPROVED WITH DRIFT NOTES, or PLAN_GAP with Outcome delivered: yes. A BLOCKED report must carry one ## Blocking Findings table (Finding, Class, Governing clause, Summary): a DESIGN finding halts for a human decision and names its governing clause; an all-REMEDIABLE table may take the enabled bounded remediation route. If that route cannot run or produces no usable plan, its halt names the disabled/non-daemon/planner cause and lists the findings. Malformed or exhausted reports halt needs-human. PLAN_GAP with Outcome delivered: no, missing, or unrecognized evidence also blocks
rebase — — Computed from live git state, not a file
finish .pipeline/finish-choice no A fresh final-outcome marker. Interactive intent is acquired by the foreground prompt host before publication; the coordinator writes pr or keep through finish-record only after the corresponding evidence is coherent. Legacy merge-local and discard markers remain readable but are never synthesized by unattended FINISH
bootstrap, remediate, attribution_verify — — No completion glob. remediate’s output, .pipeline/remediation.json, is read directly by the engine to route
assess .docs/decisions/technical-assessment-*.md yes At least one matching file

Every predicate is fail-closed: missing, stale, malformed, or non-passing evidence leaves the gate unsatisfied. Durable verdicts are written to .pipeline/gates/<step>.json.

A step the engine resolves by skipping never runs its predicate, but it still writes a verdict: {"satisfied": true, "reason": "skipped: <cause>"}. The skipped: prefix marks a gate that was deliberately not run, so it is never mistaken for evidence that passed. This covers every skip — tier, track, bootstrap mode, upstream skip, disable: true, a false when:, and an advisory step auto-skipped after a failed completion check (whose reason carries the failure). See gates.

Starting from a step

--from <step> sets the loop’s starting index by a linear name lookup over the resolved step registry:

ai-conductor inline "<feature description>" --from build

Accepted values are the 20 sequential step names above, in underscore form, plus any custom step name inserted through the steps config key. There is no dash normalization in the engine — --from conflict-check is not the same string as conflict_check.

Known limitation. --from is unvalidated. An unrecognized name resolves to index -1 with no error and no event, and the run proceeds from that index. Check spelling and underscore form before relying on it. Tracked in #1027.

Step-to-skill mapping

Dispatch reads a single map keyed by step name. That map is the authority for what a step invokes; the skillName field on the step definition is not consulted at dispatch time.

Three steps dispatch no skill at all and run entirely in the engine: build_review, test_suite, and attribution_verify. Of these, build_review dispatches its registered rubric set (currently only testQuality) and attribution_verify dispatches its own attribution-audit logic, both from engine code; test_suite is a deterministic aggregate verifier.

Two steps dispatch the conduct skill with an argument rather than a skill of their own name: worktree runs /conduct worktree and complexity runs /conduct complexity.

Known limitation. Two step definitions carry a skillName naming a skill directory that does not exist: worktree declares skillName: 'worktree' and attribution_verify declares skillName: 'attribution-verify'. Neither skills/worktree/ nor skills/attribution-verify/ is on disk. Nothing breaks, because dispatch uses the invocation map and the model table uses its own skill-to-step map, but the field misleads anyone reading the step definition. The repository’s integrity suite validates /skill-name references inside SKILL.md files, not skillName fields in TypeScript, so these are unguarded. Tracked in #1018.

  • skills — the catalog of skills these steps dispatch.
  • artifacts — every .docs/ artifact and .pipeline/ state file.
  • gates — what a gate is and why it fails closed.
  • sdlc-phases — why there are five phases, tracks, and tiers.
  • cli — every command and flag, including --from.
  • configuration — disabling steps, custom steps, validation_concurrency.

This site uses Just the Docs, a documentation theme for Jekyll.