diff --git a/.agents/skills/deft-directive-swarm/SKILL.md b/.agents/skills/deft-directive-swarm/SKILL.md new file mode 100644 index 00000000..c1a2d43e --- /dev/null +++ b/.agents/skills/deft-directive-swarm/SKILL.md @@ -0,0 +1,10 @@ +--- +name: deft-directive-swarm +description: >- + Parallel local agent orchestration. Use when running multiple agents + on vBRIEF stories simultaneously — to scan active/ for allocatable work, + set up isolated worktrees, launch agents with proven prompts, monitor + progress, handle stalled review cycles, and close out PRs cleanly. +--- + +Read and follow: skills/deft-directive-swarm/SKILL.md diff --git a/.agents/skills/deft-swarm/SKILL.md b/.agents/skills/deft-swarm/SKILL.md deleted file mode 100644 index 0fd170e3..00000000 --- a/.agents/skills/deft-swarm/SKILL.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: deft-swarm -description: >- - Parallel local agent orchestration. Use when running multiple agents - on roadmap items simultaneously — to select non-overlapping tasks, set up - isolated worktrees, launch agents with proven prompts, monitor progress, - handle stalled review cycles, and close out PRs cleanly. ---- - -Read and follow: skills/deft-swarm/SKILL.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 506d2004..2b919bf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **feat(installer): rewrite Go installer thin pointers for deft-directive-* namespace** (#332, Part of #309): Renamed 5 existing skill thin pointer constants from deft-* to deft-directive-* (deft-setup -> deft-directive-setup, deft-build -> deft-directive-build, deft-review-cycle -> deft-directive-review-cycle, deft-roadmap-refresh -> deft-directive-refinement, deft-swarm -> deft-directive-swarm); added 3 new skill thin pointers (deft-directive-interview, deft-directive-pre-pr, deft-directive-sync); expanded allSkillNames from 6 to 9 entries; updated agentsMDEntry to reference deft-directive-setup paths and PROJECT-DEFINITION.vbrief.json; added 5 new tests covering 9-skill count, individual pointer content for interview/pre-pr/sync, and refinement-replaces-roadmap-refresh assertion; updated all existing test assertions for new skill names +- **docs(vbrief): rename deft-swarm to deft-directive-swarm with flexible vBRIEF allocation** (#317, Part of #309): Renamed `skills/deft-swarm/` to `skills/deft-directive-swarm/` and updated `.agents/skills/` thin pointer; updated SKILL.md frontmatter name to `deft-directive-swarm`; rewrote Phase 0 from ROADMAP.md/SPECIFICATION.md analysis to vBRIEF-centric allocation -- monitor scans `vbrief/active/` for story-level vBRIEFs and allocates one or more per agent based on scope, complexity, and dependencies (no fixed 1:1 rule); added Phase 5 "Complete vBRIEFs" subsection -- move vBRIEF from `active/` to `completed/` via `task scope:complete`, update `plan.status`, read `references` and close origin issues; updated all cross-skill references from `deft-*` to `deft-directive-*`; removed all ROADMAP.md/SPECIFICATION.md source-of-truth references; updated prompt template to reference `vbrief/active/` for task discovery; added 2 new anti-patterns (hardcoded 1:1 allocation, completing without vBRIEF lifecycle update); updated 41 test functions in `tests/content/test_skills.py` for new path and added 7 new tests for #317 acceptance criteria - **docs(vbrief): update ancillary framework docs for vBRIEF-centric model** (#331, Part of #309): Updated 11 ancillary framework documents for the new vBRIEF-centric document model -- REFERENCES.md (PROJECT.md -> PROJECT-DEFINITION.vbrief.json, lifecycle folders and scope vBRIEFs in loading scenarios and reference chains), README.md (skill names deft-* -> deft-directive-*, directory structure with lifecycle folders, Your Artifacts section rewritten for scope vBRIEFs), CONTRIBUTING.md (CLI command descriptions updated for scope vBRIEFs), commands.md (spec delta merge updated for scope vBRIEFs instead of SPECIFICATION.md), strategies/interview.md (deft-setup -> deft-directive-setup, implementation target updated to scope vBRIEFs), strategies/map.md and strategies/speckit.md (PROJECT.md -> PROJECT-DEFINITION.vbrief.json), templates/make-spec.md (spec flow rewritten to produce scope vBRIEFs in lifecycle folders), context/working-memory.md (plan.vbrief.json + scope vBRIEF planRef relationship per D15, lifecycle folders as non-scratch), resilience/continue-here.md (continue.vbrief.json + scope vBRIEF planRef per D15), context/long-horizon.md (planRef to scope vBRIEFs, scope:complete lifecycle, anti-pattern for scratch misuse) - **Core doc updates for vBRIEF-centric model** (#313, Part of #309): Updated main.md -- replaced all PROJECT.md references with PROJECT-DEFINITION.vbrief.json (Rule Precedence, Framework Structure, Decision Making branching rule, Context Awareness), rewrote vBRIEF Persistence section to include lifecycle folder structure (proposed/, pending/, active/, completed/, cancelled/), scope vBRIEF filename convention (YYYY-MM-DD-descriptive-slug.vbrief.json), PROJECT-DEFINITION.vbrief.json as project identity gestalt, and folder-move prohibition. Updated AGENTS.md -- collapsed First Session gate from 3 checks (USER.md + PROJECT.md + SPECIFICATION.md) to 2 checks (USER.md + PROJECT-DEFINITION.vbrief.json), renamed all skill paths from deft-* to deft-directive-* (8 entries), replaced "roadmap refresh" / "triage" / "refresh roadmap" triggers with "refinement" / "reprioritize" / "refine", updated Development Process to check scope vBRIEF coverage instead of SPECIFICATION.md task coverage, updated branching rule PROJECT.md reference. Updated test assertion in test_agents_md.py to match new scope vBRIEF check wording. diff --git a/scm/github.md b/scm/github.md index 1b097bc4..26326789 100644 --- a/scm/github.md +++ b/scm/github.md @@ -90,7 +90,7 @@ Rules that apply to every `gh` invocation, regardless of context. ``` gh issue close --comment "Closed by # (squash merge -- auto-close did not trigger)" ``` -3. ~ This applies to ALL PR merges, not just swarm runs. See also: `skills/deft-review-cycle/SKILL.md` Post-Merge Verification, `skills/deft-swarm/SKILL.md` Phase 6 Step 2. +3. ~ This applies to ALL PR merges, not just swarm runs. See also: `skills/deft-review-cycle/SKILL.md` Post-Merge Verification, `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 2. ## Windows / PowerShell Encoding Guidance diff --git a/skills/deft-swarm/SKILL.md b/skills/deft-directive-swarm/SKILL.md similarity index 79% rename from skills/deft-swarm/SKILL.md rename to skills/deft-directive-swarm/SKILL.md index 356aae67..4389b95a 100644 --- a/skills/deft-swarm/SKILL.md +++ b/skills/deft-directive-swarm/SKILL.md @@ -1,15 +1,15 @@ --- -name: deft-swarm +name: deft-directive-swarm description: > Parallel local agent orchestration. Use when running multiple agents - on roadmap items simultaneously — to select non-overlapping tasks, set up - isolated worktrees, launch agents with proven prompts, monitor progress, - handle stalled review cycles, and close out PRs cleanly. + on story-level vBRIEFs simultaneously — to scan active/ for allocatable + work, set up isolated worktrees, launch agents with proven prompts, + monitor progress, handle stalled review cycles, and close out PRs cleanly. --- -# Deft Swarm +# Deft Directive Swarm -Structured workflow for a monitor agent to orchestrate N parallel local agents working on roadmap items. +Structured workflow for a monitor agent to orchestrate N parallel local agents working on story-level vBRIEFs from `vbrief/active/`. Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY. @@ -17,79 +17,86 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY. ## When to Use -- User says "run agents", "parallel agents", "swarm", or "launch N agents on roadmap items" -- Multiple independent roadmap items need to be worked on simultaneously -- A batch of Phase 1/Phase 2 items are ready and have no mutual dependencies +- User says "run agents", "parallel agents", "swarm", or "launch N agents on stories" +- Multiple independent story-level vBRIEFs in `vbrief/active/` need to be worked on simultaneously +- A batch of stories are ready and have no mutual dependencies ## Prerequisites -- ! ROADMAP.md and SPECIFICATION.md exist with actionable items +- ! `vbrief/active/` contains one or more story-level vBRIEFs with status `running` - ! GitHub CLI (`gh`) is authenticated - ! `git` supports worktrees (`git worktree` available) - ~ `oz` CLI available (for `oz agent run-cloud` cloud launch — see Phase 3 Step 2c) -## Phase 0 — Analyze +## Phase 0 — Allocate -! Before selecting tasks, analyze the roadmap and specification state to surface blockers and missing coverage. +! Before assigning work to agents, scan the active vBRIEFs and plan allocation. ### Step 1: Read Project State -- ! Read ROADMAP.md for open items, priorities, and phase assignments -- ! Read SPECIFICATION.md for task coverage, statuses, and dependency chains -- ! Cross-reference: every candidate roadmap item should have a corresponding spec task +- ! Scan `vbrief/active/` for all story-level vBRIEFs (files matching `*.vbrief.json`) +- ! Read each vBRIEF's `plan.title`, `plan.status`, `plan.items`, `references`, and `planRef` (for epic linkage) +- ! Read `vbrief/PROJECT-DEFINITION.vbrief.json` for project-wide context (narratives, scope registry) +- ! Cross-reference: every candidate vBRIEF should have acceptance criteria in its `plan.items` ### Step 2: Surface Blockers -- ! Identify blocked spec tasks (status `[blocked]`) and their blocking reasons -- ! Identify roadmap items with no corresponding spec task (missing spec coverage) -- ! For each candidate item missing spec coverage: create a skeleton spec task in SPECIFICATION.md before proceeding to Phase 1. Use the format defined in `skills/deft-roadmap-refresh/SKILL.md` Phase 2 Step 4. Swarm agents cannot implement work that has no spec task -- the skeleton ensures every assigned task has a traceable spec entry. -- ! Identify dependency conflicts between candidate items (e.g. task A depends on task B, but B is assigned to a different agent or is incomplete) -- ! Flag any candidate items whose prerequisites are unmet +- ! Identify blocked vBRIEFs (status `blocked`) and their blocking reasons (check `narrative` fields) +- ! Identify vBRIEFs with incomplete acceptance criteria (no `plan.items` or empty items array) +- ! Identify dependency conflicts between candidate vBRIEFs (e.g. story A depends on story B via `planRef` or `edges`, but B is assigned to a different agent or is incomplete) +- ! Flag any candidate vBRIEFs whose prerequisites are unmet -### Step 3: Present Analysis +### Step 3: Plan Allocation + +! The monitor allocates one or more vBRIEFs to each agent based on scope, complexity, and dependencies. There is no fixed per-agent limit. + +- ! **Small/independent stories** can be batched to a single agent — group related or low-complexity vBRIEFs together +- ! **Large/complex stories** get dedicated agents — a story with broad file scope or high acceptance criteria count should not share an agent +- ! **Dependency-aware grouping** — vBRIEFs that share `planRef` to the same epic or have `edges` between them should be assigned to the same agent when possible, OR sequenced with clear ordering +- ! The monitor decides allocation dynamically — no hardcoded 1:1 rule + +### Step 4: Present Analysis ! Present a summary to the user containing: -- **Candidate items**: roadmap items eligible for assignment (with spec task IDs and statuses) -- **Blockers found**: blocked tasks, unresolved dependencies, items requiring design decisions -- **Missing spec tasks**: roadmap items that need spec task creation before work can begin -- **Recommendations**: suggested items to include or exclude, with reasoning +- **Candidate vBRIEFs**: story-level vBRIEFs eligible for assignment (with titles, statuses, and origin references) +- **Blockers found**: blocked vBRIEFs, unresolved dependencies, items requiring design decisions +- **Incomplete vBRIEFs**: stories with missing or empty acceptance criteria +- **Allocation plan**: which agent gets which vBRIEF(s), with reasoning for batching decisions - **Tentative version bump**: current version (from CHANGELOG.md or latest git tag) and proposed next version (patch/minor/major) based on the scope and nature of candidate items — this is advisory and will be confirmed before merge cascade -### Step 4: Get User Approval +### Step 5: Get User Approval - ! Wait for explicit user approval (`yes`, `confirmed`, `approve`) before proceeding to Phase 1 (Select) -- ! If the user requests changes to the candidate list, re-analyze and re-present -- ⊗ Proceed to Phase 1 (Select) without completing the analyze phase and receiving explicit user approval +- ! If the user requests changes to the allocation plan, re-analyze and re-present +- ⊗ Proceed to Phase 1 (Select) without completing the allocate phase and receiving explicit user approval ## Phase 1 — Select -! Pick N items from ROADMAP.md and assign to agents. Each agent gets a coherent set of related work. +! Finalize assignments from the allocation plan. Each agent gets a coherent set of related work. -### Step 1: Identify Candidates +### Step 1: Confirm Candidates -- ! Use the candidate list and cross-reference produced in Phase 0 — Analyze as the starting point -- ! Re-read ROADMAP.md and SPECIFICATION.md only if Phase 0 was skipped (user override) or context was lost -- ! Cross-reference ROADMAP.md items against SPECIFICATION.md task status — if a roadmap item has a spec task marked `[completed]`, verify the work is actually done (check files) before assigning. ROADMAP.md may lag behind SPECIFICATION.md. -- ! Exclude items that are blocked, have unresolved dependencies, or require design decisions +- ! Use the allocation plan and vBRIEF analysis from Phase 0 as the starting point +- ! Re-read `vbrief/active/` only if Phase 0 was skipped (user override) or context was lost +- ! For each candidate vBRIEF, verify its `plan.status` is `running` (not `blocked` or `completed`) +- ! Exclude vBRIEFs that are blocked, have unresolved dependencies, or require design decisions ### Step 2: File-Overlap Audit -! Before assigning tasks to agents, list every file each task is expected to touch. +! Before assigning tasks to agents, list every file each vBRIEF's acceptance criteria are expected to touch. - ! Verify ZERO file overlap between agents — no two agents may modify the same file -- ! Check **transitive** file touches, not just primary scope — trace each task's acceptance criteria to specific files. A task may require changes to files outside its obvious scope (e.g., an enforcement task adding an anti-pattern to a skill file owned by another agent). -- ! Shared files (CHANGELOG.md, SPECIFICATION.md) are exceptions — each agent adds entries but does not edit existing content +- ! Check **transitive** file touches, not just primary scope — trace each vBRIEF's acceptance criteria to specific files. A task may require changes to files outside its obvious scope (e.g., an enforcement task adding an anti-pattern to a skill file owned by another agent). +- ! Shared files (CHANGELOG.md) are exceptions — each agent adds entries but does not edit existing content - ! If overlap exists, reassign tasks until overlap is eliminated -⊗ Include ROADMAP.md as a shared exception — ROADMAP.md is updated only at release time by the monitor/release manager, not by swarm agents. - ⊗ Proceed to Phase 2 while any file overlap exists between agents (excluding shared append-only files). ⊗ Assume a task only touches files in its primary scope — always check acceptance criteria for cross-file requirements. ### Step 3: Present Assignment -- ! Show the user: agent number, branch name, assigned tasks (with issue numbers), and files each agent will touch +- ! Show the user: agent number, branch name, assigned vBRIEF(s) (with origin issue numbers), and files each agent will touch - ~ Wait for user approval unless the user explicitly said to proceed autonomously ## Phase 2 — Setup @@ -185,7 +192,7 @@ Agents execute on remote VMs without local MCP servers, codebase indexing, or Wa Track each agent through these stages: -1. **Reading** — agent is loading AGENTS.md, SPECIFICATION.md, project files (no file changes yet) +1. **Reading** — agent is loading AGENTS.md, vBRIEF files, project files (no file changes yet) 2. **Implementing** — working tree shows modified files 3. **Validating** — agent running `task check` 4. **Committed** — new commit(s) in `git log` @@ -223,7 +230,7 @@ When taking over: read the agent's current state (git log, diff, PR comments), c - ~ Target <100 tool-call round-trips in any single monitor conversation before considering a fresh session handoff - ! If the monitor detects degraded output (repeated errors, inconsistent state references, tool call failures), stop and hand off to a fresh session with a state summary rather than continuing in a corrupted context -## Phase 5 — Review +## Phase 5 — Review & Complete ### Verify Review Cycle Completion @@ -234,11 +241,21 @@ For each agent's PR: 3. ! Verify no P0 or P1 issues remain (P2 are non-blocking style suggestions) 4. ! If the agent did not complete its review cycle, the monitor runs it per `skills/deft-review-cycle/SKILL.md` +### Complete vBRIEFs + +For each story vBRIEF that an agent's PR fully resolves: + +1. ! Move the vBRIEF from `vbrief/active/` to `vbrief/completed/` via `task scope:complete ` +2. ! Verify `plan.status` is set to `completed` (the scope command handles this) +3. ! If the vBRIEF has a `planRef` to a parent epic, check whether all sibling stories are now completed — if so, the epic may also be completable + +⚠️ Origin/issue closure happens in Phase 6 Step 2 (after merge), not here — closing issues before merge creates premature state if the merge cascade fails. + ### Exit Condition All PRs meet ALL of: - Greptile confidence > 3 -- No P0 or P1 issues remain (P2 issues are non-blocking style suggestions and do not gate merge) +- No P0 or P1 issues remain (P2 issues are non-blocking style suggestions) - `task check` passed (or equivalent validation completed) - CHANGELOG entries present under `[Unreleased]` @@ -279,12 +296,12 @@ All PRs meet ALL of: - ! No conflict markers remain (`<<<<<<<`, `=======`, `>>>>>>>`) - ! No collapsed or missing lines (compare line count to pre-rebase version if feasible) - ! No encoding artifacts (BOM injection, mojibake, replacement characters) -- ! For `CHANGELOG.md` and `SPECIFICATION.md` conflicts: prefer `edit_files` over shell regex (`sed`, `Select-String -replace`) for resolution -- edit_files preserves encoding and provides exact match verification, while regex substitutions risk silent line collapse or encoding corruption +- ! For `CHANGELOG.md` conflicts: prefer `edit_files` over shell regex (`sed`, `Select-String -replace`) for resolution -- edit_files preserves encoding and provides exact match verification, while regex substitutions risk silent line collapse or encoding corruption - ⊗ Run `git add` on a conflict-resolved file without first re-reading it and verifying structural integrity ! **Non-interactive rebase:** Monitor MUST set `GIT_EDITOR=true` (Unix/WSL/Git Bash) or `$env:GIT_EDITOR="echo"` (Windows PowerShell) before running `git rebase --continue` during merge cascade to prevent the default editor from blocking the agent. -! **Merge cascade warning:** Shared append-only files (CHANGELOG.md, SPECIFICATION.md) cause merge conflicts when PRs are merged sequentially — each merge changes the insertion point, conflicting remaining PRs. Each conflict requires rebase → push → wait for checks (~3 min) + ~2-5 min Greptile re-review per rebase. Plan for N-1 rebase cycles × ~3 min CI + ~2-5 min Greptile re-review per rebase when merging N PRs. +! **Merge cascade warning:** Shared append-only files (CHANGELOG.md) cause merge conflicts when PRs are merged sequentially — each merge changes the insertion point, conflicting remaining PRs. Each conflict requires rebase → push → wait for checks (~3 min) + ~2-5 min Greptile re-review per rebase. Plan for N-1 rebase cycles × ~3 min CI + ~2-5 min Greptile re-review per rebase when merging N PRs. ! **Greptile re-review on rebase force-push:** Force-pushing a rebased branch triggers a **full** Greptile re-review (not an incremental diff), even if the rebase introduced no logic changes. Expected latency is ~2-5 minutes per PR in the cascade. Factor this into merge sequencing. @@ -303,11 +320,14 @@ All PRs meet ALL of: - ! Use descriptive squash subject: `type(scope): description (#issues)` - ! After each merge, rebase remaining PRs onto updated master before merging the next -### Step 2: Close Issues +### Step 2: Close Issues and Update Origins - ! Close resolved issues with a comment referencing the PR - ~ Issues with "Closes #N" in PR body auto-close on squash merge - ! After each squash merge, verify issues actually closed: `gh issue view --json state --jq .state`. If not closed, close manually with a comment referencing the merged PR. Squash merge + closing keywords can silently fail to close issues (#167). +- ! For each completed vBRIEF: read its `references` array and update each origin: + - For `github-issue` references: verify the issue is closed (auto-close from PR body or Phase 6 Step 2 above); if not, close with `gh issue close --comment "Completed in #"` + - For other reference types: document the completion as appropriate ### Step 3: Update Master @@ -320,13 +340,7 @@ All PRs meet ALL of: - ~ Delete launch scripts if still present - ? If worktree removal fails (locked files from open terminals), note for manual cleanup -### Step 5: Update ROADMAP.md (release time only) - -~ ROADMAP.md is updated during the CHANGELOG promotion commit (the release commit), not during swarm close. Batch-move all issues resolved in this release from their roadmap phase to the Completed section at that time. - -⊗ Update ROADMAP.md during swarm close — leave it for the release commit. - -### Step 6: Generate Slack Release Announcement +### Step 5: Generate Slack Release Announcement ! After creating the GitHub release (or after the final merge if no formal release is created), generate a standard Slack announcement block and present it to the user for copy-paste into the team channel. @@ -399,14 +413,14 @@ This is a git worktree. Do NOT just read files and stop — you must implement a run task check, commit, push, create a PR, and run the review cycle. DO NOT STOP until all steps are complete. -STEP 1 — Read directives: Read AGENTS.md, PROJECT.md, SPECIFICATION.md, main.md. +STEP 1 — Read directives: Read AGENTS.md, vbrief/vbrief.md, and the assigned vBRIEF(s) from vbrief/active/. Read skills/deft-review-cycle/SKILL.md. -STEP 2 — Implement these N tasks (see SPECIFICATION.md for full acceptance criteria): +STEP 2 — Implement these N tasks (see assigned vBRIEF(s) for full acceptance criteria): -Task A ([spec-task-id], issue #[N]): [one-paragraph description with specific acceptance criteria] +Task A (vBRIEF: [filename], issue #[N]): [one-paragraph description with specific acceptance criteria] -Task B ([spec-task-id], issue #[N]): [one-paragraph description with specific acceptance criteria] +Task B (vBRIEF: [filename], issue #[N]): [one-paragraph description with specific acceptance criteria] [...repeat for each task...] @@ -434,7 +448,7 @@ CONSTRAINTS: - ! First line MUST start with `TASK:` followed by an imperative statement - ! Include `DO NOT STOP until all steps are complete` in the preamble -- ! Each task MUST include its spec task ID and issue number +- ! Each task MUST include its vBRIEF filename and origin issue number - ! CONSTRAINTS section MUST list files the agent must not touch (other agents' scope) - ! Review cycle step MUST reference `skills/deft-review-cycle/SKILL.md` explicitly - ⊗ Start the prompt with context ("You are working in...") — agents treat this as passive setup and may stop after reading @@ -450,19 +464,20 @@ CONSTRAINTS: - ⊗ Assign overlapping files to multiple agents - ⊗ Merge PRs before Greptile exit condition is met (score > 3, no P0/P1) - ⊗ Assume agents will complete the full workflow — always verify review cycle completion -- ⊗ Launch agents without checking SPECIFICATION.md for task coverage first +- ⊗ Launch agents without checking vBRIEF acceptance criteria first - ⊗ Skip the file-overlap audit in Phase 1 - ⊗ Use `git reset --hard` or force-push in any worktree (swarm agents only -- monitor may `--force-with-lease` after rebase cascade per Phase 6 Step 1) - ⊗ Present static launch options (A/B/C) instead of detecting capabilities at runtime — always probe for `start_agent` and Warp environment variables before choosing a launch path - ⊗ Offer Warp-specific launch paths (tabs, `start_agent`) when not running inside Warp — gate on `WARP_*` environment variables or `start_agent` tool presence - ⊗ Default to `oz agent run-cloud` — cloud is an explicit user-requested escape hatch, not a default path - ⊗ Use `oz agent run-cloud` when the user expects local execution — `run-cloud` routes to remote VMs with no local context -- ⊗ Proceed to Phase 1 (Select) without completing Phase 0 (Analyze) and receiving explicit user approval -- ⊗ Update ROADMAP.md during swarm close — it is updated only at release time (CHANGELOG promotion commit), not by individual agents or during PR merges. +- ⊗ Proceed to Phase 1 (Select) without completing Phase 0 (Allocate) and receiving explicit user approval - ⊗ Begin merge cascade without presenting the version bump proposal and receiving explicit user approval — the Phase 5→6 gate is mandatory - ⊗ Ignore Greptile re-review latency when planning merge cascade timing -- each rebase force-push triggers a full re-review (~2-5 min), not an incremental diff - ⊗ Proceed to the next merge in the rebase cascade before confirming the Greptile re-review is current (SHA match) and exit condition is met (confidence > 3, no P0/P1) on the rebased branch -- see `skills/deft-review-cycle/SKILL.md` Step 4 for the monitoring approach - ⊗ Spawn a replacement sub-agent without confirming the original is unresponsive via a lifecycle event (idle/blocked) — original Warp tabs can resume after apparent failure, and two concurrent agents on the same worktree will corrupt the tool_use/tool_result call chain (#261, #263) - ⊗ Skip Phase 5 or the Phase 5→6 confirmation gate under time pressure or due to long context — the gate is mandatory regardless of conversation length, elapsed time, or context-window pressure - ⊗ Run `git add` on a conflict-resolved file without re-reading and verifying structural integrity (no conflict markers, no collapsed lines, no encoding artifacts) -- see Phase 6 Step 1 read-back verification rule (#288) -- ⊗ Use shell regex (`sed`, `Select-String -replace`) to resolve `CHANGELOG.md` or `SPECIFICATION.md` rebase conflicts -- prefer `edit_files` for encoding safety and exact match verification (#288) +- ⊗ Use shell regex (`sed`, `Select-String -replace`) to resolve `CHANGELOG.md` rebase conflicts -- prefer `edit_files` for encoding safety and exact match verification (#288) +- ⊗ Hardcode a 1:1 vBRIEF-per-agent allocation rule — the monitor decides allocation dynamically based on scope, complexity, and dependencies +- ⊗ Complete a story without moving its vBRIEF from `active/` to `completed/` and updating its origin references diff --git a/skills/deft-review-cycle/SKILL.md b/skills/deft-review-cycle/SKILL.md index 9d12dd34..f77bf8dc 100644 --- a/skills/deft-review-cycle/SKILL.md +++ b/skills/deft-review-cycle/SKILL.md @@ -73,7 +73,7 @@ gh pr view --comments Both commands extract the "Comments Outside Diff" section with surrounding context, avoiding the need to process the full output. -! **MCP capability probe** (mirrors deft-swarm Phase 3 pattern): Before attempting MCP `get_review_comments`, probe whether MCP GitHub tools are available in the current session. Detection: attempt a lightweight MCP call (e.g. list available tools or a no-op query) -- if it succeeds, MCP is available; if it errors or the tool is not in the available set, MCP is unavailable. +! **MCP capability probe** (mirrors deft-directive-swarm Phase 3 pattern): Before attempting MCP `get_review_comments`, probe whether MCP GitHub tools are available in the current session. Detection: attempt a lightweight MCP call (e.g. list available tools or a no-op query) -- if it succeeds, MCP is available; if it errors or the tool is not in the available set, MCP is unavailable. - **MCP available**: ! Use MCP `get_review_comments` as the second source to catch Comments Outside Diff. - **MCP unavailable** (e.g. `start_agent` agents, cloud agents, `oz agent run`): ! Use `gh api repos///pulls//comments` as the explicit fallback for the second review source. Document in the commit message or PR comment why MCP was skipped (e.g. "MCP unavailable in this session -- used gh api fallback for review comments"). @@ -134,7 +134,7 @@ Both commands extract the "Comments Outside Diff" section with surrounding conte - **Tier 2 -- no `start_agent`, but scheduler/timer/auto-reinvocation available** → Approach 2 (yield-between-polls) - **Tier 3 -- interactive session, no `start_agent`, no timer/scheduler** → Approach 3 (blocking sleep loop as last resort) -! Detection: probe for `start_agent` in the available tool set (same pattern as deft-swarm Phase 3). If absent, check whether the runtime supports auto-reinvocation after yield (timer, scheduler, or CI trigger). If neither is available and the session is interactive, fall through to Approach 3. +! Detection: probe for `start_agent` in the available tool set (same pattern as deft-directive-swarm Phase 3). If absent, check whether the runtime supports auto-reinvocation after yield (timer, scheduler, or CI trigger). If neither is available and the session is interactive, fall through to Approach 3. ! Swarm agents launched via `start_agent` SHOULD prefer Approach 1 (spawn their own review-monitor sub-agent) when `start_agent` is available. Approach 2's yield-between-polls mechanism is not self-sustaining for swarm agents (see Approach 2 warning below). @@ -249,7 +249,7 @@ Choose whichever minimizes steps and maximizes clarity for the given task. ``` gh issue close --comment "Closed by # (squash merge — auto-close did not trigger)" ``` -3. ~ This step mirrors `skills/deft-swarm/SKILL.md` Phase 6 Step 2 and applies to ALL PR merges, not just swarm runs. +3. ~ This step mirrors `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 2 and applies to ALL PR merges, not just swarm runs. ## Anti-Patterns diff --git a/tests/content/test_skills.py b/tests/content/test_skills.py index 08fdce3b..beaa8551 100644 --- a/tests/content/test_skills.py +++ b/tests/content/test_skills.py @@ -281,21 +281,21 @@ def test_deft_build_references_task_test_coverage() -> None: # --------------------------------------------------------------------------- -# 12. deft-swarm skill — file existence and RFC2119 (#188, #199) +# 12. deft-directive-swarm skill — file existence and RFC2119 (#188, #199, #317) # --------------------------------------------------------------------------- -_SWARM_PATH = "skills/deft-swarm/SKILL.md" +_SWARM_PATH = "skills/deft-directive-swarm/SKILL.md" -def test_deft_swarm_exists() -> None: - """deft-swarm SKILL.md must exist at its expected path.""" +def test_deft_directive_swarm_exists() -> None: + """deft-directive-swarm SKILL.md must exist at its expected path.""" assert (_REPO_ROOT / _SWARM_PATH).is_file(), ( f"Skill file missing: {_SWARM_PATH}" ) -def test_deft_swarm_rfc2119_legend() -> None: - """deft-swarm must contain the RFC2119 legend line.""" +def test_deft_directive_swarm_rfc2119_legend() -> None: + """deft-directive-swarm must contain the RFC2119 legend line.""" text = _read_skill(_SWARM_PATH) assert RFC2119_LEGEND in text, ( f"{_SWARM_PATH}: missing RFC2119 legend '{RFC2119_LEGEND}'" @@ -303,34 +303,34 @@ def test_deft_swarm_rfc2119_legend() -> None: # --------------------------------------------------------------------------- -# 13. deft-swarm Phase 0 — Analyze (mandatory analyze phase, #199, t1.9.4) +# 13. deft-directive-swarm Phase 0 — Allocate (vBRIEF allocation, #199, #317) # --------------------------------------------------------------------------- -def test_deft_swarm_phase0_analyze_heading() -> None: - """deft-swarm must contain Phase 0 — Analyze heading.""" +def test_deft_directive_swarm_phase0_allocate_heading() -> None: + """deft-directive-swarm must contain Phase 0 — Allocate heading.""" text = _read_skill(_SWARM_PATH) - assert "## Phase 0" in text and "Analyze" in text, ( - f"{_SWARM_PATH}: missing Phase 0 — Analyze section (#199)" + assert "## Phase 0" in text and "Allocate" in text, ( + f"{_SWARM_PATH}: missing Phase 0 -- Allocate section (#317)" ) -def test_deft_swarm_phase0_reads_roadmap_and_spec() -> None: - """Phase 0 must read ROADMAP.md and SPECIFICATION.md.""" +def test_deft_directive_swarm_phase0_scans_vbrief_active() -> None: + """Phase 0 must scan vbrief/active/ for story-level vBRIEFs.""" text = _read_skill(_SWARM_PATH) - assert "ROADMAP.md" in text and "SPECIFICATION.md" in text, ( - f"{_SWARM_PATH}: Phase 0 must read ROADMAP.md and SPECIFICATION.md" + assert "vbrief/active/" in text and "vbrief.json" in text, ( + f"{_SWARM_PATH}: Phase 0 must scan vbrief/active/ for vBRIEFs (#317)" ) -def test_deft_swarm_phase0_surfaces_blockers() -> None: +def test_deft_directive_swarm_phase0_surfaces_blockers() -> None: """Phase 0 must surface blockers.""" text = _read_skill(_SWARM_PATH) - assert "blocked" in text.lower() and "missing spec" in text.lower(), ( - f"{_SWARM_PATH}: Phase 0 must surface blockers and missing spec coverage" + assert "blocked" in text.lower() and "incomplete" in text.lower(), ( + f"{_SWARM_PATH}: Phase 0 must surface blockers and incomplete vBRIEFs" ) -def test_deft_swarm_phase0_approval_gate() -> None: +def test_deft_directive_swarm_phase0_approval_gate() -> None: """Phase 0 must require explicit user approval before Phase 1.""" text = _read_skill(_SWARM_PATH) assert "yes" in text and "confirmed" in text and "approve" in text, ( @@ -338,7 +338,7 @@ def test_deft_swarm_phase0_approval_gate() -> None: ) -def test_deft_swarm_phase0_antipattern() -> None: +def test_deft_directive_swarm_phase0_antipattern() -> None: """Anti-patterns must prohibit proceeding to Phase 1 without Phase 0.""" text = _read_skill(_SWARM_PATH) assert "Phase 1 (Select) without completing Phase 0" in text, ( @@ -346,11 +346,25 @@ def test_deft_swarm_phase0_antipattern() -> None: ) +def test_deft_directive_swarm_flexible_allocation() -> None: + """Phase 0 must support flexible multi-vBRIEF allocation per agent (#317).""" + text = _read_skill(_SWARM_PATH) + assert "no fixed per-agent limit" in text.lower() or "no hardcoded 1:1 rule" in text.lower(), ( + f"{_SWARM_PATH}: Phase 0 must support flexible allocation (no fixed 1:1) (#317)" + ) + assert "small/independent stories" in text.lower() and "batched" in text.lower(), ( + f"{_SWARM_PATH}: Phase 0 must allow batching small stories (#317)" + ) + assert "large/complex stories" in text.lower() and "dedicated" in text.lower(), ( + f"{_SWARM_PATH}: Phase 0 must allow dedicated agents for large stories (#317)" + ) + + # --------------------------------------------------------------------------- -# 14. deft-swarm Phase 3 — Runtime capability detection (#188, t1.9.3) +# 14. deft-directive-swarm Phase 3 — Runtime capability detection (#188, t1.9.3) # --------------------------------------------------------------------------- -def test_deft_swarm_runtime_start_agent_detection() -> None: +def test_deft_directive_swarm_runtime_start_agent_detection() -> None: """Phase 3 must probe for start_agent tool.""" text = _read_skill(_SWARM_PATH) assert "start_agent" in text, ( @@ -358,7 +372,7 @@ def test_deft_swarm_runtime_start_agent_detection() -> None: ) -def test_deft_swarm_warp_env_detection() -> None: +def test_deft_directive_swarm_warp_env_detection() -> None: """Phase 3 must detect Warp via WARP_* environment variables.""" text = _read_skill(_SWARM_PATH) assert "WARP_*" in text or "WARP_TERMINAL_SESSION" in text, ( @@ -366,7 +380,7 @@ def test_deft_swarm_warp_env_detection() -> None: ) -def test_deft_swarm_no_static_abc_antipattern() -> None: +def test_deft_directive_swarm_no_static_abc_antipattern() -> None: """Anti-patterns must prohibit static A/B/C option presentation.""" text = _read_skill(_SWARM_PATH) assert "static launch options" in text.lower() or "static launch options (A/B/C)" in text, ( @@ -374,7 +388,7 @@ def test_deft_swarm_no_static_abc_antipattern() -> None: ) -def test_deft_swarm_cloud_escape_hatch_only() -> None: +def test_deft_directive_swarm_cloud_escape_hatch_only() -> None: """Cloud launch (oz agent run-cloud) must be explicit user request only.""" text = _read_skill(_SWARM_PATH) assert "explicit" in text.lower() and "user" in text.lower() and "run-cloud" in text, ( @@ -383,10 +397,10 @@ def test_deft_swarm_cloud_escape_hatch_only() -> None: # --------------------------------------------------------------------------- -# 15. deft-swarm Phase 6 — Close-out orchestration rules (#206, t2.6.3) +# 15. deft-directive-swarm Phase 6 — Close-out orchestration rules (#206, t2.6.3) # --------------------------------------------------------------------------- -def test_deft_swarm_phase6_merge_authority() -> None: +def test_deft_directive_swarm_phase6_merge_authority() -> None: """Phase 6 must contain merge authority rule.""" text = _read_skill(_SWARM_PATH) assert "Merge authority" in text and "user approves" in text, ( @@ -394,7 +408,7 @@ def test_deft_swarm_phase6_merge_authority() -> None: ) -def test_deft_swarm_phase6_rebase_ownership() -> None: +def test_deft_directive_swarm_phase6_rebase_ownership() -> None: """Phase 6 must assign rebase cascade ownership to monitor.""" text = _read_skill(_SWARM_PATH) assert "Rebase cascade ownership" in text and "Monitor owns" in text, ( @@ -402,7 +416,7 @@ def test_deft_swarm_phase6_rebase_ownership() -> None: ) -def test_deft_swarm_phase6_git_editor() -> None: +def test_deft_directive_swarm_phase6_git_editor() -> None: """Phase 6 must document GIT_EDITOR override for non-interactive rebase.""" text = _read_skill(_SWARM_PATH) assert "GIT_EDITOR" in text, ( @@ -410,7 +424,7 @@ def test_deft_swarm_phase6_git_editor() -> None: ) -def test_deft_swarm_phase6_post_merge_verification() -> None: +def test_deft_directive_swarm_phase6_post_merge_verification() -> None: """Phase 6 must verify issues closed after squash merge.""" text = _read_skill(_SWARM_PATH) assert "verify issues actually closed" in text, ( @@ -418,7 +432,7 @@ def test_deft_swarm_phase6_post_merge_verification() -> None: ) -def test_deft_swarm_push_autonomy() -> None: +def test_deft_directive_swarm_push_autonomy() -> None: """Swarm skill must contain push autonomy carve-out.""" text = _read_skill(_SWARM_PATH) assert "Push Autonomy" in text and "task check" in text.lower(), ( @@ -427,19 +441,19 @@ def test_deft_swarm_push_autonomy() -> None: # --------------------------------------------------------------------------- -# 16. deft-swarm Phase 5→6 gate — release decision checkpoint (#218, t1.10.2) +# 16. deft-directive-swarm Phase 5→6 gate — release decision checkpoint (#218, t1.10.2) # --------------------------------------------------------------------------- -def test_deft_swarm_phase5_6_gate_heading() -> None: - """deft-swarm must contain Phase 5→6 gate section.""" +def test_deft_directive_swarm_phase5_6_gate_heading() -> None: + """deft-directive-swarm must contain Phase 5→6 gate section.""" text = _read_skill(_SWARM_PATH) assert "Phase 5\u21926 Gate" in text, ( f"{_SWARM_PATH}: missing Phase 5\u21926 gate section (#218)" ) -def test_deft_swarm_phase5_6_version_bump_approval() -> None: +def test_deft_directive_swarm_phase5_6_version_bump_approval() -> None: """Phase 5→6 gate must require explicit user approval.""" text = _read_skill(_SWARM_PATH) assert "version bump" in text.lower() and "confirmed" in text, ( @@ -447,7 +461,7 @@ def test_deft_swarm_phase5_6_version_bump_approval() -> None: ) -def test_deft_swarm_greptile_rebase_latency() -> None: +def test_deft_directive_swarm_greptile_rebase_latency() -> None: """Phase 6 must document Greptile re-review latency on force-push rebase.""" text = _read_skill(_SWARM_PATH) assert "Greptile re-review" in text and "2-5" in text, ( @@ -843,11 +857,11 @@ def test_deft_pre_pr_contradiction_antipattern() -> None: # --------------------------------------------------------------------------- -# 28. deft-swarm Phase 5->6 gate hardening + crash recovery (#261, #263, t1.13.1) +# 28. deft-directive-swarm Phase 5->6 gate hardening + crash recovery (#261, #263, t1.13.1) # --------------------------------------------------------------------------- -def test_deft_swarm_phase5_6_context_pressure_callout() -> None: +def test_deft_directive_swarm_phase5_6_context_pressure_callout() -> None: """Phase 5->6 gate must contain explicit context-pressure bypass prohibition.""" text = _read_skill(_SWARM_PATH) assert "context-pressure bypass prohibition" in text.lower(), ( @@ -855,7 +869,7 @@ def test_deft_swarm_phase5_6_context_pressure_callout() -> None: ) -def test_deft_swarm_takeover_prespawn_verification() -> None: +def test_deft_directive_swarm_takeover_prespawn_verification() -> None: """Takeover Triggers must require pre-spawn verification via lifecycle events.""" text = _read_skill(_SWARM_PATH) assert "pre-spawn verification" in text.lower() and "lifecycle event" in text.lower(), ( @@ -863,15 +877,15 @@ def test_deft_swarm_takeover_prespawn_verification() -> None: ) -def test_deft_swarm_duplicate_tab_failure_mode() -> None: - """deft-swarm must document the duplicate-tab failure mode.""" +def test_deft_directive_swarm_duplicate_tab_failure_mode() -> None: + """deft-directive-swarm must document the duplicate-tab failure mode.""" text = _read_skill(_SWARM_PATH) assert "Duplicate-Tab Failure Mode" in text and "tool_use" in text and "tool_result" in text, ( f"{_SWARM_PATH}: missing Duplicate-Tab Failure Mode documentation (#261, t1.13.1)" ) -def test_deft_swarm_context_length_warning() -> None: +def test_deft_directive_swarm_context_length_warning() -> None: """Phase 4 must contain context-length warning about long monitoring sessions.""" text = _read_skill(_SWARM_PATH) assert "Context-Length Warning" in text and "conversation corruption" in text.lower(), ( @@ -879,15 +893,15 @@ def test_deft_swarm_context_length_warning() -> None: ) -def test_deft_swarm_crash_recovery_section() -> None: - """deft-swarm must contain a Crash Recovery section with recovery steps.""" +def test_deft_directive_swarm_crash_recovery_section() -> None: + """deft-directive-swarm must contain a Crash Recovery section with recovery steps.""" text = _read_skill(_SWARM_PATH) assert "## Crash Recovery" in text and "gh pr list" in text and "gh pr view" in text, ( f"{_SWARM_PATH}: missing Crash Recovery section (#263, t1.13.1)" ) -def test_deft_swarm_antipattern_no_spawn_without_lifecycle() -> None: +def test_deft_directive_swarm_antipattern_no_spawn_without_lifecycle() -> None: """Anti-patterns must prohibit spawning replacement without lifecycle confirmation.""" text = _read_skill(_SWARM_PATH) assert "spawn a replacement sub-agent without confirming" in text.lower(), ( @@ -896,7 +910,7 @@ def test_deft_swarm_antipattern_no_spawn_without_lifecycle() -> None: ) -def test_deft_swarm_antipattern_no_skip_phase5_gate() -> None: +def test_deft_directive_swarm_antipattern_no_skip_phase5_gate() -> None: """Anti-patterns must prohibit skipping Phase 5 gate under pressure.""" text = _read_skill(_SWARM_PATH) lower = text.lower() @@ -1105,11 +1119,11 @@ def test_deft_setup_phase2_references_deft_interview() -> None: # --------------------------------------------------------------------------- -# 32. deft-swarm Phase 6 read-back verification (#288, t1.21.1) +# 32. deft-directive-swarm Phase 6 read-back verification (#288, t1.21.1) # --------------------------------------------------------------------------- -def test_deft_swarm_phase6_readback_verification() -> None: +def test_deft_directive_swarm_phase6_readback_verification() -> None: """Phase 6 must require re-reading conflict-resolved files before git add.""" text = _read_skill(_SWARM_PATH) assert "Read-back verification" in text and "conflict markers" in text.lower(), ( @@ -1117,30 +1131,78 @@ def test_deft_swarm_phase6_readback_verification() -> None: ) -def test_deft_swarm_phase6_prefer_edit_files_for_conflicts() -> None: +def test_deft_directive_swarm_phase6_prefer_edit_files_for_conflicts() -> None: """Phase 6 must prefer edit_files over shell regex for conflict resolution.""" text = _read_skill(_SWARM_PATH) - assert "edit_files" in text and "CHANGELOG.md" in text and "SPECIFICATION.md" in text, ( + assert "edit_files" in text and "CHANGELOG.md" in text, ( f"{_SWARM_PATH}: Phase 6 must prefer edit_files for conflict resolution (#288)" ) # --------------------------------------------------------------------------- -# 33. deft-swarm Phase 6 Slack announcement (#292, t1.22.1) +# 33. deft-directive-swarm Phase 6 Slack announcement (#292, t1.22.1) # --------------------------------------------------------------------------- -def test_deft_swarm_phase6_slack_announcement_step() -> None: - """Phase 6 Step 6 must generate a Slack release announcement block.""" +def test_deft_directive_swarm_phase6_slack_announcement_step() -> None: + """Phase 6 Step 5 must generate a Slack release announcement block.""" text = _read_skill(_SWARM_PATH) assert "Slack" in text and "announcement" in text.lower(), ( f"{_SWARM_PATH}: Phase 6 must include Slack announcement step (#292)" ) -def test_deft_swarm_phase6_slack_required_fields() -> None: +def test_deft_directive_swarm_phase6_slack_required_fields() -> None: """Slack announcement must include version, key changes, PR numbers, and release URL.""" text = _read_skill(_SWARM_PATH) assert "Key Changes" in text and "PRs*:" in text and "Release*:" in text, ( f"{_SWARM_PATH}: Slack announcement must include required fields (#292)" ) + + +# --------------------------------------------------------------------------- +# 34. deft-directive-swarm Phase 5 vBRIEF completion lifecycle (#317) +# --------------------------------------------------------------------------- + + +def test_deft_directive_swarm_phase5_vbrief_completion() -> None: + """Phase 5 must move completed vBRIEFs from active/ to completed/.""" + text = _read_skill(_SWARM_PATH) + assert "scope:complete" in text and "vbrief/completed/" in text, ( + f"{_SWARM_PATH}: Phase 5 must move vBRIEFs to completed/ via scope:complete (#317)" + ) + + +def test_deft_directive_swarm_phase6_origin_update() -> None: + """Phase 6 must update origin references on completion (post-merge).""" + text = _read_skill(_SWARM_PATH) + assert "references" in text.lower() and "update each origin" in text.lower(), ( + f"{_SWARM_PATH}: Phase 6 must update origins on completion (#317)" + ) + + +def test_deft_directive_swarm_no_old_name_references() -> None: + """deft-directive-swarm must not reference the old deft-swarm name.""" + text = _read_skill(_SWARM_PATH) + # Check that 'deft-swarm' does not appear without the 'directive-' prefix + import re + old_refs = re.findall(r'(? None: + """SKILL.md frontmatter must have name: deft-directive-swarm.""" + text = _read_skill(_SWARM_PATH) + assert "name: deft-directive-swarm" in text, ( + f"{_SWARM_PATH}: frontmatter must contain 'name: deft-directive-swarm' (#317)" + ) + + +def test_deft_directive_swarm_no_hardcoded_allocation_antipattern() -> None: + """Anti-patterns must prohibit hardcoded 1:1 vBRIEF-per-agent allocation.""" + text = _read_skill(_SWARM_PATH) + assert "hardcode a 1:1" in text.lower() or "hardcoded 1:1" in text.lower(), ( + f"{_SWARM_PATH}: must have anti-pattern against hardcoded 1:1 allocation (#317)" + )