@ancleto/spec 0.4.2 → 0.4.5
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.
package/package.json
CHANGED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openspec-apply
|
|
3
|
+
description: Implement tasks from a change step by step, tracking progress in tasks.md. Use when artifacts are ready and implementation should start. No external binaries required.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: No external binaries required. Works with any agent runtime.
|
|
6
|
+
metadata:
|
|
7
|
+
author: ancleto
|
|
8
|
+
version: '1.0'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenSpec Apply
|
|
12
|
+
|
|
13
|
+
Implement the tasks of a change, working directly from its artifact files. No external binaries are invoked: task state lives in `tasks.md` checkboxes.
|
|
14
|
+
|
|
15
|
+
**Input**: Optionally specify a change name (e.g., `add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous, list the directories under `openspec/changes/` and ask the user to select.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
### 1. Select the change
|
|
20
|
+
|
|
21
|
+
- If a name is provided, use it. Announce: "Using change: `<name>`" and how to override.
|
|
22
|
+
- If omitted: infer from conversation context; auto-select if only one active change directory exists under `openspec/changes/`; otherwise list the directories and ask the user to choose.
|
|
23
|
+
|
|
24
|
+
**IMPORTANT**: Do NOT guess or auto-select when ambiguous. Always let the user choose.
|
|
25
|
+
|
|
26
|
+
### 2. Understand the change state
|
|
27
|
+
|
|
28
|
+
Read the change directory `openspec/changes/<name>/` and load:
|
|
29
|
+
|
|
30
|
+
- `proposal.md` — what & why (if present)
|
|
31
|
+
- `design.md` — approach and decisions (if present)
|
|
32
|
+
- `tasks.md` — the task list with checkbox state (required)
|
|
33
|
+
- `specs/` — delta requirements (if present)
|
|
34
|
+
|
|
35
|
+
If `tasks.md` is missing, report it and stop: there is nothing to implement. Suggest completing the artifacts first.
|
|
36
|
+
|
|
37
|
+
### 3. Read context files
|
|
38
|
+
|
|
39
|
+
Read every artifact found in step 2 before writing any code:
|
|
40
|
+
|
|
41
|
+
- **proposal + design**: the intent and the chosen approach
|
|
42
|
+
- **specs/**: the exact required behavior and scenarios
|
|
43
|
+
- **tasks.md**: the ordered checklist
|
|
44
|
+
|
|
45
|
+
Do not assume file names beyond these four; read what exists.
|
|
46
|
+
|
|
47
|
+
### 4. Show current progress
|
|
48
|
+
|
|
49
|
+
Display:
|
|
50
|
+
|
|
51
|
+
- Tasks completed vs total (count `- [x]` vs `- [ ]` in `tasks.md`)
|
|
52
|
+
- Remaining tasks overview
|
|
53
|
+
|
|
54
|
+
### 5. Implement tasks (loop until done or blocked)
|
|
55
|
+
|
|
56
|
+
For each pending task (`- [ ]`):
|
|
57
|
+
|
|
58
|
+
- Show which task is being worked on
|
|
59
|
+
- Make the code changes required
|
|
60
|
+
- Keep changes minimal and focused
|
|
61
|
+
- Mark the task complete in the tasks file: `- [ ]` → `- [x]`
|
|
62
|
+
- Continue to the next task
|
|
63
|
+
|
|
64
|
+
**Pause if:**
|
|
65
|
+
|
|
66
|
+
- Task is unclear → ask for clarification
|
|
67
|
+
- Implementation reveals a design issue → suggest updating artifacts
|
|
68
|
+
- Error or blocker encountered → report and wait for guidance
|
|
69
|
+
- User interrupts
|
|
70
|
+
|
|
71
|
+
### 6. On completion or pause, show status
|
|
72
|
+
|
|
73
|
+
**On completion:**
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
## Implementation Complete
|
|
77
|
+
|
|
78
|
+
**Change:** <change-name>
|
|
79
|
+
**Progress:** N/N tasks complete ✓
|
|
80
|
+
|
|
81
|
+
All tasks complete! You can archive this change with `openspec-archive`.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**On pause:**
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
## Implementation Paused
|
|
88
|
+
|
|
89
|
+
**Change:** <change-name>
|
|
90
|
+
**Progress:** M/N tasks complete
|
|
91
|
+
|
|
92
|
+
### Issue Encountered
|
|
93
|
+
<description of the issue>
|
|
94
|
+
|
|
95
|
+
What would you like to do?
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Output During Implementation
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
## Implementing: <change-name>
|
|
102
|
+
|
|
103
|
+
Working on task 3/7: <task description>
|
|
104
|
+
[...implementation happening...]
|
|
105
|
+
✓ Task complete
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Guardrails
|
|
109
|
+
|
|
110
|
+
- Keep going through tasks until done or blocked
|
|
111
|
+
- Always read the change artifacts before starting
|
|
112
|
+
- If a task is ambiguous, pause and ask before implementing
|
|
113
|
+
- If implementation reveals issues, pause and suggest artifact updates
|
|
114
|
+
- Keep code changes minimal and scoped to each task
|
|
115
|
+
- Update the task checkbox immediately after completing each task
|
|
116
|
+
- Pause on errors, blockers, or unclear requirements — don't guess
|
|
117
|
+
- An implementation task may be revisited: if artifacts change mid-flight, re-read them before continuing
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openspec-archive
|
|
3
|
+
description: Archive a completed change, syncing delta specs first when needed. Use when implementation and verification are done. Captures lessons into persistent memory. No external binaries required.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: No external binaries required. Works with any agent runtime.
|
|
6
|
+
metadata:
|
|
7
|
+
author: ancleto
|
|
8
|
+
version: '1.0'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenSpec Archive
|
|
12
|
+
|
|
13
|
+
Archive a completed change by moving its directory, after checking completion and syncing delta specs. No external binaries are invoked: completion is read from files, archiving is a directory move.
|
|
14
|
+
|
|
15
|
+
**Input**: Optionally specify a change name (e.g., `add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous, list the directories under `openspec/changes/` (excluding `archive/`) and ask the user to select.
|
|
16
|
+
|
|
17
|
+
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
|
18
|
+
|
|
19
|
+
## Steps
|
|
20
|
+
|
|
21
|
+
### 1. Check task completion status
|
|
22
|
+
|
|
23
|
+
Read `openspec/changes/<name>/tasks.md` (when it exists) and count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).
|
|
24
|
+
|
|
25
|
+
- **If incomplete tasks found**: display a warning showing the count, prompt the user for confirmation to continue, and proceed only if confirmed.
|
|
26
|
+
- **If no tasks file exists**: proceed without a task-related warning.
|
|
27
|
+
|
|
28
|
+
### 2. Assess delta spec sync state
|
|
29
|
+
|
|
30
|
+
Check for delta specs at `openspec/changes/<name>/specs/`. If none exist, proceed without a sync prompt.
|
|
31
|
+
|
|
32
|
+
**If delta specs exist:**
|
|
33
|
+
|
|
34
|
+
- Compare each delta spec with its corresponding main spec at `openspec/specs/<capability>/spec.md`.
|
|
35
|
+
- Determine what would change (adds, modifications, removals, renames) and show a combined summary.
|
|
36
|
+
- Prompt the user: "Sync now (recommended)" vs "Archive without syncing" (or "Archive now" / "Sync anyway" / "Cancel" when already synced).
|
|
37
|
+
- If the user chooses sync, apply the delta to the main spec directly, editing `openspec/specs/<capability>/spec.md`:
|
|
38
|
+
- `## ADDED Requirements` → add the new requirement blocks (skip those already present).
|
|
39
|
+
- `## MODIFIED Requirements` → update the matching requirement, preserving scenarios not mentioned in the delta.
|
|
40
|
+
- `## REMOVED Requirements` → remove the entire requirement block.
|
|
41
|
+
- `## RENAMED Requirements` → rename using the `FROM:`/`TO:` pair.
|
|
42
|
+
- Proceed to archive regardless of the choice.
|
|
43
|
+
|
|
44
|
+
### 3. Perform the archive
|
|
45
|
+
|
|
46
|
+
Create the archive directory if it does not exist: `openspec/changes/archive/`.
|
|
47
|
+
|
|
48
|
+
Generate the target name using the current date: `YYYY-MM-DD-<change-name>`.
|
|
49
|
+
|
|
50
|
+
- **If the target already exists**: fail with an error suggesting to rename the existing archive or pick a different date.
|
|
51
|
+
- **If not**: delete scaffold-only files (e.g., `openspec/changes/<name>/context.md` — they must not be preserved), then move the whole change directory to `openspec/changes/archive/YYYY-MM-DD-<name>/`.
|
|
52
|
+
|
|
53
|
+
### 4. Capture lessons into persistent memory
|
|
54
|
+
|
|
55
|
+
Record what this change taught, using the memory tools:
|
|
56
|
+
|
|
57
|
+
- Architectural decisions taken during the change, with their reasons → `recordDecision`, e.g.:
|
|
58
|
+
```
|
|
59
|
+
recordDecision({ memory_key: "<kebab-topic>", content: "<the decision>", justification: "<why this path>" })
|
|
60
|
+
```
|
|
61
|
+
- Standing rules or constraints discovered (things future agents must keep following) → `recordRule`, e.g.:
|
|
62
|
+
```
|
|
63
|
+
recordRule({ memory_key: "<kebab-topic>", content: "<the rule>", justification: "<evidence>" })
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Record only durable lessons — decisions whose reasons are not visible in the result, constraints, verified workarounds. Never record workflow meta (what was reviewed, approved, or classified). If nothing meets the bar, record nothing and say so.
|
|
67
|
+
|
|
68
|
+
### 5. Display summary
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
## Archive Complete
|
|
72
|
+
|
|
73
|
+
**Change:** <change-name>
|
|
74
|
+
**Archived to:** openspec/changes/archive/YYYY-MM-DD-<name>/
|
|
75
|
+
**Specs:** ✓ Synced to main specs (or: No delta specs / Sync skipped)
|
|
76
|
+
|
|
77
|
+
**Memories recorded:** <list, or "None">
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If warnings applied (incomplete tasks, skipped sync), show an "Archive Complete (with warnings)" variant listing them.
|
|
81
|
+
|
|
82
|
+
## Guardrails
|
|
83
|
+
|
|
84
|
+
- Always prompt for change selection if not provided.
|
|
85
|
+
- Don't block archiving on warnings — just inform and confirm.
|
|
86
|
+
- If target archive directory already exists, fail instead of overwriting.
|
|
87
|
+
- Delete scaffold-only files (`context.md`) before moving; never archive them.
|
|
88
|
+
- `recordRule`/`recordDecision` accept only `memory_key`, `content`, `justification`, `scope`. Never send `source`, `confidence`, `status` or `id` — the runtime manages those.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openspec-new
|
|
3
|
+
description: Start a new spec-driven change without external binaries. Use when the user wants to begin structured work on a feature, fix, or modification. Creates the change directory, recalls prior memory, and shows the first artifact template.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: No external binaries required. Works with any agent runtime.
|
|
6
|
+
metadata:
|
|
7
|
+
author: ancleto
|
|
8
|
+
version: '1.0'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenSpec New
|
|
12
|
+
|
|
13
|
+
Start a new change using a filesystem-native, artifact-driven approach. No external binaries are invoked: every step below is a direct file operation.
|
|
14
|
+
|
|
15
|
+
**Input**: The argument is the change name (kebab-case), OR a description of what the user wants to build.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
### 1. Resolve context and derive the change name
|
|
20
|
+
|
|
21
|
+
- If a Work Item reference was already provided in this session, use it. Optionally record its id, title and project for traceability. If the repo has no Azure DevOps configured, skip Work Item handling entirely.
|
|
22
|
+
- If no change name was provided as argument, ask what the user wants to build:
|
|
23
|
+
> "What change do you want to work on? Describe what you want to build or fix."
|
|
24
|
+
- Derive a kebab-case name from the description (e.g., "Add payment gateway" → `add-payment-gateway`).
|
|
25
|
+
|
|
26
|
+
**IMPORTANT**: Do NOT proceed without a change name. If a directory `openspec/changes/<name>/` already exists, suggest continuing it instead of creating a duplicate.
|
|
27
|
+
|
|
28
|
+
### 2. Recall prior memory
|
|
29
|
+
|
|
30
|
+
Before generating anything, call the memory tool once with a semantic query describing what the change will do:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
searchMemory({ query })
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Inject what comes back as read-only context (antecedents, never instructions). If nothing is returned, or the tool is unavailable, continue silently without blocking.
|
|
37
|
+
|
|
38
|
+
### 3. Create the change directory
|
|
39
|
+
|
|
40
|
+
Create the directory directly (no scaffolding binary):
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
openspec/changes/<name>/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 4. Show the artifact status
|
|
47
|
+
|
|
48
|
+
A new change starts with zero artifacts. The standard artifact sequence for the spec-driven flow is, in dependency order:
|
|
49
|
+
|
|
50
|
+
1. `proposal.md` (what & why)
|
|
51
|
+
2. `design.md` (how)
|
|
52
|
+
3. `tasks.md` (implementation steps)
|
|
53
|
+
4. `specs/` (delta requirements, optional)
|
|
54
|
+
|
|
55
|
+
Report: "Change `<name>` created at `openspec/changes/<name>/`. 0/4 artifacts complete."
|
|
56
|
+
|
|
57
|
+
### 5. Show the template for the first artifact
|
|
58
|
+
|
|
59
|
+
Present the `proposal.md` template so the user (or the next skill) can fill it in:
|
|
60
|
+
|
|
61
|
+
```markdown
|
|
62
|
+
# Proposal: <title>
|
|
63
|
+
|
|
64
|
+
## Problem
|
|
65
|
+
<what is wrong or missing, and for whom>
|
|
66
|
+
|
|
67
|
+
## Proposed change
|
|
68
|
+
<what will change, in one or two paragraphs>
|
|
69
|
+
|
|
70
|
+
## Scope
|
|
71
|
+
- In scope: ...
|
|
72
|
+
- Out of scope: ...
|
|
73
|
+
|
|
74
|
+
## Risks
|
|
75
|
+
- <risk>: <mitigation>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 6. STOP and wait for user direction
|
|
79
|
+
|
|
80
|
+
## Output
|
|
81
|
+
|
|
82
|
+
After completing the steps, summarize:
|
|
83
|
+
|
|
84
|
+
- Change name and location
|
|
85
|
+
- Artifact sequence and current status (0/4 artifacts complete)
|
|
86
|
+
- The template for the first artifact
|
|
87
|
+
- Prompt: "Ready to create the first artifact? Run `openspec-propose` or just describe what this change is about and I'll draft it."
|
|
88
|
+
|
|
89
|
+
## Guardrails
|
|
90
|
+
|
|
91
|
+
- Do NOT create any artifacts yet — just show the template
|
|
92
|
+
- Do NOT advance beyond showing the first artifact template
|
|
93
|
+
- If the name is invalid (not kebab-case), ask for a valid name
|
|
94
|
+
- If a change with that name already exists, suggest continuing it instead
|
|
95
|
+
- Memory recall never blocks artifact creation
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openspec-propose
|
|
3
|
+
description: Draft all artifacts for a change in one step (proposal, design, tasks, delta specs). Use after openspec-new, or directly with a change name or description. No external binaries required.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: No external binaries required. Works with any agent runtime.
|
|
6
|
+
metadata:
|
|
7
|
+
author: ancleto
|
|
8
|
+
version: '1.0'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenSpec Propose
|
|
12
|
+
|
|
13
|
+
Create a change and generate all its artifacts in one step, writing files directly. No external binaries are invoked.
|
|
14
|
+
|
|
15
|
+
**Input**: The argument is the change name (kebab-case), OR a description of what the user wants to build.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
### 1. Resolve context and derive the change name
|
|
20
|
+
|
|
21
|
+
Same as `openspec-new` step 1: use in-session Work Item context if available (record id/title/project for traceability, skip entirely when Azure DevOps is not configured), otherwise ask what the user wants to build and derive a kebab-case name.
|
|
22
|
+
|
|
23
|
+
**IMPORTANT**: Do NOT proceed without a change name. If a change with that name already exists, ask whether to continue it or create a new one.
|
|
24
|
+
|
|
25
|
+
### 2. Recall prior memory
|
|
26
|
+
|
|
27
|
+
Call the memory tool once with a semantic query describing what the change will do:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
searchMemory({ query })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Use what comes back as read-only background while drafting. If nothing is returned, or the tool is unavailable, continue silently without blocking.
|
|
34
|
+
|
|
35
|
+
### 3. Create the change directory
|
|
36
|
+
|
|
37
|
+
Create `openspec/changes/<name>/` directly if it does not exist yet.
|
|
38
|
+
|
|
39
|
+
### 4. Create artifacts in dependency order
|
|
40
|
+
|
|
41
|
+
Write each artifact file directly, in this order. Read each completed artifact before drafting the next one so they stay consistent.
|
|
42
|
+
|
|
43
|
+
**4a. `proposal.md`** — what & why:
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
# Proposal: <title>
|
|
47
|
+
|
|
48
|
+
## Problem
|
|
49
|
+
<what is wrong or missing, and for whom>
|
|
50
|
+
|
|
51
|
+
## Proposed change
|
|
52
|
+
<what will change>
|
|
53
|
+
|
|
54
|
+
## Scope
|
|
55
|
+
- In scope: ...
|
|
56
|
+
- Out of scope: ...
|
|
57
|
+
|
|
58
|
+
## Risks
|
|
59
|
+
- <risk>: <mitigation>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**4b. `design.md`** — how:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
# Design: <title>
|
|
66
|
+
|
|
67
|
+
## Approach
|
|
68
|
+
<chosen approach and why it was preferred over alternatives>
|
|
69
|
+
|
|
70
|
+
## Architecture
|
|
71
|
+
<components touched, data flow, key interfaces>
|
|
72
|
+
|
|
73
|
+
## Validation
|
|
74
|
+
<how the change will be verified: tests, checks, manual steps>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**4c. `tasks.md`** — phased implementation checklist:
|
|
78
|
+
|
|
79
|
+
```markdown
|
|
80
|
+
# Tasks: <title>
|
|
81
|
+
|
|
82
|
+
- [ ] Task 1 — <description>
|
|
83
|
+
- [ ] Task 2 — <description>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Break work into small, independently verifiable tasks. Mark each with `- [ ]` (unchecked).
|
|
87
|
+
|
|
88
|
+
**4d. `specs/<capability>/spec.md`** — delta requirements (only when the change alters specified behavior):
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
## ADDED Requirements
|
|
92
|
+
|
|
93
|
+
### Requirement: <name>
|
|
94
|
+
|
|
95
|
+
The system SHALL <behavior>.
|
|
96
|
+
|
|
97
|
+
#### Scenario: <name>
|
|
98
|
+
|
|
99
|
+
- **WHEN** <condition>
|
|
100
|
+
- **THEN** <expected outcome>
|
|
101
|
+
|
|
102
|
+
## MODIFIED Requirements
|
|
103
|
+
|
|
104
|
+
### Requirement: <name>
|
|
105
|
+
|
|
106
|
+
#### Scenario: <new or changed scenario>
|
|
107
|
+
|
|
108
|
+
- **WHEN** <condition>
|
|
109
|
+
- **THEN** <expected outcome>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If the change adds no specified behavior, skip `specs/` and note why.
|
|
113
|
+
|
|
114
|
+
### 5. Verify each file exists before proceeding to the next
|
|
115
|
+
|
|
116
|
+
After writing an artifact, confirm the file is on disk, then continue.
|
|
117
|
+
|
|
118
|
+
## Output
|
|
119
|
+
|
|
120
|
+
After completing all artifacts, summarize:
|
|
121
|
+
|
|
122
|
+
- Change name and location
|
|
123
|
+
- List of artifacts created with brief descriptions
|
|
124
|
+
- What's ready: "All artifacts created! Ready for implementation."
|
|
125
|
+
- Prompt: "Run `openspec-apply` to start implementing."
|
|
126
|
+
|
|
127
|
+
## Artifact Creation Guidelines
|
|
128
|
+
|
|
129
|
+
- Read dependency artifacts for context before creating new ones
|
|
130
|
+
- Keep each artifact focused on its own concern (what / how / steps / requirements)
|
|
131
|
+
- If context is critically unclear, ask the user — but prefer making reasonable decisions to keep momentum
|
|
132
|
+
|
|
133
|
+
## Guardrails
|
|
134
|
+
|
|
135
|
+
- Create ALL artifacts needed for implementation (proposal, design, tasks; specs only when behavior is specified)
|
|
136
|
+
- Always read dependency artifacts before creating a new one
|
|
137
|
+
- If a change with that name already exists, ask whether to continue it or create a new one
|
|
138
|
+
- Verify each artifact file exists after writing before proceeding to the next
|
|
139
|
+
- Memory recall never blocks artifact creation
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openspec-verify
|
|
3
|
+
description: Verify an implementation against its change artifacts (completeness, correctness, coherence). Use before archiving a change. Captures architectural findings into persistent memory. No external binaries required.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: No external binaries required. Works with any agent runtime.
|
|
6
|
+
metadata:
|
|
7
|
+
author: ancleto
|
|
8
|
+
version: '1.0'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenSpec Verify
|
|
12
|
+
|
|
13
|
+
Verify that an implementation matches its change artifacts (proposal, design, tasks, delta specs) by reading the files directly. No external binaries are invoked.
|
|
14
|
+
|
|
15
|
+
**Input**: Optionally specify a change name (e.g., `add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous, list the directories under `openspec/changes/` that contain a `tasks.md` file and ask the user to select. Mark changes with incomplete tasks as "(In Progress)".
|
|
16
|
+
|
|
17
|
+
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
|
18
|
+
|
|
19
|
+
## Steps
|
|
20
|
+
|
|
21
|
+
### 1. Load the change artifacts
|
|
22
|
+
|
|
23
|
+
Read everything under `openspec/changes/<name>/`:
|
|
24
|
+
|
|
25
|
+
- `tasks.md` — the checklist (required)
|
|
26
|
+
- `proposal.md`, `design.md` — intent and decisions (if present)
|
|
27
|
+
- `specs/` — delta requirements (if present)
|
|
28
|
+
|
|
29
|
+
### 2. Verify Completeness
|
|
30
|
+
|
|
31
|
+
**Task Completion:**
|
|
32
|
+
|
|
33
|
+
- Parse checkboxes in `tasks.md`: `- [ ]` (incomplete) vs `- [x]` (complete).
|
|
34
|
+
- Count complete vs total tasks.
|
|
35
|
+
- For each incomplete task, add a CRITICAL issue: "Complete task: `<description>`" or "Mark as done if already implemented".
|
|
36
|
+
|
|
37
|
+
**Spec Coverage:**
|
|
38
|
+
|
|
39
|
+
- If delta specs exist in `openspec/changes/<name>/specs/`:
|
|
40
|
+
- Extract all requirements (marked with `### Requirement:`).
|
|
41
|
+
- For each requirement, search the codebase for keywords related to it and assess whether implementation likely exists.
|
|
42
|
+
- If a requirement appears unimplemented, add a CRITICAL issue: "Requirement not found: `<requirement name>`" with the recommendation "Implement requirement: `<description>`".
|
|
43
|
+
|
|
44
|
+
### 3. Verify Correctness
|
|
45
|
+
|
|
46
|
+
**Requirement Implementation Mapping:**
|
|
47
|
+
|
|
48
|
+
- For each requirement from delta specs, search the codebase for implementation evidence.
|
|
49
|
+
- If found, note file paths and line ranges.
|
|
50
|
+
- If divergence is detected, add a WARNING: "Implementation may diverge from spec: `<details>`" with "Review `<file>:<lines>` against requirement X".
|
|
51
|
+
|
|
52
|
+
**Scenario Coverage:**
|
|
53
|
+
|
|
54
|
+
- For each scenario in delta specs (marked with `#### Scenario:`), check whether conditions are handled in code and whether tests cover the scenario.
|
|
55
|
+
- If a scenario appears uncovered, add a WARNING: "Scenario not covered: `<scenario name>`" with "Add test or implementation for scenario: `<description>`".
|
|
56
|
+
|
|
57
|
+
### 4. Verify Coherence
|
|
58
|
+
|
|
59
|
+
**Design Adherence:**
|
|
60
|
+
|
|
61
|
+
- If `design.md` exists, extract key decisions (sections like "Decision:", "Approach:", "Architecture:") and verify the implementation follows them.
|
|
62
|
+
- If a contradiction is detected, add a WARNING: "Design decision not followed: `<decision>`" with "Update implementation or revise design.md to match reality".
|
|
63
|
+
- If no `design.md` exists, skip this check and note "No design.md to verify against".
|
|
64
|
+
|
|
65
|
+
**Code Pattern Consistency:**
|
|
66
|
+
|
|
67
|
+
- Review new code for consistency with project patterns (file naming, directory structure, coding style).
|
|
68
|
+
- Significant deviations get a SUGGESTION: "Code pattern deviation: `<details>`" with "Consider following project pattern: `<example>`".
|
|
69
|
+
|
|
70
|
+
### 5. Capture findings into persistent memory
|
|
71
|
+
|
|
72
|
+
For every WARNING or CRITICAL issue that reveals an architectural decision, a standing rule, or a reusable lesson, record it with the memory tools:
|
|
73
|
+
|
|
74
|
+
- Standing rules, constraints, or conventions the team must keep following → `recordRule`, e.g.:
|
|
75
|
+
```
|
|
76
|
+
recordRule({ memory_key: "<kebab-topic>", content: "<the rule>", justification: "<evidence>" })
|
|
77
|
+
```
|
|
78
|
+
- Design decisions, trade-offs, and why one path was taken → `recordDecision`, e.g.:
|
|
79
|
+
```
|
|
80
|
+
recordDecision({ memory_key: "<kebab-topic>", content: "<the decision>", justification: "<reason>" })
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Record only findings that would save future investigation. Do not record the verification outcome itself. If no finding meets the bar, record nothing and say so.
|
|
84
|
+
|
|
85
|
+
### 6. Generate the Verification Report
|
|
86
|
+
|
|
87
|
+
**Summary Scorecard:**
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
## Verification Report: <change-name>
|
|
91
|
+
|
|
92
|
+
### Summary
|
|
93
|
+
| Dimension | Status |
|
|
94
|
+
|--------------|------------------|
|
|
95
|
+
| Completeness | X/Y tasks, N reqs|
|
|
96
|
+
| Correctness | M/N reqs covered |
|
|
97
|
+
| Coherence | Followed/Issues |
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Issues by Priority:**
|
|
101
|
+
|
|
102
|
+
1. **CRITICAL** (must fix before archive): incomplete tasks, missing requirement implementations — each with a specific, actionable recommendation.
|
|
103
|
+
2. **WARNING** (should fix): spec/design divergences, missing scenario coverage — each with a specific recommendation.
|
|
104
|
+
3. **SUGGESTION** (nice to fix): pattern inconsistencies, minor improvements.
|
|
105
|
+
|
|
106
|
+
**Final Assessment:**
|
|
107
|
+
|
|
108
|
+
- If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
|
|
109
|
+
- If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
|
|
110
|
+
- If all clear: "All checks passed. Ready for archive."
|
|
111
|
+
- Plus a line listing which memories were recorded in step 5 (or "No findings recorded").
|
|
112
|
+
|
|
113
|
+
## Verification Heuristics
|
|
114
|
+
|
|
115
|
+
- **Completeness**: focus on objective checklist items (checkboxes, requirements list).
|
|
116
|
+
- **Correctness**: use keyword search, file path analysis, reasonable inference — don't require perfect certainty.
|
|
117
|
+
- **Coherence**: look for glaring inconsistencies, don't nitpick style.
|
|
118
|
+
- **False Positives**: when uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL.
|
|
119
|
+
- **Actionability**: every issue must have a specific recommendation with file/line references where applicable.
|
|
120
|
+
|
|
121
|
+
## Graceful Degradation
|
|
122
|
+
|
|
123
|
+
- If only `tasks.md` exists: verify task completion only, skip spec/design checks.
|
|
124
|
+
- If tasks + specs exist: verify completeness and correctness, skip design.
|
|
125
|
+
- If full artifacts: verify all three dimensions.
|
|
126
|
+
- Always note which checks were skipped and why.
|
|
127
|
+
|
|
128
|
+
## Guardrails
|
|
129
|
+
|
|
130
|
+
- Use code references in format `file.ts:123`.
|
|
131
|
+
- No vague suggestions like "consider reviewing" — every issue needs a specific recommendation.
|
|
132
|
+
- `recordRule`/`recordDecision` accept only `memory_key`, `content`, `justification`, `scope`. Never send `source`, `confidence`, `status` or `id` — the runtime manages those.
|
package/src/cli/index.js
CHANGED
|
@@ -13,6 +13,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
13
13
|
const ROOT = join(__dirname, '..', '..')
|
|
14
14
|
const ASSETS = ['agents', 'commands', 'skills']
|
|
15
15
|
const TEMPLATES = ['AGENTS.md', 'PRODUCT.md']
|
|
16
|
+
const AZURE_MCP_NOTICE = 'ancleto: MCP azure-devops habilitado — usa las variables de entorno AZURE_DEVOPS_ORG_URL y AZURE_DEVOPS_PAT'
|
|
16
17
|
|
|
17
18
|
const HELP = `ancleto - orquestador SDD liviano con subagentes optimizados para costo/tokens
|
|
18
19
|
(alias: aspec)
|
|
@@ -23,9 +24,11 @@ Uso:
|
|
|
23
24
|
Configura los MCP engram + caveman por defecto
|
|
24
25
|
ancleto install --no-mcp Igual que install pero sin tocar config MCP
|
|
25
26
|
ancleto install --tier <nivel> normal | minimo | gratis (pregunta en la 1ra config)
|
|
27
|
+
ancleto install --agent <nombre> opencode | vscode | antigravity | cursor | roo (pregunta si no esta guardado)
|
|
26
28
|
ancleto update [--project <dir>] Alias de install (re-instala sobre lo existente)
|
|
27
|
-
ancleto init [--with-azure]
|
|
28
|
-
|
|
29
|
+
ancleto init [--with-azure] [--agent <nombre>]
|
|
30
|
+
Crea .ancletorc en el repositorio actual
|
|
31
|
+
(Azure desactivado por defecto, agente: opencode)
|
|
29
32
|
ancleto discovery --check Estado del seed (READY/STALE/PARTIAL/MISSING)
|
|
30
33
|
ancleto discovery [--compress] [--include G] [--ignore G] [--token-budget N]
|
|
31
34
|
Empaca el repo con Repomix y guarda estado
|
|
@@ -181,6 +184,35 @@ function askTier() {
|
|
|
181
184
|
})
|
|
182
185
|
}
|
|
183
186
|
|
|
187
|
+
const SUPPORTED_AGENTS = ['opencode', 'vscode', 'antigravity', 'cursor', 'roo']
|
|
188
|
+
const DEFAULT_AGENT = 'opencode'
|
|
189
|
+
|
|
190
|
+
function askAgent() {
|
|
191
|
+
return new Promise((resolve) => {
|
|
192
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout })
|
|
193
|
+
rl.question('Agente/IDE [opencode/vscode/antigravity/cursor/roo] (default: opencode): ', (a) => {
|
|
194
|
+
rl.close()
|
|
195
|
+
const t = a.trim().toLowerCase()
|
|
196
|
+
resolve(SUPPORTED_AGENTS.includes(t) ? t : DEFAULT_AGENT)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function resolveAgent(args, existing) {
|
|
202
|
+
const ai = args.indexOf('--agent')
|
|
203
|
+
if (ai >= 0) {
|
|
204
|
+
const name = args[ai + 1]
|
|
205
|
+
if (!SUPPORTED_AGENTS.includes(name)) {
|
|
206
|
+
console.error(`ancleto: agente invalido: ${name} (${SUPPORTED_AGENTS.join('/')})`)
|
|
207
|
+
process.exit(1)
|
|
208
|
+
}
|
|
209
|
+
return name
|
|
210
|
+
}
|
|
211
|
+
if (existing && SUPPORTED_AGENTS.includes(existing)) return existing
|
|
212
|
+
if (process.stdin.isTTY) return askAgent()
|
|
213
|
+
return DEFAULT_AGENT
|
|
214
|
+
}
|
|
215
|
+
|
|
184
216
|
async function mergeMcp(configDir, mcpMap) {
|
|
185
217
|
if (Object.keys(mcpMap).length === 0) return { file: null, added: [] }
|
|
186
218
|
|
|
@@ -223,6 +255,34 @@ async function copyAssets(dest) {
|
|
|
223
255
|
}
|
|
224
256
|
}
|
|
225
257
|
|
|
258
|
+
const AGENT_SKILLS_DIR = {
|
|
259
|
+
opencode: '.opencode/skills',
|
|
260
|
+
vscode: '.vscode/skills',
|
|
261
|
+
antigravity: '.antigravity/skills',
|
|
262
|
+
cursor: '.cursor/skills',
|
|
263
|
+
roo: '.roo/skills'
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const OPENSPEC_PACK1 = ['openspec-new', 'openspec-propose', 'openspec-apply', 'openspec-verify', 'openspec-archive']
|
|
267
|
+
|
|
268
|
+
async function installAgentSkills(projectDir, agent) {
|
|
269
|
+
const dir = AGENT_SKILLS_DIR[agent] || AGENT_SKILLS_DIR.opencode
|
|
270
|
+
const dest = join(projectDir, dir)
|
|
271
|
+
await mkdir(dest, { recursive: true })
|
|
272
|
+
for (const name of OPENSPEC_PACK1) {
|
|
273
|
+
const src = join(ROOT, 'skills', name)
|
|
274
|
+
if (!(await exists(src))) {
|
|
275
|
+
console.warn(`ancleto: skill no encontrada en el paquete: ${name}`)
|
|
276
|
+
continue
|
|
277
|
+
}
|
|
278
|
+
await cp(src, join(dest, name), { recursive: true })
|
|
279
|
+
}
|
|
280
|
+
if (dir !== AGENT_SKILLS_DIR.opencode) {
|
|
281
|
+
await cp(join(ROOT, 'skills'), dest, { recursive: true })
|
|
282
|
+
}
|
|
283
|
+
return dir.replace(/\\/g, '/')
|
|
284
|
+
}
|
|
285
|
+
|
|
226
286
|
const DEFAULT_OPENSPEC_CONFIG = `# OpenSpec project configuration
|
|
227
287
|
# Generado por @ancleto/spec (G5) — editalo libremente, no se sobrescribe en reinstalaciones.
|
|
228
288
|
schema: spec-driven-development
|
|
@@ -289,7 +349,7 @@ async function install(args) {
|
|
|
289
349
|
const pi = args.indexOf('--project')
|
|
290
350
|
const project = pi >= 0 ? args[pi + 1] : null
|
|
291
351
|
const withMcp = !args.includes('--no-mcp')
|
|
292
|
-
|
|
352
|
+
let mcpMap = withMcp ? buildDefaultMcp() : {}
|
|
293
353
|
|
|
294
354
|
const ti = args.indexOf('--tier')
|
|
295
355
|
let tier = ti >= 0 ? args[ti + 1] : null
|
|
@@ -311,12 +371,16 @@ async function install(args) {
|
|
|
311
371
|
if (project) {
|
|
312
372
|
await copyTemplates(resolve(project))
|
|
313
373
|
await scaffoldOpenSpec(resolve(project))
|
|
374
|
+
const existingRc = await readAncletorc(resolve(project))
|
|
375
|
+
const agent = await resolveAgent(args, existingRc?.agent)
|
|
376
|
+
const agentSkillsDir = await installAgentSkills(resolve(project), agent)
|
|
314
377
|
await writeManifest(resolve(project), {
|
|
378
|
+
agent,
|
|
315
379
|
installedPaths: {
|
|
316
380
|
templates: ['AGENTS.md', 'PRODUCT.md'],
|
|
317
381
|
agents: ['.opencode/agents'],
|
|
318
382
|
commands: ['.opencode/commands'],
|
|
319
|
-
skills: [
|
|
383
|
+
skills: [agentSkillsDir]
|
|
320
384
|
}
|
|
321
385
|
})
|
|
322
386
|
} else {
|
|
@@ -332,6 +396,15 @@ async function install(args) {
|
|
|
332
396
|
await applyTier(join(target, 'agents'), tier)
|
|
333
397
|
await writeFile(tierStatePath(target), tier + '\n')
|
|
334
398
|
|
|
399
|
+
let azureMcp = false
|
|
400
|
+
if (project && withMcp) {
|
|
401
|
+
const rc = await readAncletorc(resolve(project))
|
|
402
|
+
if (rc?.azure?.enabled) {
|
|
403
|
+
mcpMap['azure-devops'] = { type: 'local', enabled: true, command: ['npx', '-y', '@davstack/mcp-azure-devops'] }
|
|
404
|
+
azureMcp = true
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
335
408
|
const res = await mergeMcp(target, mcpMap)
|
|
336
409
|
const loc = project
|
|
337
410
|
? `${resolve(project)} (.opencode/ + templates en la raiz)`
|
|
@@ -341,6 +414,7 @@ async function install(args) {
|
|
|
341
414
|
if (res.added.length) {
|
|
342
415
|
console.log(`ancleto: MCP configurados: ${res.added.join(', ')} en ${res.file}`)
|
|
343
416
|
}
|
|
417
|
+
if (azureMcp) console.log(AZURE_MCP_NOTICE)
|
|
344
418
|
}
|
|
345
419
|
|
|
346
420
|
async function initProject(args) {
|
|
@@ -350,9 +424,11 @@ async function initProject(args) {
|
|
|
350
424
|
const azure = existing?.azure ?? { enabled: false }
|
|
351
425
|
if (withAzure) azure.enabled = true
|
|
352
426
|
const discovery = existing?.discovery ?? { outputDir: 'docs/technical-discovery', exclude: [] }
|
|
353
|
-
const
|
|
427
|
+
const agent = await resolveAgent(args, existing?.agent)
|
|
428
|
+
const manifest = await writeManifest(projectDir, { azure, discovery, agent })
|
|
354
429
|
await scaffoldOpenSpec(projectDir)
|
|
355
|
-
|
|
430
|
+
if (azure.enabled) console.log(AZURE_MCP_NOTICE)
|
|
431
|
+
console.log(`ancleto: .ancletorc actualizado en ${projectDir} (v${manifest.version})${azure.enabled ? ' (Azure habilitado)' : ' (Azure desactivado)'} (Agente: ${agent})`)
|
|
356
432
|
}
|
|
357
433
|
|
|
358
434
|
const DEFAULT_IGNORES = ['node_modules', '.git', 'dist']
|