Skip to content

Commit 353c0cb

Browse files
BenBtgCopilot
andcommitted
feat: fold converge artifacts from #3003 and #3005
- Add speckit.converge Copilot agent and prompt files (#3003) - Add regression test for Claude argument hints (#3005) - Remove invalid converge entry from Claude argument hints - Fix documentation removing branch-prefix fallback claims Supersedes: #3003, #3005 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent afa6470 commit 353c0cb

8 files changed

Lines changed: 327 additions & 24 deletions

File tree

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
---
2+
description: Assess the current codebase against the feature's spec, plan, and tasks, then append any remaining unbuilt work as new tasks to tasks.md so implement can complete it.
3+
---
4+
5+
## User Input
6+
7+
```text
8+
$ARGUMENTS
9+
```
10+
11+
You **MUST** consider the user input before proceeding (if not empty).
12+
13+
## Pre-Execution Checks
14+
15+
**Check for extension hooks (before convergence)**:
16+
17+
- Check if `.specify/extensions.yml` exists in the project root.
18+
- If it exists, read it and look for entries under the `hooks.before_converge` key
19+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
20+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
21+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
22+
23+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
24+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
25+
26+
- For each executable hook, output the following based on its `optional` flag:
27+
28+
- **Optional hook** (`optional: true`):
29+
30+
```text
31+
## Extension Hooks
32+
33+
**Optional Pre-Hook**: {extension}
34+
Command: `/{command}`
35+
Description: {description}
36+
37+
Prompt: {prompt}
38+
To execute: `/{command}`
39+
```
40+
41+
- **Mandatory hook** (`optional: false`):
42+
43+
```text
44+
## Extension Hooks
45+
46+
**Automatic Pre-Hook**: {extension}
47+
Executing: `/{command}`
48+
EXECUTE_COMMAND: {command}
49+
50+
Wait for the result of the hook command before proceeding to the Goal.
51+
```
52+
53+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
54+
55+
## Goal
56+
57+
Close the gap between what a feature's specification, plan, and tasks call for and what the
58+
codebase currently implements. Read `spec.md`, `plan.md`, and `tasks.md` as the **sole
59+
source of intent** (with the constitution as governing constraints), assess the current
60+
state of the code, determine which requirements, acceptance criteria, plan decisions, and
61+
existing tasks are unmet, incomplete, or only partially satisfied, and **append each piece
62+
of remaining work as a new, traceable task** at the bottom of `tasks.md` so that
63+
`/speckit.implement` can complete it. This command MUST run only after
64+
`/speckit.tasks` has produced a complete `tasks.md`.
65+
66+
This is **not** a diff tool and does **not** track changes. It assesses the present state
67+
of the code relative to the feature's artifacts — no git, no branch comparison, no history.
68+
69+
## Operating Constraints
70+
71+
**APPEND-ONLY, NEVER REWRITE**: The command's **only** write is appending a new
72+
`## Phase N — Convergence` section to `tasks.md`. It MUST NOT:
73+
74+
- modify `spec.md` or `plan.md` in any way;
75+
- rewrite, renumber, reorder, or delete any existing task (including tasks from a prior
76+
Convergence phase);
77+
- modify, create, or delete any application code — completing the appended tasks is the
78+
job of `/speckit.implement`.
79+
80+
When the codebase already satisfies everything, the command MUST leave `tasks.md`
81+
**byte-for-byte unchanged** (no empty Convergence header) and report a clean result.
82+
83+
**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is
84+
**non-negotiable**. Code that violates a MUST principle is the highest-severity finding and
85+
produces a corresponding remediation task. If the constitution is an unfilled template,
86+
skip constitution checks gracefully rather than failing.
87+
88+
## Execution Steps
89+
90+
### 1. Initialize Convergence Context
91+
92+
Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
93+
94+
- SPEC = FEATURE_DIR/spec.md
95+
- PLAN = FEATURE_DIR/plan.md
96+
- TASKS = FEATURE_DIR/tasks.md
97+
- CONSTITUTION = `.specify/memory/constitution.md` (if present)
98+
99+
If `plan.md` or `tasks.md` is missing, STOP with a clear, actionable message naming the
100+
prerequisite command to run (`/speckit.plan` for a missing plan,
101+
`/speckit.tasks` for missing tasks). Do not produce partial output.
102+
For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
103+
104+
### 2. Load Artifacts (Progressive Disclosure)
105+
106+
Load only the minimal necessary context from each artifact:
107+
108+
**From spec.md:**
109+
110+
- Functional Requirements (FR-###)
111+
- Success Criteria (SC-###) — include only items requiring buildable work; exclude
112+
post-launch outcome metrics and business KPIs
113+
- User Stories and their Acceptance Scenarios
114+
- Edge Cases (if present)
115+
116+
**From plan.md:**
117+
118+
- Architecture/stack choices and technical decisions
119+
- Data Model references
120+
- Phases and named touch-points (files/components the plan says will be created or edited)
121+
- Technical constraints
122+
123+
**From tasks.md:**
124+
125+
- Task IDs (to compute the next ID and next phase number)
126+
- Descriptions, phase grouping, and referenced file paths
127+
128+
**From constitution (if not an unfilled template):**
129+
130+
- Principle names and MUST/SHOULD normative statements
131+
132+
### 3. Build the Intent Inventory
133+
134+
Create an internal model (do not echo raw artifacts):
135+
136+
- **Requirements inventory**: one stable key per FR-### / SC-### / user-story acceptance
137+
scenario (e.g. `US1/AC2`), plus the plan decisions and constitution principles that
138+
impose buildable obligations.
139+
- **Code-scope map**: from the file paths named in `plan.md` and `tasks.md`, plus a keyword
140+
search for the concepts each requirement describes, derive the set of source files and
141+
components in scope for assessment. Bound the assessment to these — do **not** infer
142+
scope beyond what the artifacts define (FR-001).
143+
144+
### 4. Assess the Codebase and Classify Findings
145+
146+
For each item in the intent inventory, inspect the current code in scope and produce a
147+
`Finding` only where there is a gap. Classify every finding by **gap type**:
148+
149+
- **`missing`**: the required work is absent from the code entirely.
150+
- **`partial`**: the work exists but does not yet fully satisfy the requirement /
151+
acceptance criterion / plan decision.
152+
- **`contradicts`**: the code does something that conflicts with stated intent or a
153+
constitution MUST principle.
154+
- **`unrequested`**: the code contains work not called for by the spec, plan, or tasks
155+
(surfaced for awareness — converge does **not** delete code, it only appends a task to
156+
review/justify or remove it).
157+
158+
Each `Finding` records: a stable id, the `source-ref` it traces to, the `gap-type`, a
159+
severity, and a short human-readable description with the evidence (the file/area observed).
160+
161+
**Edge cases:**
162+
163+
- **Little or no code yet**: treat the entire specified scope as `missing` remaining work
164+
rather than failing.
165+
- **Nothing remains**: produce zero findings and follow the converged branch in Step 7.
166+
167+
### 5. Assign Severity
168+
169+
- **CRITICAL**: violates a constitution MUST principle, or a `missing`/`contradicts` gap
170+
that blocks baseline functionality of a P1 user story.
171+
- **HIGH**: a `missing` or `partial` gap on a core functional requirement or acceptance
172+
criterion.
173+
- **MEDIUM**: a `partial` gap on a secondary requirement, or an `unrequested` addition with
174+
unclear justification.
175+
- **LOW**: minor partial gaps, polish, or low-risk `unrequested` additions.
176+
177+
### 6. Present the In-Session Findings Summary
178+
179+
Before appending anything, output a compact, severity-graded summary (no file writes yet):
180+
181+
## Convergence Findings
182+
183+
| ID | Gap Type | Severity | Source | Evidence | Remaining Work |
184+
|----|----------|----------|--------|----------|----------------|
185+
| F1 | missing | HIGH | FR-008 | converge template has no guardrail text | Add append-only enforcement |
186+
187+
**Summary metrics:**
188+
189+
- Requirements / acceptance criteria checked
190+
- Plan decisions checked
191+
- Constitution principles checked (or "skipped — template")
192+
- Findings by gap type (missing / partial / contradicts / unrequested)
193+
- Findings by severity
194+
195+
### 7. Append Convergence Tasks (or report converged)
196+
197+
**If there are one or more actionable findings** (`tasks_appended` outcome):
198+
199+
Append to the **end** of `tasks.md`, per the append contract:
200+
201+
1. Scan all existing task IDs; let `M` be the maximum. Determine the next phase number `N`
202+
(highest existing phase + 1).
203+
2. Write a single new section header `## Phase N — Convergence`.
204+
3. Emit one checklist item per actionable finding, ordered CRITICAL/HIGH first, assigning
205+
IDs `M+1, M+2, …`:
206+
207+
```markdown
208+
- [ ] T<NNN>: <imperative description> per <source-ref> (<gap-type>)
209+
```
210+
211+
- `<source-ref>` traces the task to its origin: e.g. `FR-003`, `SC-002`, `US1/AC2`,
212+
`plan: storage decision`, `Constitution II`.
213+
- `<gap-type>` is one of `missing`, `partial`, `contradicts`, `unrequested`.
214+
- Constitution-violation tasks MUST be emitted first and described as `CRITICAL`.
215+
4. Never reuse or renumber existing IDs. If a prior Convergence phase exists, add a new,
216+
separately-numbered one below it — do not touch the old one.
217+
218+
**If there are no actionable findings** (`converged` outcome):
219+
220+
- Do **not** modify `tasks.md` at all — no empty phase header.
221+
- Report: **"✅ Converged — the implementation satisfies the spec, plan, and tasks."**
222+
- Include the summary counts of what was checked.
223+
224+
### 8. Provide Next Actions (Handoff)
225+
226+
- On `tasks_appended`: state how many tasks were appended under which phase, and recommend
227+
running `/speckit.implement` to complete them; note that a follow-up converge
228+
run will find fewer or no remaining items.
229+
- On `converged`: recommend proceeding to review / opening a PR. No further implement pass
230+
is needed for this feature's specified scope.
231+
232+
### 9. Check for extension hooks
233+
234+
After producing the result, check if `.specify/extensions.yml` exists in the project root.
235+
236+
- If it exists, read it and look for entries under the `hooks.after_converge` key
237+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
238+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
239+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
240+
241+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
242+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
243+
244+
- Pass the convergence outcome (`converged` or `tasks_appended`) to the hook context so an
245+
extension can branch on it.
246+
- For each executable hook, output the following based on its `optional` flag:
247+
248+
- **Optional hook** (`optional: true`):
249+
250+
```text
251+
## Extension Hooks
252+
253+
**Optional Hook**: {extension}
254+
Command: `/{command}`
255+
Description: {description}
256+
257+
Prompt: {prompt}
258+
To execute: `/{command}`
259+
```
260+
261+
- **Mandatory hook** (`optional: false`):
262+
263+
```text
264+
## Extension Hooks
265+
266+
**Automatic Hook**: {extension}
267+
Executing: `/{command}`
268+
EXECUTE_COMMAND: {command}
269+
```
270+
271+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
agent: speckit.converge
3+
---

specs/001-converge-command/contracts/command-interface.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ Defines the user-facing invocation contract for `/speckit.converge`.
55
## Invocation
66

77
```text
8-
/speckit.converge [feature-name]
8+
/speckit.converge
99
```
1010

11-
- `feature-name` (optional positional argument): the feature directory to assess (e.g. `specs/003-user-auth`). When omitted, the command resolves the active feature via `SPECIFY_FEATURE_DIRECTORY` or `.specify/feature.json` (the same mechanism used by `analyze` and `implement`). If neither is set, the command must stop with an actionable error explaining how to set feature context (for example by running `specify` first or exporting `SPECIFY_FEATURE_DIRECTORY`).
11+
- The command resolves the active feature via `SPECIFY_FEATURE_DIRECTORY` or `.specify/feature.json` (the same mechanism used by `analyze` and `implement`). If neither is set, the command must stop with an actionable error explaining how to set feature context (for example by running `specify` first or exporting `SPECIFY_FEATURE_DIRECTORY`).
1212
- Invocation convention follows the agent's separator: `/speckit.converge` (dot agents) or
1313
`/speckit-converge` (skills/hyphen agents). This is produced automatically from the
1414
`__SPECKIT_COMMAND_CONVERGE__` token — no per-agent code required.

specs/001-converge-command/plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ src/specify_cli/
102102
├── commands/
103103
│ └── init.py # EDIT — add "converge" to the post-init "Next Steps" panel (after implement)
104104
└── integrations/
105-
└── claude/__init__.py # EDIT — add "converge" argument hint
105+
└── claude/__init__.py # EDIT — keep converge out of Claude argument hints
106106
107107
tests/
108108
├── test_agent_config_consistency.py # VERIFY — converge token resolves correctly

specs/001-converge-command/research.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ that shape the design, with rationale and rejected alternatives.
2626
(and the `.ps1` equivalent) in the command frontmatter `scripts:` block to resolve
2727
`FEATURE_DIR` and confirm `plan.md` + `tasks.md` exist.
2828
- **Rationale**: This is the same mechanism `analyze` and `implement` use. It already
29-
resolves the feature directory via `SPECIFY_FEATURE_DIRECTORY``.specify/feature.json`
30-
→ branch-prefix fallback, so it works with or without git (Constitution Principle II).
29+
resolves the feature directory via `SPECIFY_FEATURE_DIRECTORY``.specify/feature.json`,
30+
so it works without introducing any git dependency (Constitution Principle II).
3131
No new script is introduced, preserving cross-platform parity by construction.
3232
- **Alternatives considered**:
3333
- *New `converge`-specific helper script* — rejected: would require Bash + PowerShell

specs/001-converge-command/tasks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ in `docs/`.
3939

4040
- [X] T003 [P] Add `"converge"` with a one-line description to `SKILL_DESCRIPTIONS` in `src/specify_cli/__init__.py`.
4141
- [X] T004 [P] Add `"converge"` to the `_FALLBACK_CORE_COMMAND_NAMES` frozenset in `src/specify_cli/extensions.py` (~L31; it is a frozenset, so simply append the entry — ordering is not significant).
42-
- [X] T005 [P] Add a `"converge"` argument-hint entry to `ARGUMENT_HINTS` in `src/specify_cli/integrations/claude/__init__.py`.
42+
- [X] T005 [P] Keep `"converge"` out of `ARGUMENT_HINTS` in `src/specify_cli/integrations/claude/__init__.py` because the command does not accept a feature-name argument.
4343
- [X] T006 [P] Add `"converge"` to the `COMMAND_STEMS` list in `tests/integrations/test_integration_base_yaml.py`.
4444
- [X] T007 [P] Add `"converge"` to the `COMMAND_STEMS` list in `tests/integrations/test_integration_base_toml.py`.
4545
- [X] T008 [P] Add `"converge"` to the expected command-stems list in `tests/integrations/test_integration_base_markdown.py`.
@@ -140,7 +140,7 @@ in `docs/`.
140140
# These edit different files and can be done together:
141141
Task: T003 Add "converge" to SKILL_DESCRIPTIONS in src/specify_cli/__init__.py
142142
Task: T004 Add "converge" to _FALLBACK_CORE_COMMAND_NAMES in src/specify_cli/extensions.py
143-
Task: T005 Add "converge" hint in src/specify_cli/integrations/claude/__init__.py
143+
Task: T005 Keep "converge" out of ARGUMENT_HINTS in src/specify_cli/integrations/claude/__init__.py
144144
Task: T006 Add "converge" to COMMAND_STEMS in tests/integrations/test_integration_base_yaml.py
145145
Task: T007 Add "converge" to COMMAND_STEMS in tests/integrations/test_integration_base_toml.py
146146
Task: T008 Add "converge" to tests/integrations/test_integration_base_markdown.py

src/specify_cli/integrations/claude/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"plan": "Optional guidance for the planning phase",
1717
"tasks": "Optional task generation constraints",
1818
"implement": "Optional implementation guidance or task filter",
19-
"converge": "Optional feature name to converge",
2019
"analyze": "Optional focus areas for analysis",
2120
"clarify": "Optional areas to clarify in the spec",
2221
"constitution": "Principles or values for the project constitution",

0 commit comments

Comments
 (0)