opencode-swarm 7.108.0 → 7.109.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/.opencode/skills/clarify-spec/SKILL.md +15 -9
  2. package/.opencode/skills/critic-gate/SKILL.md +12 -4
  3. package/.opencode/skills/execute/SKILL.md +1 -0
  4. package/.opencode/skills/phase-wrap/SKILL.md +2 -2
  5. package/.opencode/skills/plan/SKILL.md +23 -11
  6. package/.opencode/skills/specify/SKILL.md +27 -9
  7. package/dist/cli/{core-vev13ej2.js → core-mbd2g302.js} +5 -1
  8. package/dist/cli/{curator-drift-fdfgj9qf.js → curator-drift-169wgaxn.js} +1 -1
  9. package/dist/cli/{curator-llm-factory-n70bxf40.js → curator-llm-factory-gtfhwnbr.js} +4 -4
  10. package/dist/cli/{curator-js92gc8a.js → curator-q4febs18.js} +4 -4
  11. package/dist/cli/{evidence-summary-service-bjhr75v0.js → evidence-summary-service-8tasw2tt.js} +2 -2
  12. package/dist/cli/{guardrail-explain-sn2a4pb7.js → guardrail-explain-r2d8ftkv.js} +5 -5
  13. package/dist/cli/{hive-promoter-3hh8ph4a.js → hive-promoter-mfd5p9f5.js} +4 -4
  14. package/dist/cli/{index-x06d2qqm.js → index-1capawwy.js} +5 -5
  15. package/dist/cli/{index-f1qyj61w.js → index-3yk9196e.js} +40 -3
  16. package/dist/cli/{index-48mc4d48.js → index-j2v3w1ds.js} +8 -2
  17. package/dist/cli/{index-1emhz3zb.js → index-nq9h2t3x.js} +137 -70
  18. package/dist/cli/{index-91j1sqzm.js → index-scww5b77.js} +47 -0
  19. package/dist/cli/{index-7jyndvsy.js → index-wsg3vkss.js} +1 -1
  20. package/dist/cli/index.js +4 -4
  21. package/dist/commands/registry.d.ts +2 -2
  22. package/dist/commands/sdd.d.ts +10 -0
  23. package/dist/config/index.d.ts +1 -0
  24. package/dist/config/worktree-isolation-config.d.ts +10 -0
  25. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +4 -2
  26. package/dist/hooks/delegation-gate.d.ts +1 -0
  27. package/dist/hooks/guardrails/index.d.ts +1 -1
  28. package/dist/hooks/guardrails/tool-before.d.ts +5 -0
  29. package/dist/index.js +130 -121
  30. package/dist/plan/ledger.d.ts +60 -0
  31. package/dist/sdd/effective-spec.d.ts +21 -0
  32. package/dist/tools/save-plan.d.ts +24 -0
  33. package/dist/worktree/core.d.ts +58 -7
  34. package/dist/worktree/index.d.ts +1 -1
  35. package/package.json +1 -1
@@ -9,11 +9,13 @@ description: >
9
9
  This protocol is loaded on demand by the architect stub in src/agents/architect.ts. The architect prompt keeps only activation, action, and hard safety constraints; the full execution details live here.
10
10
 
11
11
  ### MODE: CLARIFY-SPEC
12
- Activates when: `.swarm/spec.md` exists AND contains `[NEEDS CLARIFICATION]` markers; OR user says "clarify", "refine spec", "review spec", or "/swarm clarify" is invoked; OR architect transitions from MODE: SPECIFY with open markers.
12
+ Activates when: `/swarm sdd status` reports a **single resolved EFFECTIVE spec** (non-null) AND it contains `[NEEDS CLARIFICATION]` markers; OR user says "clarify", "refine spec", "review spec", or "/swarm clarify" is invoked; OR architect transitions from MODE: SPECIFY with open markers.
13
13
 
14
- CONSTRAINT: CLARIFY-SPEC must NEVER create a spec. If `.swarm/spec.md` does not exist, tell the user: "No spec found. Use `/swarm specify` to generate one first." and stop.
14
+ `/swarm sdd status` reflects `readEffectiveSpecSync`, which returns **null** (NO effective spec) for: no sources at all, multiple competing sources (e.g. `openspec/` AND `.specify/`), multi-feature Spec-Kit without a selected feature, or any other unresolvable state. CLARIFY-SPEC does NOT activate in these null cases — tell the user: "No resolved effective spec exists. Disambiguate with `/swarm sdd project --source <source>` or `--feature <feature>`, or run `/swarm specify` to generate one first." and stop.
15
15
 
16
- 1. Read `.swarm/spec.md` (read current spec FIRST before making any changes).
16
+ CONSTRAINT: CLARIFY-SPEC must NEVER create a spec. Always consult `/swarm sdd status` to determine the effective spec source before proceeding.
17
+
18
+ 1. Read the **effective spec** resolved by `/swarm sdd status` (native `.swarm/spec.md` OR OpenSpec `openspec/` OR Spec-Kit `.specify/` — read the resolved spec FIRST before making any changes).
17
19
  2. Scan for ambiguities beyond explicit `[NEEDS CLARIFICATION]` markers:
18
20
  - Vague adjectives ("fast", "secure", "user-friendly") without measurable targets
19
21
  - Requirements that overlap or potentially conflict with each other
@@ -28,10 +30,14 @@ CONSTRAINT: CLARIFY-SPEC must NEVER create a spec. If `.swarm/spec.md` does not
28
30
  - Offer 2–4 multiple-choice options for each question
29
31
  - Mark the recommended option with reasoning (e.g., "Recommended: Option 2 because…")
30
32
  - Allow free-form input as an alternative to the options
31
- 5. After each accepted answer:
32
- - Immediately update `.swarm/spec.md` with the resolution
33
- - Replace the relevant `[NEEDS CLARIFICATION]` marker or vague language with the accepted answer
34
- - If the answer invalidates an earlier requirement, update it to remove the contradiction
33
+ 5. After each accepted answer, write the resolution to the **resolved effective source** (source-aware write-back):
34
+ - **NATIVE effective spec** (`.swarm/spec.md` exists): update `.swarm/spec.md` with the resolution directly.
35
+ - **NON-NATIVE effective spec** (openspec/specify-only, NO native `.swarm/spec.md`): do NOT write `.swarm/spec.md` this would silently shadow the non-native source. Instead:
36
+ - (a) If the resolved source supports in-place edits (e.g., OpenSpec sections), update the source artifacts directly.
37
+ - (b) If no in-place edit path exists, ask the user: "The effective spec lives in `<source>`. To persist this resolution as a native spec, run `/swarm sdd project` first to materialize one, or I can stop here. Proceed?" — if the user consents to project, materialize via `/swarm sdd project` then write `.swarm/spec.md`; otherwise stop.
38
+ - (c) If neither (a) nor (b) applies, stop and tell the user the clarification cannot be auto-written to a non-native source without a projection step.
39
+ - Replace the relevant `[NEEDS CLARIFICATION]` marker or vague language with the accepted answer.
40
+ - If the answer invalidates an earlier requirement, update it to remove the contradiction.
35
41
  6. Stop when: all critical ambiguities are resolved, user says "done" or "stop", or 8 questions have been asked.
36
42
  7. Report a ## Clarification Summary: total questions asked, requirements added/modified/removed, remaining open ambiguities (if any), and suggest next step (`PLAN` if spec is clear, or continue clarifying).
37
43
 
@@ -39,9 +45,9 @@ CLARIFY-SPEC RULES:
39
45
  - FR-ID increment rule: When adding new requirements, find the highest existing FR-ID and increment from there (FR-001 → FR-002). Never reuse or skip FR-IDs.
40
46
  - One question at a time — never ask multiple questions in the same message.
41
47
  - Do not modify any part of the spec that was not affected by the accepted answer.
42
- - Always write the accepted answer back to spec.md before presenting the next question.
48
+ - Always write the accepted answer back to the resolved effective source before presenting the next question. Never write `.swarm/spec.md` in a non-native (openspec/specify-only) repo — see step 5 source-aware write-back rule.
43
49
  - Max 8 questions per session — if limit reached, report remaining ambiguities and stop.
44
- - Do not create or overwrite the spec file — only refine what exists.
50
+ - Do not create, overwrite, or shadow the spec file — only refine what exists. In non-native (openspec/specify-only) repos, never silently materialize a `.swarm/spec.md` that would shadow the effective source.
45
51
 
46
52
  ### Scoped Funnel Protocol (CLARIFY-SPEC only)
47
53
 
@@ -11,6 +11,7 @@ This protocol is loaded on demand by the architect stub in src/agents/architect.
11
11
  ### MODE: CRITIC-GATE
12
12
  Delegate plan to the active swarm's critic agent for review BEFORE any implementation begins.
13
13
  - Send the full plan.md content and codebase context summary
14
+ - Explicitly reference "plan.md" or "critic-gate" in the dispatch prompt text. This lets the mechanical approval-recording gate reliably detect the review and record the critic's APPROVED verdict, which the EXECUTE-phase coder gate then requires.
14
15
  - **APPROVED** → Proceed to MODE: EXECUTE
15
16
  - **NEEDS_REVISION** → Revise the plan based on critic feedback, then resubmit (max 2 cycles)
16
17
  - **REJECTED** → Inform the user of fundamental issues and ask for guidance before proceeding
@@ -26,11 +27,12 @@ You MUST NOT proceed to MODE: EXECUTE without printing this checklist with fille
26
27
  CRITIC-GATE TRIGGER: Run ONCE when you first write the complete .swarm/plan.md.
27
28
  Do NOT re-run CRITIC-GATE before every project phase.
28
29
  If resuming a project with an existing approved plan, CRITIC-GATE is already satisfied.
30
+ Caveat: this assumption breaks if the plan lacks a `plan_critic_gate`-tagged approval snapshot (e.g. a plan approved before this mechanical gate existed, or one where the recording heuristic didn't fire) — in that case the first coder dispatch will fail with `PLAN_CRITIC_GATE_VIOLATION`. If that happens, do not assume CRITIC-GATE is satisfied; re-run it and get a fresh APPROVED verdict.
29
31
 
30
32
  6j. SPEC-GATE (Execute BEFORE any save_plan call):
31
- - The save_plan tool will REJECT if .swarm/spec.md does not exist (enforced at the tool level via SWARM_SKIP_SPEC_GATE env var bypass).
32
- - Before calling save_plan, verify spec.md is present using lint_spec.
33
- - If spec.md is absent: do NOT call save_plan. Use /swarm specify to create a spec first, or inform the user.
33
+ - An effective spec exists iff `/swarm sdd status` reports a resolved spec (it reflects `readEffectiveSpecSync`, which returns null — NO effective spec — for no sources, multiple competing sources (openspec+specify), multi-feature Spec-Kit without a selected feature, or any unresolvable state). `save_plan` rejects (SPEC_REQUIRED) when `/swarm sdd status` reports no resolved spec. The gate is overridable via `SWARM_SKIP_SPEC_GATE=1`.
34
+ - Before calling save_plan, verify an effective spec exists (via `/swarm sdd status` or `lint_spec`).
35
+ - If no effective spec exists: do NOT call save_plan. Generate one first native via `/swarm specify`, or via the agent-invocable `/swarm sdd project` (from SDD sources, after consent).
34
36
  - This rule is satisfied by the save_plan tool's own spec gate — it exists as a reminder that planning requires a spec.
35
37
 
36
38
  6k. SPEC-STALENESS GUARD:
@@ -60,7 +62,13 @@ If resuming a project with an existing approved plan, CRITIC-GATE is already sat
60
62
 
61
63
  6l. OBLIGATION TRACEABILITY CHECK (FR-003):
62
64
  - Before the critic's substantive rubric, the critic MUST cross-reference every
63
- MUST/SHALL SC-### obligation in .swarm/spec.md against the plan tasks.
65
+ MUST/SHALL SC-### obligation in the EFFECTIVE spec against the plan tasks.
66
+ An effective spec exists iff `/swarm sdd status` reports a resolved spec (it
67
+ reflects `readEffectiveSpecSync`, which returns null — NO effective spec — for
68
+ no sources, multiple competing sources (openspec+specify), multi-feature
69
+ Spec-Kit without a selected feature, or any unresolvable state). Obligations
70
+ are traced only against the resolved effective spec; in a null/unresolved
71
+ state there is nothing to trace (this check is not applicable).
64
72
  - If ANY MUST/SHALL SC-### has zero corresponding plan tasks, the critic MUST
65
73
  return VERDICT: REJECTED enumerating each unmapped obligation.
66
74
  - The critic MUST evaluate coverage against the FULL plan — each task's
@@ -55,6 +55,7 @@ All other gates: failure → return to coder. No self-fixes. No workarounds.
55
55
  → Subsequent `pre_check_batch` calls with `phase: <N>` will automatically diff against this baseline — only NEW findings (not in baseline) drive the fail verdict.
56
56
  -> PREFLIGHT CHECKLIST: Before first coder delegation, answer "SAST baseline captured before first coder delegation? yes/no/disabled/error". If the answer is no, do not delegate to coder; run 5b-BASE first. If disabled or error, record the exact tool result.
57
57
  5b. the active swarm's coder agent - Implement (if designer scaffold produced, include it as INPUT).
58
+ → If this dispatch fails with `PLAN_CRITIC_GATE_VIOLATION`: the plan has no current critic-approved snapshot (commonly a plan approved before this mechanical gate existed). Do NOT retry the coder dispatch as-is — re-run MODE: CRITIC-GATE to get a fresh critic `APPROVED` verdict, then retry this step.
58
59
  5b-bis. **CODER OUTPUT VERIFICATION**: After the coder reports completion, do NOT accept the self-report alone. Run `diff` (step 5c) and inspect at least one of the modified files yourself to confirm the change exists. The coder may report DONE without having produced any diff. A 30-second read of the changed file(s) catches this failure mode. This is NOT a separate explorer dispatch — the existing `diff` tool at step 5c is the verification mechanism; the key discipline is checking that `diff` returns actual changes before proceeding, rather than forwarding the coder's self-report to the next gate.
59
60
  5c. Run `diff` tool. If `hasContractChanges` → the active swarm's explorer agent integration analysis. If COMPATIBILITY SIGNALS=INCOMPATIBLE or MIGRATION_SURFACE=yes → coder retry. If COMPATIBILITY SIGNALS=COMPATIBLE and MIGRATION_SURFACE=no → proceed.
60
61
  → REQUIRED: Print "diff: [PASS | CONTRACT CHANGE — details]"
@@ -62,7 +62,7 @@ The tool will automatically write the retrospective to \`.swarm/evidence/retro-{
62
62
  4. Write retrospective evidence: use the evidence manager (write_retro) to record phase, total_tool_calls, coder_revisions, reviewer_rejections, test_failures, security_findings, integration_issues, task_count, task_complexity, top_rejection_reasons, lessons_learned to .swarm/evidence/. Reset Phase Metrics in context.md to 0.
63
63
  4.5. Run `evidence_check` to verify all completed tasks have required evidence (review + test). If gaps found, note in retrospective lessons_learned. Optionally run `pkg_audit` if dependencies were modified during this phase. Optionally run `schema_drift` if API routes were modified during this phase.
64
64
  5. Run `sbom_generate` with scope='changed' to capture post-implementation dependency snapshot (saved to `.swarm/evidence/sbom/`). This is a non-blocking step - always proceeds to summary.
65
- 5.5. **Drift verification**: Conditional on .swarm/spec.md existence if spec.md does not exist, skip silently and proceed to step 5.55. If spec.md exists, delegate to the active swarm's critic_drift_verifier agent with DRIFT-CHECK context:
65
+ 5.5. **Drift verification**: Conditional on an EFFECTIVE spec existing (determined via `/swarm sdd status` or `readEffectiveSpecSync` — native `.swarm/spec.md`, OpenSpec `openspec/`, or Spec-Kit `.specify/`). If NO effective spec exists at all, skip silently. If an effective spec exists (even openspec-only or specify-only), delegate to the active swarm's critic_drift_verifier agent with DRIFT-CHECK context:
66
66
  - Provide: phase number being completed, completed task IDs and their descriptions
67
67
  - Include evidence path (.swarm/evidence/) for the critic to read implementation artifacts
68
68
  The critic reads every target file, verifies described changes exist against the spec, and returns per-task verdicts: ALIGNED, MINOR_DRIFT, MAJOR_DRIFT, or OFF_SPEC.
@@ -92,7 +92,7 @@ The tool will automatically write the retrospective to \`.swarm/evidence/retro-{
92
92
  5.58. **Design-doc sync (conditional on `design_docs.enabled` — issue #1080)**: If `design_docs.enabled` is not true, skip silently. Otherwise: `phase_complete` runs a deterministic, non-blocking design-doc drift check and writes `.swarm/doc-drift-phase-{phase}.json`. If its verdict is `DOC_STALE`, enter MODE: DESIGN_DOCS in sync mode for the stale sections only — delegate to the active swarm's `docs_design` agent (NOT the standard `docs` agent) with the changed files + the stale section IDs, and have it update the affected docs and append a `design-changelog.md` entry. This is advisory and NON-BLOCKING — never hold up phase_complete on design-doc lag, and never write `.swarm/spec.md`, `CHANGELOG.md`, or `docs/releases/pending/*` here.
93
93
  5.6. **Mandatory gate evidence**: Before calling phase_complete, ensure:
94
94
  - `.swarm/evidence/{phase}/completion-verify.json` exists (written automatically by the completion-verify gate)
95
- - `.swarm/evidence/{phase}/drift-verifier.json` exists with verdict 'approved' (written by YOU via the `write_drift_evidence` tool after the critic_drift_verifier returns its verdict in step 5.5) — required when .swarm/spec.md exists
95
+ - `.swarm/evidence/{phase}/drift-verifier.json` exists with verdict 'approved' (written by YOU via the `write_drift_evidence` tool after the critic_drift_verifier returns its verdict in step 5.5) — required when an effective spec exists
96
96
  - `.swarm/evidence/{phase}/hallucination-guard.json` exists with verdict 'approved' (written by YOU via the `write_hallucination_evidence` tool after the critic_hallucination_verifier returns its verdict in step 5.55) — ONLY required when `hallucination_guard` is enabled in the QA gate profile
97
97
  - `.swarm/evidence/{phase}/mutation-gate.json` exists with verdict 'pass' or 'warn' (written by YOU via the `write_mutation_evidence` tool after step 5.56) — ONLY required when `mutation_test` is enabled in the QA gate profile
98
98
  - regression-test falsification evidence exists for at least one regression
@@ -11,22 +11,25 @@ This protocol is loaded on demand by the architect stub in src/agents/architect.
11
11
  ### MODE: PLAN
12
12
 
13
13
  SPEC GATE (soft — check before planning):
14
- - If `.swarm/spec.md` does NOT exist:
14
+
15
+ An effective spec exists iff `/swarm sdd status` reports a resolved spec (it reflects `readEffectiveSpecSync`, which returns null for no sources, multiple competing sources, multi-feature Spec-Kit without a selected feature, or any unresolvable state). Do NOT enumerate these cases — defer to `/swarm sdd status`.
16
+
17
+ - If NO effective spec exists (confirmed via `/swarm sdd status`):
15
18
  - PLAN INGESTION DETECTION: Check if the user is providing an external plan (indicators: markdown content with Phase/Task structure, or phrases like "ingest this plan", "implement this plan", "prepare for implementation", "here is a plan", "here's the plan"):
16
- - If plan ingestion is detected AND no spec.md exists: offer this choice FIRST before any planning:
19
+ - If plan ingestion is detected AND no effective spec exists: offer this choice FIRST before any planning:
17
20
  1. "Generate spec from this plan first" → enter EXTERNAL PLAN IMPORT PATH in MODE: SPECIFY to reverse-engineer a spec.md from the provided plan, then return to planning
18
21
  2. "Skip spec and proceed with the provided plan" → proceed directly to plan ingestion and planning without creating a spec
19
22
  - This is a SOFT gate — option 2 always lets the user proceed without a spec
20
- - If no plan ingestion detected: Warn: "No spec found. A spec helps ensure the plan covers all requirements and gives the critic something to verify against. Would you like to create one first?"
23
+ - If no plan ingestion detected: Warn: "No effective spec found. A spec helps ensure the plan covers all requirements and gives the critic something to verify against. Would you like to create one first?"
21
24
  - Offer two options:
22
25
  1. "Create a spec first" → transition to MODE: SPECIFY
23
26
  2. "Skip and plan directly" → continue with the steps below unchanged
24
- - If `.swarm/spec.md` EXISTS:
27
+ - If an effective spec EXISTS:
25
28
  - NOTE: Stale detection is intentionally heuristic (compare headings) — false positives are acceptable because this is a SOFT gate. When in doubt, ask the user.
26
- - Read the spec and compare its first heading (or feature description) against the current planning context (the user's request and any existing plan.md title/phase names)
29
+ - Read the spec (using the effective spec path reported by `/swarm sdd status`) and compare its first heading (or feature description) against the current planning context (the user's request and any existing plan.md title/phase names)
27
30
  - STALE SPEC DETECTION: If the spec heading or feature description does NOT match the current work being planned (e.g., spec describes "user authentication" but user is asking to plan "payment integration"), treat the spec as potentially stale and offer three options:
28
31
  1. **Archive and create new spec** → attempt to rename .swarm/spec.md to .swarm/spec-archive/spec-{YYYY-MM-DD}.md (create the directory if needed); if archival succeeds: enter MODE: SPECIFY and skip the "spec already exists" prompt; if archival fails: inform user of the failure and offer: retry archival, or proceed with option 2, or proceed with option 3
29
- 2. **Keep existing spec** → use spec.md as-is and proceed with planning below
32
+ 2. **Keep existing spec** → use the effective spec as-is and proceed with planning below
30
33
  3. **Skip spec entirely** → proceed to planning below ignoring the existing spec
31
34
  - If the spec appears current (heading matches the work being planned) OR user chose option 2 above, proceed with spec:
32
35
  - Read it and use it as the primary input for planning
@@ -37,7 +40,16 @@ SPEC GATE (soft — check before planning):
37
40
 
38
41
  This is a SOFT gate. When the user chooses "Skip and plan directly", proceed to the steps below exactly as before — do NOT modify any planning behavior.
39
42
 
40
- Run CODEBASE REALITY CHECK scoped to codebase elements referenced in spec.md or user constraints. Discrepancies must be reflected in the generated plan.
43
+ **SAVE_PLAN SPEC_REQUIRED RECOVERY:**
44
+ When `save_plan` returns a SPEC_REQUIRED rejection (no effective spec found), the architect MUST:
45
+ 1. DIAGNOSE: run `/swarm sdd status` to determine why no effective spec resolved.
46
+ - (a) If `/swarm sdd status` shows NO sources → transition to MODE: SPECIFY.
47
+ - (b) If `/swarm sdd status` shows multiple competing sources (e.g., openspec AND specify with no native) → ask the user which provider to use (`openspec` or `speckit`), then run `/swarm sdd project --source <user_choice>` (obtain explicit consent first; add `--overwrite` only if a native `.swarm/spec.md` already exists). Then re-attempt `save_plan`.
48
+ - (c) If `/swarm sdd status` shows Spec-Kit with multiple features → ask the user which feature, then run `/swarm sdd project --source speckit --feature <id>` (obtain explicit consent first; add `--overwrite` only if a native `.swarm/spec.md` already exists). Then re-attempt `save_plan`.
49
+ 2. If `/swarm sdd status` shows a single resolvable source but it was not yet materialized: run `/swarm sdd project` (obtain explicit consent first; add `--overwrite` only if a native `.swarm/spec.md` already exists). Then re-attempt `save_plan`.
50
+ 3. If the user does NOT consent to materializing an effective spec: surface the blockage and stop — do not silently skip or retry without a spec.
51
+
52
+ Run CODEBASE REALITY CHECK scoped to codebase elements referenced in the effective spec or user constraints. Discrepancies must be reflected in the generated plan.
41
53
 
42
54
  ### GENERAL COUNCIL ADVISORY OPTION (pre-save_plan)
43
55
 
@@ -305,17 +317,17 @@ PHASE COUNT GUIDANCE:
305
317
 
306
318
  Also create .swarm/context.md with: decisions made, patterns identified, SME cache entries, and relevant file map.
307
319
 
308
- TRACEABILITY CHECK (run after plan is written, when spec.md exists):
320
+ TRACEABILITY CHECK (run after plan is written, when an effective spec exists):
309
321
 
310
322
  OBLIGATION TRACEABILITY — STRUCTURAL COMPLETENESS PRECONDITION
311
323
  The obligation-traceability mapping is a STRUCTURAL COMPLETENESS precondition. It MUST be evaluated BEFORE the critic begins its substantive 5-axis/7-dimension rubric. An unmapped MUST/SHALL obligation makes the plan structurally incomplete — it is not an afterthought.
312
324
 
313
325
  1. FR-### MAPPING (existing requirement):
314
- - Every FR-### in spec.md MUST map to at least one task → unmapped FRs = coverage gap, flag to user
326
+ - Every FR-### in the effective spec (resolved via `/swarm sdd status`) MUST map to at least one task → unmapped FRs = coverage gap, flag to user
315
327
  - Every task MUST reference its source FR-### in the description or acceptance field → tasks with no FR = potential gold-plating, flag to critic
316
328
 
317
329
  2. SC-### MAPPING (MUST/SHALL obligations):
318
- - Parse spec.md for every SC-### line whose obligation text contains MUST or SHALL/SHALL NOT
330
+ - Parse the effective spec (resolved via `/swarm sdd status`) for every SC-### line whose obligation text contains MUST or SHALL/SHALL NOT
319
331
  - Each such MUST/SHALL SC-### MUST be referenced by ≥1 task's description or acceptance field
320
332
  - Unmapped MUST/SHALL SC-### are structural coverage gaps that must be resolved — surface them prominently, not buried
321
333
  - A plan where every MUST/SHALL SC-### is referenced by ≥1 task passes this check and is not blocked by it
@@ -324,7 +336,7 @@ The obligation-traceability mapping is a STRUCTURAL COMPLETENESS precondition. I
324
336
  REPORT FORMAT:
325
337
  "TRACEABILITY: <N> FRs mapped, <M> unmapped FRs (gap), <K> tasks with no FR mapping (gold-plating risk), <P> MUST/SHALL SCs mapped, <Q> unmapped MUST/SHALL SCs (structural gap)"
326
338
 
327
- - If no spec.md: skip this check silently.
339
+ - If no effective spec: skip this check silently.
328
340
 
329
341
  ### Transition to CRITIC-GATE
330
342
 
@@ -9,15 +9,33 @@ description: >
9
9
  This protocol is loaded on demand by the architect stub in src/agents/architect.ts. The architect prompt keeps only activation, action, and hard safety constraints; the full execution details live here.
10
10
 
11
11
  ### MODE: SPECIFY
12
- Activates when: user asks to "specify", "define requirements", "write a spec", or "define a feature"; OR `/swarm specify` is invoked; OR no `.swarm/spec.md` exists and no `.swarm/plan.md` exists.
13
-
14
- 1. Check if `.swarm/spec.md` already exists.
15
- - If YES (and this is not a call from the stale spec archival path in MODE: PLAN): ask the user "A spec already exists. Do you want to overwrite it or refine it?"
16
- - Overwrite → ARCHIVE FIRST: read the existing spec, extract version (priority order): (1) from spec heading, look for patterns like "v{semver}" or "Version {semver}" in the first H1/H2; (2) from package.json version field in project root; create `.swarm/spec-archive/` directory if it does not exist; copy existing spec.md to `.swarm/spec-archive/spec-v{version}.md`; if version cannot be determined, use date-based fallback: `.swarm/spec-archive/spec-{YYYY-MM-DD}.md`; log the archive location to the user ("Archived existing spec to .swarm/spec-archive/spec-v{version}.md"); then proceed to generation (step 2)
17
- - Refine delegate to MODE: CLARIFY-SPEC
18
- - If NO: proceed to generation (step 2)
19
- - If this is called from the stale spec archival path (MODE: PLAN option 1) — archival was already completed; skip this check and proceed directly to generation (step 2)
20
- 1b. Run CODEBASE REALITY CHECK for any codebase references mentioned by the user or implied by the feature. Skip if work is purely greenfield (no existing codebase to check). Report discrepancies before proceeding to explorer.
12
+ Activates when: user asks to "specify", "define requirements", "write a spec", or "define a feature"; OR `/swarm specify` is invoked; OR no EFFECTIVE spec exists and no `.swarm/plan.md` exists (use `/swarm sdd status` to determine effective-spec existence — native `.swarm/spec.md`, OpenSpec `openspec/`, or Spec-Kit `.specify/`).
13
+
14
+ 1. Run `/swarm sdd status` to determine whether an effective spec exists and, if so, how it should be handled. An effective spec exists iff `/swarm sdd status` reports a resolved spec. `/swarm sdd status` reflects `readEffectiveSpecSync`, which returns null (NO effective spec) for: no sources, multiple competing sources (openspec+speckit), multi-feature Spec-Kit without a selected feature, or any unresolvable state. When `/swarm sdd status` reports a resolved spec, classify it as NATIVE (native `.swarm/spec.md`) vs NON-NATIVE (projected). When it reports NO resolved spec, do NOT treat any source as an effective spec. Based on this classification, branch to the appropriate sub-step:
15
+ - **NATIVE**: proceed to step 1a (overwrite/refine/archive).
16
+ - **NON-NATIVE**: proceed to step 1b (non-shadowing choice).
17
+ - **NO effective spec** (ambiguous or no sources): if multiple SDD sources are present, proceed to step 1c (disambiguation); otherwise proceed to step 1d (native authoring).
18
+ - If this is called from the stale spec archival path (MODE: PLAN option 1) — archival was already completed; skip all branches and proceed directly to generation (step 2).
19
+ 1a. **NATIVE SPEC overwrite/refine/archive.** Ask the user "A spec already exists. Do you want to overwrite it or refine it?"
20
+ - Overwrite ARCHIVE FIRST: read the existing spec, extract version (priority order): (1) from spec heading, look for patterns like "v{semver}" or "Version {semver}" in the first H1/H2; (2) from package.json version field in project root; create `.swarm/spec-archive/` directory if it does not exist; copy existing spec.md to `.swarm/spec-archive/spec-v{version}.md`; if version cannot be determined, use date-based fallback: `.swarm/spec-archive/spec-{YYYY-MM-DD}.md`; log the archive location to the user ("Archived existing spec to .swarm/spec-archive/spec-v{version}.md"); then proceed to generation (step 2)
21
+ - Refine → delegate to MODE: CLARIFY-SPEC
22
+ 1b. **NON-NATIVE SPEC — non-shadowing check (FR-002).** The effective spec comes from `openspec/` or `.specify/` sources with no native `.swarm/spec.md`. Do NOT silently author a competing native spec. Instead OFFER the user a choice:
23
+ - **(a) Project/ingest** the existing SDD sources into `.swarm/spec.md` via the agent-invocable `/swarm sdd project` command. Obtain EXPLICIT user consent before proceeding. (Do not pass `--overwrite` in this branch — no native spec exists yet.)
24
+ - **(b) Proceed with native authoring** (`/swarm specify`) if the user explicitly chooses to ignore the SDD sources and write a new spec from scratch.
25
+ - **(c) Cancel** — abort SPECIFY; the existing SDD sources remain the effective spec.
26
+ - If the user chooses option (a) and `/swarm sdd project` completes successfully: the projected spec is now materialized as `.swarm/spec.md` (NATIVE). Do NOT proceed to generation (step 2) — that would overwrite the just-projected spec. Instead route to step 1a (overwrite/refine/archive) so the user can refine, overwrite, or archive the projected spec.
27
+ - If the user chooses option (b): proceed directly to generation (step 2) with a note that existing SDD sources were bypassed per user decision.
28
+ - If the user chooses option (a) and `/swarm sdd project` fails: report the failure and re-offer the choices.
29
+ 1c. **AMBIGUOUS — multiple SDD sources detected.** Both `openspec/` AND `.specify/` exist with no native `.swarm/spec.md`. Per `readEffectiveSpecSync` semantics this is NOT an effective spec (the function returns null). Do NOT treat this as a single-source NON-NATIVE choice. Instead:
30
+ - Inform the user: "Multiple SDD sources detected (openspec AND speckit) but no native spec exists. This is ambiguous — there is no single effective spec. You must choose which source to project, or disambiguate via `/swarm sdd status --source`."
31
+ - Offer the user a choice:
32
+ - **(a) Project from openspec** — run `/swarm sdd project --source openspec` (after consent) to project the openspec source into `.swarm/spec.md`.
33
+ - **(b) Project from speckit** — run `/swarm sdd project --source speckit` (after consent) to project the speckit source into `.swarm/spec.md`.
34
+ - **(c) Cancel** — abort SPECIFY; the ambiguous sources remain as-is.
35
+ - After a successful projection (a or b): the spec is now NATIVE → route to step 1a (overwrite/refine/archive).
36
+ - After a failed projection: report the failure and re-offer the choices.
37
+ 1d. **NO EFFECTIVE SPEC.** Proceed directly to generation (step 2).
38
+ 1e. Run CODEBASE REALITY CHECK for any codebase references mentioned by the user or implied by the feature. Skip if work is purely greenfield (no existing codebase to check). Report discrepancies before proceeding to explorer.
21
39
  2. Delegate to `the active swarm's explorer agent` to scan the codebase for relevant context (existing patterns, related code, affected areas).
22
40
  3. Delegate to `the active swarm's sme agent` for domain research on the feature area to surface known constraints, best practices, and integration concerns.
23
41
  4. Generate `.swarm/spec.md` capturing:
@@ -6,13 +6,15 @@ import {
6
6
  checkPathBudget,
7
7
  cleanUntrackedFiles,
8
8
  isCleanWorktree,
9
+ isPathUnderSwarmWorktreeBase,
9
10
  makeWorktreeBranchName,
10
11
  provisionWorktree,
11
12
  removeLaneProfileFromDiskReal,
12
13
  removeWorktree,
14
+ resolveWorktreeBaseDir,
13
15
  shortenWorktreePath,
14
16
  writeLaneProfileToDiskReal
15
- } from "./index-f1qyj61w.js";
17
+ } from "./index-3yk9196e.js";
16
18
  import"./index-5e4e2hvv.js";
17
19
  import"./index-p0arc26j.js";
18
20
  import"./index-zgwm4ryv.js";
@@ -21,10 +23,12 @@ import"./index-a76rekgs.js";
21
23
  export {
22
24
  writeLaneProfileToDiskReal,
23
25
  shortenWorktreePath,
26
+ resolveWorktreeBaseDir,
24
27
  removeWorktree,
25
28
  removeLaneProfileFromDiskReal,
26
29
  provisionWorktree,
27
30
  makeWorktreeBranchName,
31
+ isPathUnderSwarmWorktreeBase,
28
32
  isCleanWorktree,
29
33
  cleanUntrackedFiles,
30
34
  checkPathBudget,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./index-c8s9a3zh.js";
5
5
  import {
6
6
  readEffectiveSpecSync
7
- } from "./index-91j1sqzm.js";
7
+ } from "./index-scww5b77.js";
8
8
  import {
9
9
  readSwarmFileAsync,
10
10
  validateSwarmPath
@@ -1,13 +1,13 @@
1
1
  // @bun
2
2
  import {
3
3
  createCuratorLLMDelegate
4
- } from "./index-1emhz3zb.js";
4
+ } from "./index-nq9h2t3x.js";
5
5
  import"./index-wj4jeavn.js";
6
6
  import"./index-5gnp8fyw.js";
7
7
  import"./index-c8s9a3zh.js";
8
8
  import"./index-fm7xz1ne.js";
9
- import"./index-48mc4d48.js";
10
- import"./index-91j1sqzm.js";
9
+ import"./index-j2v3w1ds.js";
10
+ import"./index-scww5b77.js";
11
11
  import"./index-yw8qpf51.js";
12
12
  import"./index-85bacexr.js";
13
13
  import"./index-09xpycan.js";
@@ -21,7 +21,7 @@ import"./index-bfwt3abw.js";
21
21
  import"./index-wvrj16f0.js";
22
22
  import"./index-q1exe2b3.js";
23
23
  import"./index-x2q0gnt8.js";
24
- import"./index-f1qyj61w.js";
24
+ import"./index-3yk9196e.js";
25
25
  import"./index-r3j3458j.js";
26
26
  import"./index-jtqkh8jf.js";
27
27
  import"./index-5e4e2hvv.js";
@@ -11,13 +11,13 @@ import {
11
11
  runCuratorInit,
12
12
  runCuratorPhase,
13
13
  writeCuratorSummary
14
- } from "./index-1emhz3zb.js";
14
+ } from "./index-nq9h2t3x.js";
15
15
  import"./index-wj4jeavn.js";
16
16
  import"./index-5gnp8fyw.js";
17
17
  import"./index-c8s9a3zh.js";
18
18
  import"./index-fm7xz1ne.js";
19
- import"./index-48mc4d48.js";
20
- import"./index-91j1sqzm.js";
19
+ import"./index-j2v3w1ds.js";
20
+ import"./index-scww5b77.js";
21
21
  import"./index-yw8qpf51.js";
22
22
  import"./index-85bacexr.js";
23
23
  import"./index-09xpycan.js";
@@ -31,7 +31,7 @@ import"./index-bfwt3abw.js";
31
31
  import"./index-wvrj16f0.js";
32
32
  import"./index-q1exe2b3.js";
33
33
  import"./index-x2q0gnt8.js";
34
- import"./index-f1qyj61w.js";
34
+ import"./index-3yk9196e.js";
35
35
  import"./index-r3j3458j.js";
36
36
  import"./index-jtqkh8jf.js";
37
37
  import"./index-5e4e2hvv.js";
@@ -6,8 +6,8 @@ import {
6
6
  loadPlanJsonOnly,
7
7
  mergeDurableGateEntriesFromEvidence,
8
8
  readDurableGateEvidence
9
- } from "./index-48mc4d48.js";
10
- import"./index-91j1sqzm.js";
9
+ } from "./index-j2v3w1ds.js";
10
+ import"./index-scww5b77.js";
11
11
  import"./index-q1exe2b3.js";
12
12
  import"./index-r3j3458j.js";
13
13
  import"./index-jtqkh8jf.js";
@@ -1,14 +1,14 @@
1
1
  // @bun
2
2
  import {
3
3
  handleGuardrailExplain
4
- } from "./index-7jyndvsy.js";
5
- import"./index-1emhz3zb.js";
4
+ } from "./index-wsg3vkss.js";
5
+ import"./index-nq9h2t3x.js";
6
6
  import"./index-wj4jeavn.js";
7
7
  import"./index-5gnp8fyw.js";
8
8
  import"./index-c8s9a3zh.js";
9
9
  import"./index-fm7xz1ne.js";
10
- import"./index-48mc4d48.js";
11
- import"./index-91j1sqzm.js";
10
+ import"./index-j2v3w1ds.js";
11
+ import"./index-scww5b77.js";
12
12
  import"./index-yw8qpf51.js";
13
13
  import"./index-85bacexr.js";
14
14
  import"./index-09xpycan.js";
@@ -22,7 +22,7 @@ import"./index-bfwt3abw.js";
22
22
  import"./index-wvrj16f0.js";
23
23
  import"./index-q1exe2b3.js";
24
24
  import"./index-x2q0gnt8.js";
25
- import"./index-f1qyj61w.js";
25
+ import"./index-3yk9196e.js";
26
26
  import"./index-r3j3458j.js";
27
27
  import"./index-jtqkh8jf.js";
28
28
  import"./index-5e4e2hvv.js";
@@ -5,13 +5,13 @@ import {
5
5
  isHiveEligible,
6
6
  promoteFromSwarm,
7
7
  promoteToHive
8
- } from "./index-1emhz3zb.js";
8
+ } from "./index-nq9h2t3x.js";
9
9
  import"./index-wj4jeavn.js";
10
10
  import"./index-5gnp8fyw.js";
11
11
  import"./index-c8s9a3zh.js";
12
12
  import"./index-fm7xz1ne.js";
13
- import"./index-48mc4d48.js";
14
- import"./index-91j1sqzm.js";
13
+ import"./index-j2v3w1ds.js";
14
+ import"./index-scww5b77.js";
15
15
  import"./index-yw8qpf51.js";
16
16
  import"./index-85bacexr.js";
17
17
  import"./index-09xpycan.js";
@@ -25,7 +25,7 @@ import"./index-bfwt3abw.js";
25
25
  import"./index-wvrj16f0.js";
26
26
  import"./index-q1exe2b3.js";
27
27
  import"./index-x2q0gnt8.js";
28
- import"./index-f1qyj61w.js";
28
+ import"./index-3yk9196e.js";
29
29
  import"./index-r3j3458j.js";
30
30
  import"./index-jtqkh8jf.js";
31
31
  import"./index-5e4e2hvv.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  handleGuardrailExplain
4
- } from "./index-7jyndvsy.js";
4
+ } from "./index-wsg3vkss.js";
5
5
  import {
6
6
  handleGuardrailLog
7
7
  } from "./index-vx76tcxe.js";
@@ -80,13 +80,13 @@ import {
80
80
  handleWriteRetroCommand,
81
81
  normalizeSwarmCommandInput,
82
82
  resolveCommand
83
- } from "./index-1emhz3zb.js";
83
+ } from "./index-nq9h2t3x.js";
84
84
  import"./index-wj4jeavn.js";
85
85
  import"./index-5gnp8fyw.js";
86
86
  import"./index-c8s9a3zh.js";
87
87
  import"./index-fm7xz1ne.js";
88
- import"./index-48mc4d48.js";
89
- import"./index-91j1sqzm.js";
88
+ import"./index-j2v3w1ds.js";
89
+ import"./index-scww5b77.js";
90
90
  import"./index-yw8qpf51.js";
91
91
  import"./index-85bacexr.js";
92
92
  import"./index-09xpycan.js";
@@ -104,7 +104,7 @@ import"./index-bfwt3abw.js";
104
104
  import"./index-wvrj16f0.js";
105
105
  import"./index-q1exe2b3.js";
106
106
  import"./index-x2q0gnt8.js";
107
- import"./index-f1qyj61w.js";
107
+ import"./index-3yk9196e.js";
108
108
  import"./index-r3j3458j.js";
109
109
  import"./index-jtqkh8jf.js";
110
110
  import"./index-5e4e2hvv.js";
@@ -162,9 +162,39 @@ function makeWorktreeBranchName(sessionId, id, options) {
162
162
  }
163
163
  return `swarm/${options.purpose}/${sessionId}/${id}`;
164
164
  }
165
+ function resolveWorktreeBaseDir(directory, worktreeDir) {
166
+ return worktreeDir ? path.resolve(directory, worktreeDir) : path.resolve(path.dirname(directory), ".swarm-worktrees");
167
+ }
168
+ function isPathUnderSwarmWorktreeBase(targetPath, directory, worktreeDirOverrides = []) {
169
+ const caseInsensitive = process.platform === "win32";
170
+ let realTarget;
171
+ try {
172
+ realTarget = fs.realpathSync(path.resolve(directory, targetPath));
173
+ } catch {
174
+ return false;
175
+ }
176
+ const bases = [
177
+ resolveWorktreeBaseDir(directory),
178
+ ...worktreeDirOverrides.map((d) => resolveWorktreeBaseDir(directory, d))
179
+ ];
180
+ const cmpTarget = caseInsensitive ? realTarget.toLowerCase() : realTarget;
181
+ return bases.some((base) => {
182
+ let realBase;
183
+ try {
184
+ realBase = fs.realpathSync(base);
185
+ } catch {
186
+ realBase = path.resolve(base);
187
+ }
188
+ const cmpBase = caseInsensitive ? realBase.toLowerCase() : realBase;
189
+ if (cmpTarget === cmpBase)
190
+ return true;
191
+ const rel = path.relative(cmpBase, cmpTarget);
192
+ return rel.length > 0 && !rel.startsWith("..") && !path.isAbsolute(rel);
193
+ });
194
+ }
165
195
  async function provisionWorktree(directory, id, sessionId, options) {
166
196
  const branchName = makeWorktreeBranchName(sessionId, id, options);
167
- let worktreePath = options.worktreeDir ? path.resolve(directory, options.worktreeDir, sessionId, id) : path.resolve(path.dirname(directory), ".swarm-worktrees", sessionId, id);
197
+ let worktreePath = path.resolve(resolveWorktreeBaseDir(directory, options.worktreeDir), sessionId, id);
168
198
  const budgetResult = await checkPathBudget(worktreePath, directory);
169
199
  if (budgetResult.ok === false) {
170
200
  if (options.worktreeDir) {
@@ -285,7 +315,7 @@ async function provisionWorktree(directory, id, sessionId, options) {
285
315
  sessionId
286
316
  };
287
317
  }
288
- async function removeWorktree(worktreePath, projectRoot) {
318
+ async function removeWorktree(worktreePath, projectRoot, options) {
289
319
  const isWindows = _internals.platform === "win32";
290
320
  const MAX_RETRIES = 4;
291
321
  const RETRY_DELAY_MS = 2000;
@@ -300,6 +330,13 @@ async function removeWorktree(worktreePath, projectRoot) {
300
330
  await _internals.sleep(RETRY_DELAY_MS);
301
331
  continue;
302
332
  }
333
+ if (options?.force && isPathUnderSwarmWorktreeBase(worktreePath, projectRoot, options.worktreeDir ? [options.worktreeDir] : [])) {
334
+ const forced = await runGit(["worktree", "remove", "--force", worktreePath], projectRoot);
335
+ if (forced.exitCode === 0) {
336
+ return { success: true };
337
+ }
338
+ return { error: forced.stderr.trim() || forced.stdout.trim() };
339
+ }
303
340
  return { error: lastError };
304
341
  }
305
342
  return { error: lastError };
@@ -415,4 +452,4 @@ async function assertCleanWorkingTree(directory) {
415
452
  return { clean: true };
416
453
  }
417
454
 
418
- export { _internals, writeLaneProfileToDiskReal, removeLaneProfileFromDiskReal, checkPathBudget, shortenWorktreePath, makeWorktreeBranchName, provisionWorktree, removeWorktree, isCleanWorktree, autoCommitDirty, cleanUntrackedFiles, assertCleanWorkingTree };
455
+ export { _internals, writeLaneProfileToDiskReal, removeLaneProfileFromDiskReal, checkPathBudget, shortenWorktreePath, makeWorktreeBranchName, resolveWorktreeBaseDir, isPathUnderSwarmWorktreeBase, provisionWorktree, removeWorktree, isCleanWorktree, autoCommitDirty, cleanUntrackedFiles, assertCleanWorkingTree };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  readEffectiveSpecSync
4
- } from "./index-91j1sqzm.js";
4
+ } from "./index-scww5b77.js";
5
5
  import {
6
6
  _internals,
7
7
  buildDefaultPolicy,
@@ -2339,7 +2339,7 @@ async function takeSnapshotWithRetry(directory, plan, options) {
2339
2339
  } catch {}
2340
2340
  }
2341
2341
  async function takeSnapshotEvent(directory, plan, options) {
2342
- const payloadHash = computePlanHash(plan);
2342
+ const payloadHash = options?.payloadHashOverride ?? computePlanHash(plan);
2343
2343
  const snapshotPayload = {
2344
2344
  plan,
2345
2345
  payload_hash: payloadHash
@@ -2536,6 +2536,9 @@ async function quarantineLedgerSuffix(directory, badSuffix) {
2536
2536
  }
2537
2537
  async function loadLastApprovedPlan(directory, expectedPlanId) {
2538
2538
  const events = await readLedgerEvents(directory);
2539
+ return findLastApprovedSnapshot(events, expectedPlanId);
2540
+ }
2541
+ function findLastApprovedSnapshot(events, expectedPlanId, extraFilter) {
2539
2542
  if (events.length === 0) {
2540
2543
  return null;
2541
2544
  }
@@ -2558,6 +2561,9 @@ async function loadLastApprovedPlan(directory, expectedPlanId) {
2558
2561
  continue;
2559
2562
  }
2560
2563
  }
2564
+ if (extraFilter && !extraFilter(payload)) {
2565
+ continue;
2566
+ }
2561
2567
  return {
2562
2568
  plan: payload.plan,
2563
2569
  seq: event.seq,