Pipeline Orchestrator#
한마디로#
이 문서는 제품을 처음 아이디어부터 출시까지 만드는 과정을, 마치 공장의 컨베이어 벨트처럼 7개의 정해진 단계(발견 → 출시)로 자동 진행해 주는 "총괄 진행자(orchestrator)" 설명서입니다. 요리에 비유하면, 재료 준비부터 손질·조리·플레이팅·서빙까지의 순서를 정리해 둔 레시피이자, 각 단계가 끝날 때마다 "다음 단계로 넘어가도 될 만큼 잘 됐는지" 검사하는 체크포인트(gate)를 두어 품질을 지키는 매니저 역할을 합니다. 각 단계의 결과물(artifact)은 파일로 차곡차곡 저장되므로, 중간에 대화를 새로 시작해도 작업 내용이 사라지지 않습니다. 개발자가 아니어도 "지금 어느 단계까지 왔고, 무엇이 만들어졌는지"를 한눈에 따라갈 수 있도록 돕는 안내서라고 보시면 됩니다.
무엇을·언제#
무엇을 해 주나요
- 제품을 만드는 전 과정을 7단계(발견 → 사양 정의 → 기획 → 설계 → 뼈대 만들기 → 일감 생성 → 개발 → 출시)로 나눠 순서대로 자동으로 진행해 줍니다.
- 각 단계마다 알맞은 도구(플러그인)를 알아서 불러와 일을 시키고, 그 단계의 결과물을
docs/폴더에 파일로 저장해 둡니다. - 저장만 하고 끝내지 않습니다 — 일감 생성 단계가 끝난 시점에 그때까지의 문서를, 출시 단계가 끝난 시점에 출시 문서를 PR 로 올려 팀의 기본 코드 줄기에 합칩니다. 그래야 문서가 작업하던 컴퓨터 한 대에만 남지 않고, 이어지는 개발 작업이 문서가 들어 있는 기준점에서 시작합니다.
- 단계를 넘어가기 전에 "충분히 잘 됐는지" 검사하는 관문(gate)을 두어 품질을 챙기고, 앞 단계의 결과를 다음 단계로 자동으로 넘겨 줍니다.
- 관문 검사에서 떨어지면 그 단계를 최대 2번까지 다시 돌립니다(최초 판정까지 합쳐 총 3번). 그래도 통과하지 못하면 어떤 기준이 미충족인지 그대로 인용해 사용자에게 물어보고 멈춥니다 — 조용히 다음 단계로 넘어가는 일은 없습니다.
- 검사를 아예 할 수 없어 "판정 불가"가 나온 경우도 통과가 아니라 실패로 취급합니다.
- 몇 번 시도했는지·무엇을 검사에서 뺐는지 같은 기록은 상태 파일에 남기므로, 중간에 대화를 새로 시작해도 재시도 횟수가 0으로 초기화되지 않습니다.
- 프로젝트가 작으면 불필요한 단계는 건너뛰자고 제안하고, 건너뛸 때는 항상 사용자에게 먼저 확인합니다.
- 지금 어느 단계까지 왔는지, 무엇이 만들어졌는지 한눈에 보여 주는 진행 현황판을 제공합니다.
언제 작동하나요
- "프로젝트 시작", "새 프로젝트", "전체 파이프라인" 같은 말을 했을 때
/product명령을 실행했을 때- 분석 → 사양 검증 → 기획 → 설계 → 개발 → 출시까지 전체 흐름이 필요할 때
- 흩어져 있는 여러 도구(플러그인)를 하나의 흐름으로 묶어 진행해야 할 때
핵심 용어 사전#
| 용어 | 쉬운 설명 |
|---|---|
| orchestration / orchestrator | 여러 도구와 단계를 하나의 흐름으로 묶어 순서대로 자동 진행시키는 "총괄 지휘" 역할. 오케스트라 지휘자가 여러 연주자를 한 곡으로 모으는 것과 같습니다. |
| slug |
프로젝트를 가리키는 짧고 단순한 이름표. 예를 들어 "Community Feature"를
community
처럼 컴퓨터가 다루기 쉬운 형태로 줄인 식별자입니다.
|
| kebab-case |
단어 사이를 띄어쓰기 대신 붙임표(-)로 잇고 모두 소문자로 쓰는 표기 방식. "꼬치(kebab)"에 단어를 꿰듯 이어 붙여서 붙은 이름입니다. (예:
new-project
)
|
| artifact (산출물) | 각 단계를 거치며 만들어져 파일로 남는 결과물. 문서, 사양서, 설계도 등이 여기 해당하며 docs/ 폴더에 저장됩니다. |
| gate (게이트/관문) | 다음 단계로 넘어가기 전에 "충분히 잘 됐는지" 확인하는 품질 검사 지점. 통과해야만 다음으로 진행할 수 있는 관문입니다. |
| verdict (판정) |
관문 검사의 결과.
pass
(통과)·
fail
(실패)·
undetermined
(판정 불가) 세 값이며, 판정 불가는 통과가 아니라 실패로 취급합니다.
|
| budget (예산) | 같은 일을 몇 번까지 다시 시도해도 되는지 정해 둔 횟수 한도. 이 횟수를 상태 파일에 적어 두지 않으면 한도가 있다고 말할 수 없습니다. |
| BYPASSED (우회 기록) | 관문을 통과하지 못했는데도 사용자가 명시적으로 넘어가기로 결정한 경우, 그 사실을 상태 파일과 최종 보고에 남겨 두는 표시. 아무 말 없이 넘어가는 것과는 다릅니다. |
| BMAD Level (레벨 0~4) | 프로젝트의 규모와 복잡도를 숫자로 나눈 등급. 숫자가 낮으면(0~1) 작은 기능 추가, 높으면 큰 프로젝트를 뜻하며, 어떤 단계를 건너뛸지 판단하는 기준이 됩니다. |
| Seed spec (시드 사양) | 프로젝트의 핵심 요구사항을 처음으로 또렷하게 정리해 둔 "씨앗" 문서. 이후 모든 설계와 개발이 여기서 자라납니다. |
| Socratic (소크라테스식 인터뷰) | 꼬리에 꼬리를 무는 질문을 던져 숨어 있는 요구사항과 가정을 끄집어내는 대화 방식. |
| PRD | Product Requirements Document(제품 요구사항 문서). 무엇을, 왜, 어떻게 만들지를 정리한 제품의 설계 청사진입니다. |
| BDD Acceptance Criteria | Behavior-Driven Development(행위 주도 개발)에서 "이 기능이 이렇게 동작하면 합격"이라고 미리 정해 두는 합격 기준. |
| Epic (에픽) | 여러 작은 작업(Story)을 하나로 묶은 큰 단위의 일감. 책으로 치면 "장(章)"에 해당합니다. |
| Story (스토리) | Epic을 잘게 나눈 실제 개발 작업 단위. 책으로 치면 한 "장" 안의 개별 이야기/항목에 해당합니다. |
| DoD (Definition of Done) | "이 작업이 끝났다고 인정하는 조건". 무엇을 충족해야 완료로 볼지 미리 정의한 기준입니다. |
| persona (페르소나) | 각 단계를 검토하는 가상의 전문가 역할(분석가, 아키텍트, PM 등). 실제 사람 대신 그 관점으로 결과물을 점검합니다. |
| 문서 PR (docs PR) | 파이프라인이 만든 문서들을 모아 팀의 기본 코드 줄기에 합쳐 달라고 보내는 요청서. 일감 생성 직후와 출시 직후 두 번 올라가며, 이걸 거치지 않은 문서는 만든 사람 컴퓨터에만 있습니다. |
| 기본 브랜치 (default branch) | 팀이 공식으로 쓰는 코드의 본줄기. 새 작업은 여기서 갈라져 나오므로, 문서가 여기 들어와 있어야 이후 작업이 그 문서를 갖고 시작합니다. |
| context-clear handoff | 한 단계가 끝나면 대화 기록을 깨끗이 비우고(/clear) 다음 단계로 넘기는 방식. 결과물은 파일로 남아 있어 정보 손실 없이 새 대화에서 이어집니다. |
Triggers#
- When keywords like "start project", "new project", "full pipeline" are mentioned
- When the
/productcommand is invoked - When the full flow of analysis → spec verification → planning → design → development → launch is needed
- When orchestration connecting existing plugins is needed
Behavior#
1. Project Initialization#
- Generate project slug (kebab-case)
- Create
.pipeline/{slug}.yamlstate file - Determine BMAD project level (Level 0-4)
2. Stage Execution Flow#
Normative declaration. The ```flow block below is the single normative statement of this
pipeline's stages, gates and fail edges. Notation, the gate tri-state and the loop contract are
defined in plugins/cc-dev/rules/orchestration-graph.md and are cited here, not restated. Every
other rendering of this flow — the ASCII digest below, the §3/§5 tables, commands/product.md
Execution Flow, references/phase-gates.md diagrams — is a non-normative derived view; where a
view disagrees with the block, the block wins.
# Notation / gate tri-state / loop contract: plugins/cc-dev/rules/orchestration-graph.md (§1, §3, §2)
# substrate: inline / sequential (same SoT §4, row 1) — no fan-out: each stage reads the previous
# stage ' s artifacts. tier: is unset because nothing here spawns a session; degree is always 1.
# Node ids for stages are the keys of config/pipeline.json → stages.* (§6).
DISC ACT discovery — research / vision writes:docs/discovery-{slug}.md
SPEC LOOP specification (cc-spec) contract:L-gate-revise writes:docs/seed-spec-{slug}.md
G-spec GATE specification gate verdict:unmet(specification)==0 undet:fail fail:SPEC
PLAN LOOP planning — prd / tech-spec / bdd contract:L-gate-revise writes:docs/prd-{slug}.md
G-anly GATE analysis gate verdict:unmet(analysis)==0 undet:fail fail:PLAN
DSGN LOOP design — architecture / ux contract:L-gate-revise writes:docs/architecture-{slug}.md
G-soln GATE solutioning gate verdict:unmet(solutioning)==0 undet:fail fail:DSGN
SCAF LOOP scaffold (cc-bricks / cc-flutter) contract:L-gate-revise writes:lib/**,test/**,*.feature
G-scaf GATE scaffold gate verdict:unmet(scaffold)==0 undet:fail fail:SCAF
BRKD LOOP breakdown (cc-dev / zenhub) contract:L-gate-revise writes:zenhub:issues,.claude/docs/{feature}/zenhub/priority.md
G-plng GATE planning gate verdict:unmet(planning)==0 undet:fail fail:BRKD
DOCS ACT planning docs PR (helpers.md: Publish Pipeline Docs PR) writes:github:pr(docs),.pipeline#stages.*.docs_pr
DEV LOOP development (cc-dev run) contract:L-gate-revise writes:github:pr,zenhub:pipeline
G-impl GATE implementation gate verdict:unmet(implementation)==0 undet:fail fail:DEV
LNCH ACT launch — gtm / analytics writes:docs/gtm-{slug}.md
LDOC ACT launch docs PR (same helper) writes:github:pr(docs),.pipeline#stages.launch.docs_pr
ESC ASK quote unmet criterion, ask user options:reset attempts + --from {stage}|record BYPASSED|HALT
DISC -- > SPEC -- > G-spec -- > PLAN -- > G-anly -- > DSGN -- > G-soln -- > SCAF
SCAF -- > G-scaf -- > BRKD -- > G-plng -- > DOCS -- > DEV -- > G-impl -- > LNCH -- > LDOC
G-spec == > SPEC on:verdict!=pass bound:2 invalidates:SPEC,G-spec
G-anly == > PLAN on:verdict!=pass bound:2 invalidates:PLAN,G-anly
G-soln == > DSGN on:verdict!=pass bound:2 invalidates:DSGN,G-soln
G-scaf == > SCAF on:verdict!=pass bound:2 invalidates:SCAF,G-scaf
G-plng == > BRKD on:verdict!=pass bound:2 invalidates:BRKD,G-plng
G-impl == > DEV on:verdict!=pass bound:2 invalidates:DEV,G-impl
SPEC ~~ > ESC on:attempts==3 record:.pipeline/{slug}.yaml#stages.specification.gate
PLAN ~~ > ESC on:attempts==3 record:.pipeline/{slug}.yaml#stages.planning.gate
DSGN ~~ > ESC on:attempts==3 record:.pipeline/{slug}.yaml#stages.design.gate
SCAF ~~ > ESC on:attempts==3 record:.pipeline/{slug}.yaml#stages.scaffold.gate
BRKD ~~ > ESC on:attempts==3 record:.pipeline/{slug}.yaml#stages.breakdown.gate
DEV ~~ > ESC on:attempts==3 record:.pipeline/{slug}.yaml#stages.development.gate
ESC ~~ > HALT on:answer==HALT record:.pipeline#stages.{stage}(status:failed,gate.verdict:fail)
DISC ~~ > SPEC on:skip(discovery) record:ASK+.pipeline#stages.discovery(status:skipped,skip_reason)
SPEC ~~ > PLAN on:skip(specification) record:ASK+.pipeline#stages.specification(status:skipped,gate.verdict:skipped,skip_reason)
DSGN ~~ > SCAF on:skip(design) record:ASK+.pipeline#stages.design(status:skipped,gate.verdict:skipped,skip_reason)
SCAF ~~ > BRKD on:skip(scaffold) record:ASK+.pipeline#stages.scaffold(status:skipped,gate.verdict:skipped,skip_reason)
BRKD ~~ > DOCS on:skip(breakdown) record:ASK+.pipeline#stages.breakdown(status:skipped,gate.verdict:skipped,skip_reason)
DOCS ~~ > DEV on:degraded record:.pipeline#stages.{stage}.docs_pr(status:degraded,reason)
LNCH ~~ > SKIP on:skip(launch) record:ASK+.pipeline#stages.launch(status:skipped,skip_reason)
ESC's other two answers leave the block through a new --from
invocation (§8), which re-enters
at a declared stage node — so no unbudgeted back-edge exists in the graph. Six gates, six fail
edges: a gate whose only outcome is "pass" was never a gate.
DOCS / LDOC — publication, not a gate. Every stage before them writes its artifacts to the
working tree and stops there; without these two nodes the pipeline ends with its documents committed
nowhere, and DEV cuts every Story branch from a base that lacks the architecture/UX spec those
Stories cite as DoD. They are ACT, not GATE: they have no verdict and cannot fail the pipeline —
a degraded publication is recorded and named, and the chain continues (DOCS ~~> DEV).
LDOC
degrades by the same rule; being terminal it has no successor edge, so its record and the final
report are its only outputs. The protocol itself lives at references/helpers.md
→ Publish
Pipeline Docs PR and is cited, never restated — here or in the two calling commands.
BRKD ~~> DOCS (not ~~> DEV): skipping the breakdown stage does not un-write the documents
DISC–DSGN already produced, so the publication point must survive the skip. When there genuinely
are no documents — a Level 0 run that skipped nearly everything — the helper reports an empty set
rather than opening an empty PR.
Predicates (values live here, at their own site — SoT keeps only the contract):
-
unmet(g)= the entries ofconfig/pipeline.json→gates.{g}.checkswhose result is notpass, counting un-run and undeterminable checks as unmet. If the checks list itself cannot be read,unmetisunknown, not0(orchestration-graph.md §3.2, empty-set pass). -
skip(s)= project level ∈stages.{s}.skip.levelsor a listedstages.{s}.skip.conditionsmatch, and the user confirmed (§5). A skip is durable, never silent. -
attempts=.pipeline/{slug}.yaml→stages.{s}.gate.attempts. It is the only counter that survives a/clear(§7). -
degraded= thePublish Pipeline Docs PRhelper returned without a merged PR — nogh/remote, an empty collected set, a stage withheld for a non-passing gate, or CI red on the docs PR. It is a recorded outcome, not a verdict: it never makes a gate pass and never halts the chain, but adocs_prleftnullwith no reason is a violation of this node's contract, not a quiet success.
Contract L-gate-revise — the 7 required loop fields (orchestration-graph.md §2). One contract
shared by all six gated stages; {stage} / {gate} are the keys from
config/pipeline.json.
inv: at judgment time every path in stages.{stage}.artifacts exists and is non-empty —
a missing artifact is `undetermined`, never " nothing to check "
prog: unmet({gate}) strictly decreases per attempt
no-prog: the same unmet set twice → stop spending budget, go to ESC
term: unmet({gate}) == 0 ( " re-review if it still looks off " is not a termination predicate)
budget: 2 re-runs per gate = 3 judgments total, the same number as references/phase-gates.md
" Retry Limit " (maxRetries: 3 → escalate on the 3rd failure). Per stage, not per pipeline.
exhaust: ESC — escalate to the user quoting the unmet check names verbatim; the stage stays
`status: failed`. Warn-and-continue is not available at this gate.
resume: reads .pipeline/{slug}.yaml#stages.{stage}.gate.{verdict,attempts,at}; re-running a
stage is idempotent (it overwrites the same artifact paths)
log: one line per attempt — " specification #2: unmet 3→1 (consensus) " — plus durable
skipped_checks / dropped entries for anything left out
Derived view — stage digest (non-normative). Keys are config/pipeline.json
→ stages.*.
discovery → specification → planning → design → scaffold → breakdown → development → launch
│ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
pm+bmad cc-spec- bmad+pm bmad cc-bricks cc-dev cc-dev pm
(research) clarity (plan/biz) (arch/ux) +cc-flutter +bmad(story) +bmad(dev) (gtm/anal)
(외부) (외부) (외부) (외부)
내부 역량(bmad persona·커맨드, pm 기법)은 cc-product 자체가 단계별로 dispatch. 외부 플러그인만 위임: cc-spec(Spec) · cc-bricks/cc-flutter(Scaffold) · cc-dev(Breakdown/Dev).
3. Per Stage Execution#
- Check previous artifacts: Verify previous stage artifacts exist
- Evaluate skip conditions: Determine skippability based on project level/type
- Delegate to source plugins: Invoke the stage's skills/commands in order
-
Gate verification (tri-state): Evaluate the stage's gate — Specification, Analysis,
Solutioning, Scaffold, Planning, Implementation (the six
gates.*ofconfig/pipeline.json). The verdict ispass | fail | undetermined, andundeterminedbehaves asfail(plugins/cc-dev/rules/orchestration-graph.md§3): a check that could not be run, a missing artifact, or an unreadable checks list never passes the gate. -
On fail / undetermined: take the gate's fail edge from §2 — re-run this stage under
L-gate-revise(bound 2 re-runs = 3 judgments total), incrementingstages.{stage}.gate.attemptsbefore anything else. On exhaustion, escalate to the user quoting the specific unmet criterion by name (ESC); never continue to the next stage. - Save artifacts: Store results in
docs/directory -
Update state: Refresh
.pipeline/{slug}.yaml(status,gate,skipped_checks,dropped) -
Publish — at the two publication points only:
DOCS(after the planning gate) andLDOC(after launch) callreferences/helpers.md→ Publish Pipeline Docs PR. Saving an artifact in step 6 is not publishing it: until one of those two nodes runs, the file exists in this working tree and nowhere else. Per-stage publication is deliberately not offered —L-gate-reviseoverwrites the same artifact paths on every re-run, so a stage that publishes before its verdict puts a document on the default branch that its own next attempt contradicts.
4. Inter-stage Data Passing#
- Automatically pass previous stage artifact paths to next stage
- Discovery → Specification: Research results, vision
- Specification → Planning: Seed spec, ambiguity evaluation, decision log
- Planning → Design: PRD, technical specification, BDD Acceptance Criteria
- Design → Scaffold: Architecture doc, UX spec, PRD (acceptance criteria)
- Scaffold → Breakdown: Scaffolded feature list, .feature file paths, test file paths
-
Breakdown → Development: Epic/Story issue numbers (Stories reference scaffolded code + step stubs as DoD)
and the merged planning docs PR — the documents those Stories cite are on the default branch
before
DEVbranches, so a Story branch never has to carry them - Development → Launch: Deployed feature list
5. Skip Rules#
- Discovery skip: BMAD Level 0-1 (small-scale feature addition for existing product)
- Specification skip: BMAD Level 0-1 (small-scale feature addition for existing product)
- Scaffold skip: BMAD Level 0-1 (hotfix, minor feature without new code structure)
- Launch skip: Internal features, minor improvements, infrastructure changes
- User confirmation: Always confirm with user when skipping
-
Authoritative skip matrix:
config/pipeline.json(stages.*.skip+levels.*.defaultSkip) — the list above is a non-normative digest, and it omits the Level 0design/breakdownskips thatlevels.0.defaultSkipdeclares. -
Recording a skip: follow the
~~>edges in §2 — writestatus: skipped+skip_reason, and for a gated stage alsogate.verdict: skipped. Never leave a skipped stagepending, and never let a skip leave a gate with no recorded verdict (that is what §8 refuses on re-entry).
6. State File Format (.pipeline/{slug}.yaml)#
project:
name: " Community Feature "
slug: community
level: 3
created: 2025-01-15T10:00:00Z
updated: 2025-01-16T14:30:00Z
# Stage keys are the keys of config/pipeline.json → stages.* (single source). No aliases.
stages:
discovery:
status: completed # pending | in-progress | completed | skipped | failed
started: 2025-01-15T10:00:00Z
completed: 2025-01-15T12:00:00Z
artifacts:
- docs/discovery-community.md
skip_reason: null
skipped_checks: [] # checks left out of this stage ' s gate, with reason — durable, not console
dropped: [] # requirements/scope deliberately dropped here (L-gate-revise log:)
specification:
status: completed
started: 2025-01-15T13:00:00Z
completed: 2025-01-15T14:00:00Z
gate: # was a bare string (`gate: specification`) — now the verdict record
name: specification
verdict: pass # pass | fail | undetermined | skipped | BYPASSED
attempts: 1 # judgments so far; budget = 2 re-runs → 3 (L-gate-revise, §2)
at: 2025-01-15T14:00:00Z
artifacts:
- docs/seed-spec-community.md
- docs/socratic-discovery-community.md
docs_pr: # written by the DOCS node (§2) on every stage it published
number: 412
url: https://github.com/{org}/{repo}/pull/412
merged_at: 2025-01-16T09:10:00Z
status: merged # merged | degraded
reason: null # required when status is degraded
skipped_checks: []
dropped: []
planning:
status: failed # gate failed and the budget is spent — NOT the same as pending
started: 2025-01-15T14:00:00Z
gate:
name: analysis
verdict: fail
attempts: 3
at: 2025-01-16T14:30:00Z
artifacts: []
skipped_checks:
- check: ac_testability
reason: " BDD suite not generated yet — re-checked at the scaffold gate "
dropped: []
design:
status: pending
scaffold: # order 4.5 in config/pipeline.json, gate: scaffold
status: pending
breakdown: # NOT `epic:` — the key comes from config/pipeline.json
status: pending
development:
status: pending
launch:
status: pending
docs_pr: — publication is state, not console output. null means
not published yet, never
"nothing to publish"; a stage whose documents the helper deliberately withheld carries
status: degraded with a reason. The distinction is what makes re-entry safe: on a re-run the
helper reads this field to decide between "already merged, skip" and "never published, publish now",
and a publication recorded only in the conversation is gone after /clear
— the same reason
attempts lives here (§7).
Why failed had to exist: without it, a gate-failed stage and a never-started stage are the same
pending on re-entry, which quietly defeats the artifact + state-file resume design — the pipeline
re-runs the stage with attempts back at zero and the budget is fiction.
Reading a state file written before this schema (gate: still a string, no
skipped_checks /
dropped, no failed): treat every absent key as unknown, and unknown is
undetermined — so
that gate is re-evaluated with attempts: 0, not failed outright. The migration re-verifies; it
does not block an in-flight pipeline. Only a fresh fail blocks. Likewise, an absent
skipped_checks / dropped means "nothing was recorded", never "nothing was dropped".
7. Context-Clear Handoff#
Each stage produces persistent artifacts in docs/. Between stages, offer the user a context-clear handoff to maximize token efficiency:
Stage {N} complete. Artifacts saved:
- docs/{artifact}-{slug}.md
**Option 1 (Recommended)**: Clear context and continue to next stage
/clear
Then run: /product:{next_stage} docs/{artifact}-{slug}.md
**Option 2**: Continue in current context
Proceed directly to /product:{next_stage}
Why context-clear matters:
- Each stage can consume significant context window (Socratic interviews, architecture reviews, etc.)
-
Artifacts persist in
docs/and.pipeline/{slug}.yaml, so no information is lost within this working tree — they survive a/clear, not a fresh clone or a removed worktree. Reaching the repository is what theDOCS/LDOCpublication nodes (§2) are for - Next stage reads previous artifacts from files, not from conversation history
- Fresh context allows the next stage to operate at full capacity
Rules:
- Always present Option 1 first (recommended)
- Include the exact artifact file paths so the user can reference them after
/clear - The pipeline state file
.pipeline/{slug}.yamltracks progress across context clears - If the user chooses Option 2, proceed normally in the same context
-
Counter persistence (budget rule): any loop with a
budget:must persist its counter to.pipeline/{slug}.yamlbefore yielding to a context-clear handoff — a loop whose counter is not persisted has no budget. A conversation-local retry count does not survive/clear, soL-gate-revise's 2 re-runs (andreferences/phase-gates.md'smaxRetries: 3) exist only asstages.{stage}.gate.attemptson disk. The same applies to a user-granted reset: an unrecorded reset ofattemptsis a budget that never existed.
8. Re-entry Assertion (--from / --to)#
--from and --to are declared in plugins/cc-product/commands/product.md
(Options). This
orchestrator owns their precondition: --from X may not silently start behind an unresolved gate.
Assertion. For every stage before X in config/pipeline.json
order, .pipeline/{slug}.yaml
must record one of:
-
gate.verdict: pass— orstatus: completedfor the two gateless stages (discovery,launch); -
status: skippedwithgate.verdict: skipped(gated stages) and a non-nullskip_reason.
Anything else fails the assertion — fail, undetermined, pending, or a
missing gate: block
(unknown ≠ passed). There are exactly two legal outcomes, and "proceed anyway" is not one of them:
-
Refuse (default): stop, name the first offending stage and its gate, and tell the user to run
--from {that stage}instead. -
Bypass, on explicit user confirmation: write
gate: {name, verdict: BYPASSED, attempts, at}plus the bypass reason on that stage, and carry every BYPASSED gate name into the final report and the stage dashboard.BYPASSEDis a recorded user decision, not a verdict — it never makesundeterminedpass, and it is never inferred from silence.
Contract L-resume (product.stage-chain-resume) — 7 fields (orchestration-graph.md §2), values
at this site:
inv: every stage before the entry point is pass | skipped | BYPASSED in .pipeline/{slug}.yaml
prog: resolved = count of stages whose status ∈ {completed, skipped}; monotone increasing
no-prog: two consecutive --from re-entries at the same stage with no increase in
gate.attempts → ESC (do not spend a third re-entry on the same state)
term: stages.launch.status ∈ {completed, skipped}
budget: re-entry itself is unbudgeted; the per-gate budget is L-gate-revise ' s 2 re-runs and its
only evidence is stages.{stage}.gate.attempts on disk (§7)
exhaust: ESC — escalate quoting the unmet criterion; resuming again requires the user to reset
gate.attempts explicitly, and the reset is recorded with a reason
resume: reads .pipeline/{slug}.yaml and the artifact files only — conversation history is never
an input, so it cannot be a source of progress either
log: one line per re-entry — " --from planning: analysis 2/3 attempts, bypassed: none " —
plus the BYPASSED / dropped list carried into the final report
Output#
- Project status dashboard (progress by stage)
- Each stage's artifacts (docs/ directory)
.pipeline/{slug}.yamlstate tracking file- Summary report on stage transitions
Notes#
- Orchestrates from above without modifying existing plugins
-
Gates serve as quality checkpoints — the six
gates.*ofconfig/pipeline.json(specification, analysis, solutioning, scaffold, planning, implementation). Each one has a fail edge in §2, andundeterminedcounts asfail - Personas serve as reviewers at each stage (Analyst, Architect, PM, etc.)
- Users can independently execute any stage if desired — subject to §8's re-entry assertion
-
Stage keys are single-sourced from
config/pipeline.json(stages.*);.pipeline/{slug}.yaml,config/stage-mapping.yamlandcommands/product.mdall use those keys. There is noepicstage - Stage-to-source command mappings managed in
config/stage-mapping.yaml -
Flow notation, gate tri-state, loop contract and substrate matrix:
plugins/cc-dev/rules/orchestration-graph.md