diff --git a/CLAUDE.md b/CLAUDE.md index f60124f7..9cfa12bf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -167,6 +167,7 @@ Working memory files live in a dedicated `.memory/` directory: - Target: ~120-150 lines per SKILL.md with progressive disclosure to `references/` - Skills default to read-only (`allowed-tools: Read, Grep, Glob`); exceptions: git/review skills add `Bash`, interactive skills add `AskUserQuestion`, `quality-gates` adds `Write` for state persistence, and `router` omits `allowed-tools` entirely (unrestricted, as the main-session orchestrator) - All skills live in `shared/skills/` — add to plugin `plugin.json` `skills` array, then `npm run build` +- Orchestration skills (`*:orch`) follow the Phase Protocol (defined in `router/SKILL.md`) — each phase needs `**Produces:**`/`**Requires:**` annotations and a `## Phase Completion Checklist` ### Agents diff --git a/plugins/devflow-audit-claude/commands/audit-claude.md b/plugins/devflow-audit-claude/commands/audit-claude.md index a991b6b9..fa8407c7 100644 --- a/plugins/devflow-audit-claude/commands/audit-claude.md +++ b/plugins/devflow-audit-claude/commands/audit-claude.md @@ -19,6 +19,8 @@ Audit CLAUDE.md files against Anthropic's best practices. Finds oversized files, ### Phase 1: Discovery +**Produces:** CLAUDE_FILES + Find all CLAUDE.md files to audit: ```bash @@ -36,6 +38,9 @@ If a specific path argument was provided, use only that file. ### Phase 2: Analysis +**Produces:** AUDIT_RESULTS +**Requires:** CLAUDE_FILES + For each discovered file, spawn a `claude-md-auditor` agent: ``` @@ -53,6 +58,8 @@ Run agents in parallel when multiple files are found. ### Phase 3: Report +**Requires:** AUDIT_RESULTS + Combine all agent outputs into a single report: ```markdown diff --git a/plugins/devflow-code-review/commands/code-review-teams.md b/plugins/devflow-code-review/commands/code-review-teams.md index afb19c78..0a0eea39 100644 --- a/plugins/devflow-code-review/commands/code-review-teams.md +++ b/plugins/devflow-code-review/commands/code-review-teams.md @@ -21,6 +21,8 @@ Run a comprehensive code review of the current branch by spawning a review team #### Step 0a: Discover Worktrees +**Produces:** WORKTREES + 1. **Discover reviewable worktrees** using the `devflow:worktree-support` skill discovery algorithm: - Run `git worktree list --porcelain` → parse, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit - See `~/.claude/skills/devflow:worktree-support/SKILL.md` for the full 7-step algorithm and canonical protected branch list @@ -31,6 +33,9 @@ Run a comprehensive code review of the current branch by spawning a review team #### Step 0b: Per-Worktree Pre-Flight (Git Agent) +**Produces:** BRANCH_INFO, PR_INFO +**Requires:** WORKTREES + For each reviewable worktree, spawn Git agent: ``` @@ -49,6 +54,9 @@ In multi-worktree mode, spawn all pre-flight agents **in a single message** (par #### Step 0c: Incremental Detection & Timestamp Setup +**Produces:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP +**Requires:** BRANCH_INFO + For each worktree: 1. Generate timestamp: `YYYY-MM-DD_HHMM`. If directory already exists (same-minute collision), append seconds (`YYYY-MM-DD_HHMMSS`). @@ -64,6 +72,9 @@ For each worktree: ### Phase 1: Analyze Changed Files +**Produces:** REVIEWER_LIST +**Requires:** DIFF_RANGE + Per worktree, detect file types in diff using `DIFF_RANGE` to determine conditional reviews: | Condition | Adds Perspective | @@ -84,6 +95,8 @@ Per worktree, detect file types in diff using `DIFF_RANGE` to determine conditio ### Phase 1b: Load Knowledge Index +**Produces:** KNOWLEDGE_CONTEXT + Load the knowledge index for the current worktree before spawning the review team: ```bash @@ -94,6 +107,9 @@ This produces a compact index of active ADR/PF entries. Pass `KNOWLEDGE_CONTEXT` ### Phase 2: Spawn Review Team +**Produces:** REVIEWER_OUTPUTS +**Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, KNOWLEDGE_CONTEXT, REVIEWER_LIST + **Per worktree**, create an agent team for adversarial review. Always include 4 core perspectives; conditionally add more based on Phase 1 analysis. **Note**: In multi-worktree mode, process worktrees sequentially for Agent Teams (one team per session constraint). Each worktree gets its own team lifecycle: create → debate → synthesize → cleanup. @@ -166,6 +182,8 @@ Spawn review teammates. For each teammate, compose a self-contained prompt using ### Phase 2b: Debate Round +**Requires:** REVIEWER_OUTPUTS + After all reviewers complete initial analysis, lead initiates adversarial debate: Lead initiates debate via broadcast: @@ -196,6 +214,9 @@ Reviewers message each other directly using SendMessage: ### Phase 3: Synthesis and PR Comments +**Produces:** REVIEW_SUMMARY +**Requires:** REVIEWER_OUTPUTS, REVIEW_DIR, PR_INFO + **WAIT** for debate to complete, then lead produces outputs. Spawn 2 agents **in a single message**: @@ -240,6 +261,8 @@ Check for existing inline comments at same file:line before creating new ones." ### Phase 4: Write Review Head Marker +**Requires:** BRANCH_INFO, REVIEW_DIR + Per worktree, after successful completion: 1. Write current HEAD SHA to `{worktree_path}/.docs/reviews/{branch-slug}/.last-review-head` @@ -248,6 +271,8 @@ Per worktree, after successful completion: ### Phase 5: Cleanup and Report +**Requires:** REVIEW_SUMMARY + Shut down all review teammates explicitly: ``` diff --git a/plugins/devflow-code-review/commands/code-review.md b/plugins/devflow-code-review/commands/code-review.md index 84bb6d50..9b6effff 100644 --- a/plugins/devflow-code-review/commands/code-review.md +++ b/plugins/devflow-code-review/commands/code-review.md @@ -28,6 +28,8 @@ Run a comprehensive code review of the current branch by spawning parallel revie #### Step 0a: Discover Worktrees +**Produces:** WORKTREES + 1. **Discover reviewable worktrees** using the `devflow:worktree-support` skill discovery algorithm: - Run `git worktree list --porcelain` → parse, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit - See `~/.claude/skills/devflow:worktree-support/SKILL.md` for the full 7-step algorithm and canonical protected branch list @@ -38,6 +40,9 @@ Run a comprehensive code review of the current branch by spawning parallel revie #### Step 0b: Per-Worktree Pre-Flight (Git Agent) +**Produces:** BRANCH_INFO, PR_INFO +**Requires:** WORKTREES + For each reviewable worktree, spawn Git agent: ``` @@ -56,6 +61,9 @@ In multi-worktree mode, spawn all pre-flight agents **in a single message** (par #### Step 0c: Incremental Detection & Timestamp Setup +**Produces:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP +**Requires:** BRANCH_INFO + For each worktree: 1. Generate timestamp: `YYYY-MM-DD_HHMM`. If directory already exists (same-minute collision), append seconds (`YYYY-MM-DD_HHMMSS`). @@ -71,6 +79,9 @@ For each worktree: ### Phase 1: Analyze Changed Files +**Produces:** REVIEWER_LIST +**Requires:** DIFF_RANGE + Per worktree, detect file types in diff using `DIFF_RANGE` to determine conditional reviews: | Condition | Adds Review | @@ -91,6 +102,8 @@ Per worktree, detect file types in diff using `DIFF_RANGE` to determine conditio ### Phase 1b: Load Knowledge Index +**Produces:** KNOWLEDGE_CONTEXT + While file analysis runs (or just before spawning reviewers), load the knowledge index for the current worktree: ```bash @@ -101,6 +114,9 @@ This produces a compact index of active ADR/PF entries. Pass `KNOWLEDGE_CONTEXT` ### Phase 2: Run Reviews (Parallel) +**Produces:** REVIEWER_OUTPUTS +**Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, KNOWLEDGE_CONTEXT, REVIEWER_LIST + Spawn Reviewer agents **in a single message**. Always run 7 core reviews; conditionally add more based on changed file types: | Focus | Always | Pattern Skill | @@ -141,6 +157,9 @@ In multi-worktree mode, process worktrees **sequentially** (one worktree at a ti ### Phase 3: Synthesis (Parallel) +**Produces:** REVIEW_SUMMARY +**Requires:** REVIEWER_OUTPUTS, REVIEW_DIR, PR_INFO + **WAIT** for Phase 2, then spawn agents per worktree **in a single message**: **Git Agent (PR Comments)** per worktree: @@ -169,6 +188,8 @@ Output: {worktree_path}/.docs/reviews/{branch-slug}/{timestamp}/review-summary.m ### Phase 4: Write Review Head Marker & Report +**Requires:** BRANCH_INFO, REVIEW_DIR + Per worktree, after successful completion: 1. Write current HEAD SHA to `{worktree_path}/.docs/reviews/{branch-slug}/.last-review-head` 2. Display results from all agents: diff --git a/plugins/devflow-debug/commands/debug-teams.md b/plugins/devflow-debug/commands/debug-teams.md index 38e32ed3..961271d9 100644 --- a/plugins/devflow-debug/commands/debug-teams.md +++ b/plugins/devflow-debug/commands/debug-teams.md @@ -25,6 +25,8 @@ Investigate bugs by spawning a team of agents, each pursuing a different hypothe ### Phase 1: Load Knowledge Index (Orchestrator-Local) +**Produces:** KNOWLEDGE_CONTEXT + Before hypothesizing, load the knowledge index: ```bash @@ -35,6 +37,9 @@ The orchestrator uses `KNOWLEDGE_CONTEXT` locally when generating hypotheses (Ph ### Phase 2: Context Gathering +**Produces:** HYPOTHESES, BUG_CONTEXT +**Requires:** KNOWLEDGE_CONTEXT + If `$ARGUMENTS` starts with `#`, fetch the GitHub issue: ``` @@ -51,6 +56,8 @@ Analyze the bug description (from arguments or issue) and identify 3-5 plausible ### Phase 3: Spawn Investigation Team +**Requires:** HYPOTHESES, BUG_CONTEXT + Create an agent team with one investigator per hypothesis: ``` @@ -111,6 +118,9 @@ Spawn investigator teammates with self-contained prompts: ### Phase 4: Investigation +**Produces:** INVESTIGATION_RESULTS +**Requires:** HYPOTHESES + Teammates investigate in parallel: - Read relevant source files - Trace execution paths @@ -120,6 +130,8 @@ Teammates investigate in parallel: ### Phase 5: Adversarial Debate +**Requires:** INVESTIGATION_RESULTS + Lead initiates debate via broadcast: ``` @@ -147,6 +159,9 @@ Teammates challenge each other directly using SendMessage: ### Phase 6: Convergence +**Produces:** CONVERGENCE_RESULTS +**Requires:** INVESTIGATION_RESULTS + After debate (max 2 rounds), lead collects results: ``` @@ -159,6 +174,8 @@ Lead broadcast: ### Phase 7: Cleanup +**Requires:** CONVERGENCE_RESULTS + Shut down all investigator teammates explicitly: ``` @@ -172,6 +189,8 @@ Verify TeamDelete succeeded. If failed, retry once after 5s. If retry fails, HAL ### Phase 8: Report +**Requires:** CONVERGENCE_RESULTS + Lead produces final report: ```markdown diff --git a/plugins/devflow-debug/commands/debug.md b/plugins/devflow-debug/commands/debug.md index 18b62365..12ec57e1 100644 --- a/plugins/devflow-debug/commands/debug.md +++ b/plugins/devflow-debug/commands/debug.md @@ -33,6 +33,8 @@ Investigate bugs by spawning parallel agents, each pursuing a different hypothes ### Phase 1: Load Knowledge Index (Orchestrator-Local) +**Produces:** KNOWLEDGE_CONTEXT + Before hypothesizing, load the knowledge index: ```bash @@ -43,6 +45,9 @@ The orchestrator uses `KNOWLEDGE_CONTEXT` locally when generating hypotheses (Ph ### Phase 2: Context Gathering +**Produces:** HYPOTHESES, BUG_CONTEXT +**Requires:** KNOWLEDGE_CONTEXT + If `$ARGUMENTS` starts with `#`, fetch the GitHub issue: ``` @@ -59,6 +64,9 @@ Analyze the bug description (from arguments or issue) and identify 3-5 plausible ### Phase 3: Investigate (Parallel) +**Produces:** INVESTIGATION_RESULTS +**Requires:** HYPOTHESES + Spawn one Explore agent per hypothesis in a **single message** (parallel execution): ``` @@ -102,6 +110,9 @@ Focus area: {specific code area, mechanism, or condition} ### Phase 4: Synthesize +**Produces:** ROOT_CAUSE_SYNTHESIS +**Requires:** INVESTIGATION_RESULTS + Once all investigators return, spawn a Synthesizer agent to aggregate findings: ``` @@ -120,6 +131,8 @@ Instructions: ### Phase 5: Report +**Requires:** ROOT_CAUSE_SYNTHESIS + Produce the final report: ```markdown diff --git a/plugins/devflow-implement/commands/implement-teams.md b/plugins/devflow-implement/commands/implement-teams.md index 390aef23..915e3f2f 100644 --- a/plugins/devflow-implement/commands/implement-teams.md +++ b/plugins/devflow-implement/commands/implement-teams.md @@ -29,6 +29,8 @@ Orchestrate a single task through implementation by spawning specialized agent t ### Phase 1: Setup +**Produces:** TASK_ID, BASE_BRANCH, EXECUTION_PLAN + Record the current branch name as `BASE_BRANCH` - this will be the PR target. Spawn Git agent to set up task environment. The Git agent derives the branch name automatically from the issue or task description: @@ -60,6 +62,9 @@ Return the branch setup summary." ### Phase 2: Implement +**Produces:** CODER_OUTPUT, FILES_CHANGED +**Requires:** TASK_ID, BASE_BRANCH, EXECUTION_PLAN + Based on Setup context (plan document, issue body, or conversation context), use the three-strategy framework: **Strategy Selection**: @@ -157,6 +162,9 @@ DOMAIN: {subtask 2 domain}" ### Phase 3: Validate +**Produces:** VALIDATION_RESULT +**Requires:** FILES_CHANGED + After Coder completes, spawn Validator to verify correctness: ``` @@ -187,6 +195,9 @@ Run build, typecheck, lint, test. Report pass/fail with failure details." ### Phase 4: Simplify +**Produces:** SIMPLIFIER_OUTPUT +**Requires:** FILES_CHANGED + After validation passes, spawn Simplifier to polish the code: ``` @@ -199,6 +210,9 @@ Focus on code modified by Coder, apply project standards, enhance clarity" ### Phase 5: Self-Review +**Produces:** SCRUTINIZER_OUTPUT +**Requires:** FILES_CHANGED + After Simplifier completes, spawn Scrutinizer as final quality gate: ``` @@ -212,6 +226,9 @@ If Scrutinizer returns BLOCKED, report to user and halt. ### Phase 6: Re-Validate (if Scrutinizer made changes) +**Produces:** REVALIDATION_RESULT +**Requires:** SCRUTINIZER_OUTPUT + If Scrutinizer made code changes (status: FIXED), spawn Validator to verify: ``` @@ -227,6 +244,9 @@ Verify Scrutinizer's fixes didn't break anything." ### Phase 7: Evaluator↔Coder Dialogue +**Produces:** ALIGNMENT_RESULT +**Requires:** FILES_CHANGED, EXECUTION_PLAN + After Scrutinizer passes (and re-validation if needed), check alignment using direct dialogue: Create a mini-team for alignment validation: @@ -318,6 +338,9 @@ Step 3: GATE — Verify TeamDelete succeeded ### Phase 8: QA Testing +**Produces:** QA_RESULT +**Requires:** FILES_CHANGED, EXECUTION_PLAN + After Evaluator passes, spawn Tester for scenario-based acceptance testing (standalone agent, not a teammate — testing is sequential, not debate): ``` @@ -357,12 +380,17 @@ Design and execute scenario-based acceptance tests. Report PASS or FAIL with evi ### Phase 9: Create PR +**Produces:** PR_URL +**Requires:** BASE_BRANCH, TASK_ID + **For SEQUENTIAL_CODERS or PARALLEL_CODERS**: The last sequential Coder (with CREATE_PR: true) handles PR creation. For parallel coders, create unified PR using `devflow:git` skill patterns. Push branch and run `gh pr create` with comprehensive description, targeting `BASE_BRANCH`. **For SINGLE_CODER**: PR is created by the Coder agent (CREATE_PR: true). ### Phase 10: Report +**Requires:** VALIDATION_RESULT, ALIGNMENT_RESULT, QA_RESULT, PR_URL + Display completion summary with phase status, PR info, and next steps. ## Phase 1.5: Load Project Knowledge +**Produces:** KNOWLEDGE_CONTEXT +**Requires:** REVIEW_DIR + Run `node scripts/hooks/lib/knowledge-context.cjs index "{worktree}"` to produce a compact index of active ADR/PF entries from `decisions.md` and `pitfalls.md`, with Deprecated/Superseded entries already stripped. Falls back to `(none)` when both files are absent or all entries are filtered. Pass `KNOWLEDGE_CONTEXT` to every Resolver agent in Phase 4. Resolver agents use `devflow:apply-knowledge` to Read full entry bodies on demand — no fan-out of the full corpus. ## Phase 2: Parse Issues +**Produces:** ISSUES +**Requires:** REVIEW_DIR + Read all `{focus}.md` files in the timestamped directory (exclude `review-summary.md` and `resolution-summary.md`). Extract **ALL** issues from all categories and severities, including Suggestions. @@ -49,6 +57,9 @@ If no actionable issues found: "Review is clean — no issues to resolve." → s ## Phase 3: Analyze & Batch +**Produces:** BATCHES +**Requires:** ISSUES + Group issues by file/function for efficient resolution: - Issues in the same file → same batch - Issues with cross-file dependencies → same batch @@ -58,6 +69,9 @@ Determine execution: batches with no shared files can run in parallel. ## Phase 4: Resolve (Parallel) +**Produces:** RESOLUTION_RESULTS +**Requires:** BATCHES, KNOWLEDGE_CONTEXT, BRANCH_SLUG + Spawn `Agent(subagent_type="Resolver")` agents — one per batch, parallel where possible. Each receives: @@ -73,6 +87,9 @@ Resolvers follow a 3-tier risk approach: ## Phase 5: Collect & Simplify +**Produces:** SIMPLIFICATION_RESULTS +**Requires:** RESOLUTION_RESULTS + Aggregate results from all Resolver agents: - Count: fixed, false positives, deferred @@ -80,6 +97,8 @@ Spawn `Agent(subagent_type="Simplifier")` on all files modified by Resolvers. ## Phase 6: Report +**Requires:** RESOLUTION_RESULTS, SIMPLIFICATION_RESULTS, REVIEW_DIR + Write `resolution-summary.md` to the same timestamped review directory. The report includes a `## Knowledge Citations` section at the top (before Statistics) listing all unique `applies ADR-NNN` and `avoids PF-NNN` references extracted from Resolver Reasoning columns. Omit the section entirely if no citations were made. @@ -97,3 +116,17 @@ Report to user: - **All issues false positive**: Report findings, write resolution-summary noting no changes needed - **Resolver BLOCKED**: Report which batch blocked, continue with remaining - **Simplifier fails**: Resolution still valid — report that simplification was skipped + +## Phase Completion Checklist + +Before reporting results, verify every phase was announced: + +- [ ] Phase 1: Target Review Directory → REVIEW_DIR captured +- [ ] Phase 1.5: Load Project Knowledge → KNOWLEDGE_CONTEXT captured +- [ ] Phase 2: Parse Issues → ISSUES captured (or stopped: no actionable issues) +- [ ] Phase 3: Analyze & Batch → BATCHES captured +- [ ] Phase 4: Resolve → RESOLUTION_RESULTS captured per batch +- [ ] Phase 5: Collect & Simplify → SIMPLIFICATION_RESULTS captured +- [ ] Phase 6: Report → resolution-summary.md written + +If any phase is unchecked, execute it before proceeding. diff --git a/shared/skills/review:orch/SKILL.md b/shared/skills/review:orch/SKILL.md index 6e33ae5f..3577e02b 100644 --- a/shared/skills/review:orch/SKILL.md +++ b/shared/skills/review:orch/SKILL.md @@ -19,8 +19,12 @@ This is a lightweight variant of `/code-review` for ambient ORCHESTRATED mode. E --- +**Continuation**: Phase 2 handles incremental detection via `.last-review-head` — no separate continuation path needed. + ## Phase 1: Pre-flight +**Produces:** BRANCH_INFO, PR_INFO + Spawn `Agent(subagent_type="Git")` with action `ensure-pr-ready`: - Extract: branch, base_branch, branch_slug, pr_number - If BLOCKED (detached HEAD, no commits ahead of base): halt with message @@ -29,6 +33,9 @@ Determine base branch: use PR target if PR exists, otherwise `main`/`master`. ## Phase 2: Incremental Detection +**Produces:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP +**Requires:** BRANCH_INFO + Check `.docs/reviews/{branch_slug}/.last-review-head`: - If file exists and SHA matches HEAD: "No new commits since last review. Nothing to do." → stop - If file exists and SHA differs: set `DIFF_RANGE={sha}...HEAD` (incremental) @@ -39,6 +46,9 @@ Create directory: `mkdir -p .docs/reviews/{branch_slug}/{timestamp}` ## Phase 2b: Load Knowledge Index +**Produces:** KNOWLEDGE_CONTEXT +**Requires:** REVIEW_DIR + After incremental detection, load the knowledge index: ```bash @@ -49,6 +59,9 @@ This produces a compact index of active ADR/PF entries. Pass `KNOWLEDGE_CONTEXT` ## Phase 3: File Analysis +**Produces:** REVIEWER_LIST +**Requires:** DIFF_RANGE + Run `git diff --name-only {DIFF_RANGE}` to get changed files. Detect conditional reviewers from file types: @@ -69,6 +82,9 @@ Detect conditional reviewers from file types: ## Phase 4: Reviews (Parallel) +**Produces:** REVIEWER_OUTPUTS +**Requires:** DIFF_RANGE, REVIEW_DIR, TIMESTAMP, KNOWLEDGE_CONTEXT, REVIEWER_LIST + Spawn all reviewers in a single message (parallel execution): **7 core reviewers** (always): @@ -86,6 +102,8 @@ Each reviewer receives: ## Phase 5: Synthesis (Parallel) +**Requires:** REVIEWER_OUTPUTS, REVIEW_DIR, PR_INFO + After all reviewers complete, spawn in parallel: 1. `Agent(subagent_type="Git")` with action `comment-pr` — post review summary as PR comment (deduplicate: check existing comments first) @@ -93,6 +111,8 @@ After all reviewers complete, spawn in parallel: ## Phase 6: Finalize +**Requires:** BRANCH_INFO, REVIEW_DIR + Write HEAD SHA to `.docs/reviews/{branch_slug}/.last-review-head` for next incremental review. Report to user: @@ -107,3 +127,17 @@ Report to user: - **No changed files**: "No changes to review." → stop - **Reviewer fails**: Report which reviewer failed, continue with remaining - **Synthesizer fails**: Reports are still on disk — user can read them directly + +## Phase Completion Checklist + +Before reporting results, verify every phase was announced: + +- [ ] Phase 1: Pre-flight → BRANCH_INFO, PR_INFO captured +- [ ] Phase 2: Incremental Detection → DIFF_RANGE, REVIEW_DIR, TIMESTAMP captured +- [ ] Phase 2b: Load Knowledge Index → KNOWLEDGE_CONTEXT captured +- [ ] Phase 3: File Analysis → REVIEWER_LIST captured +- [ ] Phase 4: Reviews → REVIEWER_OUTPUTS written to disk +- [ ] Phase 5: Synthesis → review-summary.md written +- [ ] Phase 6: Finalize → .last-review-head updated, results reported + +If any phase is unchecked, execute it before proceeding. diff --git a/shared/skills/router/SKILL.md b/shared/skills/router/SKILL.md index b8a1011d..845b8046 100644 --- a/shared/skills/router/SKILL.md +++ b/shared/skills/router/SKILL.md @@ -13,6 +13,16 @@ GUIDED: work directly in main session. Spawn Simplifier after code changes. - GUIDED PLAN: spawn Skimmer for orientation, then plan directly. ORCHESTRATED: follow the loaded orchestration skill's pipeline. +## Phase Protocol + +All ORCHESTRATED pipelines follow this protocol: + +1. **Announce** — Before executing each phase, output: `Phase N: {name}`. No phase may execute without this announcement. Skipping the announcement and doing the work anyway is a protocol violation. +2. **Produce** — Each phase declares what it `Produces:`. Capture that output by name. Subsequent phases reference it via `Requires:`. +3. **No silent skips** — If a phase's preconditions are not met (e.g., no issues found), announce the phase, state why it is being skipped, and move to the next phase. The announcement must still appear. +4. **Verify** — Before presenting final output, check the skill's Phase Completion Checklist. Every phase must show as announced. If any phase was missed, execute it before proceeding. +5. **Scoped nesting** — When a pipeline delegates to another orchestration skill (e.g., pipeline:orch → implement:orch), the inner skill's phases use a scoped prefix: `{Outer} > Phase N: {name}` (e.g., `Implement > Phase 1: Pre-flight`). + ## GUIDED | Intent | Skills | diff --git a/tests/ambient.test.ts b/tests/ambient.test.ts index 07eacf46..63abcaf4 100644 --- a/tests/ambient.test.ts +++ b/tests/ambient.test.ts @@ -693,6 +693,11 @@ describe('preamble drift detection', () => { expect(routerContent).toContain('DEBUG'); expect(routerContent).toContain('PLAN'); expect(routerContent).toContain('REVIEW'); + + // Must contain Phase Protocol section + expect(routerContent).toContain('## Phase Protocol'); + expect(routerContent).toContain('Announce'); + expect(routerContent).toContain('No silent skips'); }); it('session-start-classification hook reads classification-rules.md', async () => { @@ -702,3 +707,151 @@ describe('preamble drift detection', () => { expect(hookContent).toContain('classification-rules.md'); }); }); + +describe('phase protocol structural validation', () => { + const sharedSkillsDir = path.resolve(__dirname, '../shared/skills'); + + async function discoverOrchSkills(): Promise { + const entries = await fs.readdir(sharedSkillsDir); + return entries.filter(e => e.endsWith(':orch')).sort(); + } + + it('every orch skill has a Phase Completion Checklist', async () => { + for (const skill of await discoverOrchSkills()) { + const content = await fs.readFile( + path.join(sharedSkillsDir, skill, 'SKILL.md'), + 'utf-8', + ); + expect(content, `${skill} missing Phase Completion Checklist`).toContain( + '## Phase Completion Checklist', + ); + } + }); + + it('every orch skill has Produces: annotations', async () => { + for (const skill of await discoverOrchSkills()) { + const content = await fs.readFile( + path.join(sharedSkillsDir, skill, 'SKILL.md'), + 'utf-8', + ); + expect(content, `${skill} missing Produces: annotations`).toContain( + '**Produces:**', + ); + } + }); + + it('every orch skill has Requires: annotations', async () => { + for (const skill of await discoverOrchSkills()) { + const content = await fs.readFile( + path.join(sharedSkillsDir, skill, 'SKILL.md'), + 'utf-8', + ); + expect(content, `${skill} missing Requires: annotations`).toContain( + '**Requires:**', + ); + } + }); + + it('plan:orch and implement:orch have Continuation Detection', async () => { + for (const skill of ['plan:orch', 'implement:orch']) { + const content = await fs.readFile( + path.join(sharedSkillsDir, skill, 'SKILL.md'), + 'utf-8', + ); + expect(content, `${skill} missing Continuation Detection`).toContain( + '## Continuation Detection', + ); + } + }); + + it('checklist item count matches phase count in each orch skill', async () => { + for (const skill of await discoverOrchSkills()) { + const content = await fs.readFile( + path.join(sharedSkillsDir, skill, 'SKILL.md'), + 'utf-8', + ); + + // Count phase headings (## Phase N or ### Phase N — digit distinguishes from ## Phase Completion Checklist) + const phaseHeadings = content.match(/^#{2,3}\s+Phase\s+\d/gm) ?? []; + + // Count checklist items (- [ ] Phase) + const checklistItems = content.match(/^- \[ \] Phase/gm) ?? []; + + expect( + checklistItems.length, + `${skill}: ${checklistItems.length} checklist items but ${phaseHeadings.length} phases`, + ).toBe(phaseHeadings.length); + } + }); +}); + +describe('command Produces/Requires validation', () => { + const pluginsDir = path.resolve(__dirname, '../plugins'); + const phaseStepPattern = /^#{2,4}\s+(Phase|Step)\s+\d/; + + function headingLevel(line: string): number { + return (line.match(/^(#+)/) ?? ['', ''])[1].length; + } + + async function discoverCommandFiles(): Promise { + const plugins = await fs.readdir(pluginsDir); + const files: string[] = []; + for (const plugin of plugins) { + const cmdDir = path.join(pluginsDir, plugin, 'commands'); + try { + const entries = await fs.readdir(cmdDir); + for (const f of entries) { + if (f.endsWith('.md')) files.push(path.join(cmdDir, f)); + } + } catch { /* no commands dir */ } + } + return files.sort(); + } + + it('every command file has Produces: annotations', async () => { + for (const file of await discoverCommandFiles()) { + const content = await fs.readFile(file, 'utf-8'); + const name = path.relative(pluginsDir, file); + expect(content, `${name} missing Produces:`).toContain('**Produces:**'); + } + }); + + it('every command file has Requires: annotations', async () => { + for (const file of await discoverCommandFiles()) { + const content = await fs.readFile(file, 'utf-8'); + const name = path.relative(pluginsDir, file); + expect(content, `${name} missing Requires:`).toContain('**Requires:**'); + } + }); + + it('every phase/step heading is followed by a Produces or Requires annotation', async () => { + for (const file of await discoverCommandFiles()) { + const content = await fs.readFile(file, 'utf-8'); + const name = path.relative(pluginsDir, file); + const lines = content.split('\n'); + + const headingIndices: number[] = []; + for (let i = 0; i < lines.length; i++) { + if (phaseStepPattern.test(lines[i])) headingIndices.push(i); + } + + for (let h = 0; h < headingIndices.length; h++) { + const idx = headingIndices[h]; + const currentLevel = headingLevel(lines[idx]); + + // Skip container headings (next heading is deeper level = substeps) + if (h + 1 < headingIndices.length) { + if (headingLevel(lines[headingIndices[h + 1]]) > currentLevel) continue; + } + + const endIdx = h + 1 < headingIndices.length ? headingIndices[h + 1] : lines.length; + const body = lines.slice(idx + 1, endIdx).join('\n'); + + expect( + body.includes('**Produces:**') || body.includes('**Requires:**'), + `${name}: "${lines[idx].trim()}" missing Produces/Requires annotation`, + ).toBe(true); + } + } + }); +});