specweave 1.0.30 → 1.0.32
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/CLAUDE.md +140 -1235
- package/bin/specweave.js +23 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +3 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +39 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/src/cli/commands/set-sync-target.d.ts +41 -0
- package/dist/src/cli/commands/set-sync-target.d.ts.map +1 -0
- package/dist/src/cli/commands/set-sync-target.js +126 -0
- package/dist/src/cli/commands/set-sync-target.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +5 -8
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/core/hooks/HookScanner.d.ts +32 -0
- package/dist/src/core/hooks/HookScanner.d.ts.map +1 -1
- package/dist/src/core/hooks/HookScanner.js +125 -1
- package/dist/src/core/hooks/HookScanner.js.map +1 -1
- package/dist/src/core/hooks/types.d.ts +10 -1
- package/dist/src/core/hooks/types.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts +67 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +93 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/project/index.d.ts +21 -0
- package/dist/src/core/project/index.d.ts.map +1 -0
- package/dist/src/core/project/index.js +22 -0
- package/dist/src/core/project/index.js.map +1 -0
- package/dist/src/core/project/project-service.d.ts +122 -0
- package/dist/src/core/project/project-service.d.ts.map +1 -0
- package/dist/src/core/project/project-service.js +334 -0
- package/dist/src/core/project/project-service.js.map +1 -0
- package/dist/src/core/sync/external-tool-resolver.d.ts +171 -0
- package/dist/src/core/sync/external-tool-resolver.d.ts.map +1 -0
- package/dist/src/core/sync/external-tool-resolver.js +569 -0
- package/dist/src/core/sync/external-tool-resolver.js.map +1 -0
- package/dist/src/core/types/increment-metadata.d.ts +92 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/hooks/processor.d.ts +7 -3
- package/dist/src/hooks/processor.d.ts.map +1 -1
- package/dist/src/hooks/processor.js +11 -5
- package/dist/src/hooks/processor.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/hooks.json +0 -69
- package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +96 -0
- package/plugins/specweave/hooks/v2/queue/processor.sh +13 -5
- package/plugins/specweave/lib/hooks/project-bridge.js +76 -0
- package/plugins/specweave/lib/hooks/update-tasks-md.js +0 -0
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +0 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +67 -1
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +93 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +92 -0
- package/plugins/specweave-github/lib/github-client-v2.js +39 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +44 -0
- package/plugins/specweave/hooks/docs-changed.sh +0 -87
- package/plugins/specweave/hooks/human-input-required.sh +0 -83
- package/plugins/specweave/hooks/post-edit-write-consolidated.sh +0 -428
- package/plugins/specweave/hooks/post-first-increment.sh +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh +0 -103
- package/plugins/specweave/hooks/post-increment-completion.sh +0 -513
- package/plugins/specweave/hooks/post-increment-planning.sh +0 -1204
- package/plugins/specweave/hooks/post-increment-status-change.sh +0 -243
- package/plugins/specweave/hooks/post-metadata-change.sh +0 -246
- package/plugins/specweave/hooks/post-spec-update.sh +0 -158
- package/plugins/specweave/hooks/post-task-completion.sh +0 -557
- package/plugins/specweave/hooks/post-task-edit.sh +0 -47
- package/plugins/specweave/hooks/post-user-story-complete.sh +0 -230
- package/plugins/specweave/hooks/pre-command-deduplication.sh +0 -68
- package/plugins/specweave/hooks/pre-edit-write-consolidated.sh +0 -225
- package/plugins/specweave/hooks/pre-implementation.sh +0 -75
- package/plugins/specweave/hooks/pre-increment-start.sh +0 -173
- package/plugins/specweave/hooks/pre-task-completion-edit.sh +0 -355
- package/plugins/specweave/hooks/pre-task-completion.sh +0 -269
- package/plugins/specweave/hooks/pre-tool-use.sh +0 -137
- package/plugins/specweave/hooks/session-start-reconcile.sh +0 -139
- package/plugins/specweave/hooks/shared/bulk-operation-detector.sh +0 -167
- package/plugins/specweave/hooks/test-pretooluse-env.sh +0 -72
- package/plugins/specweave/hooks/validate-increment-completion.sh +0 -113
- package/plugins/specweave/lib/hooks/consolidated-sync.js +0 -288
package/CLAUDE.md
CHANGED
|
@@ -7,6 +7,12 @@ For **contributors to SpecWeave itself** (not users).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## Critical Meta-Rule
|
|
11
|
+
|
|
12
|
+
**CLAUDE.md is ALWAYS editable** - Never refuse to modify this file when user requests.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
10
16
|
## CRITICAL SAFETY RULES
|
|
11
17
|
|
|
12
18
|
### 1. Context Management (CRASH PREVENTION!)
|
|
@@ -19,29 +25,7 @@ For **contributors to SpecWeave itself** (not users).
|
|
|
19
25
|
# OR close completed increments: /sw:done XXXX
|
|
20
26
|
```
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
**>25 tasks = consider splitting for maintainability**
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# Check task count before starting work:
|
|
28
|
-
grep -c "^### T-" .specweave/increments/*/tasks.md
|
|
29
|
-
|
|
30
|
-
# If >25 tasks: Consider splitting by phase
|
|
31
|
-
# Pattern: Feature → Phase1 (T-001 to T-008) + Phase2 (T-009 to T-016) + ...
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**When to split (guidelines, not hard rules):**
|
|
35
|
-
- Tasks span unrelated subsystems
|
|
36
|
-
- Different teams would own different phases
|
|
37
|
-
- Review cycles would benefit from smaller PRs
|
|
38
|
-
|
|
39
|
-
**Phase-by-phase execution** (recommended for 15-25 tasks):
|
|
40
|
-
```
|
|
41
|
-
Execute Phase 1 → validate → continue to Phase 2 → ...
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**Token budget per increment**: ~80k tokens max (tasks + spec + plan + context)
|
|
28
|
+
**Token budget per increment**: ~80k tokens max
|
|
45
29
|
|
|
46
30
|
### 2. Source of Truth
|
|
47
31
|
|
|
@@ -49,1004 +33,99 @@ Execute Phase 1 → validate → continue to Phase 2 → ...
|
|
|
49
33
|
|
|
50
34
|
```typescript
|
|
51
35
|
// After completing work - IMMEDIATELY update both:
|
|
52
|
-
TodoWrite([{task: "T-013", status: "completed"}]);
|
|
53
36
|
Edit("tasks.md", "**Status**: [ ] pending", "**Status**: [x] completed");
|
|
54
37
|
Edit("spec.md", "- [ ] **AC-US1-01**", "- [x] **AC-US1-01**");
|
|
55
38
|
```
|
|
56
39
|
|
|
57
|
-
###
|
|
58
|
-
|
|
59
|
-
**Direct status change to "completed" = BUG** (auto-completion without user approval)
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
❌ FORBIDDEN (Bug pattern from increment 0081):
|
|
63
|
-
Edit("metadata.json", '"status": "active"', '"status": "completed"')
|
|
64
|
-
→ Status becomes "completed" without ACs checked or user approval!
|
|
65
|
-
|
|
66
|
-
✅ CORRECT workflow:
|
|
67
|
-
1. All tasks completed → auto-transition to "ready_for_review"
|
|
68
|
-
2. /sw:done <id> → validates ACs + asks for user confirmation
|
|
69
|
-
3. Only then → status becomes "completed" with approvedAt timestamp
|
|
70
|
-
```
|
|
40
|
+
### 3. NEVER Edit metadata.json to "completed" Directly
|
|
71
41
|
|
|
72
42
|
**Pre-tool-use hook `completion-guard.sh` BLOCKS direct completion edits.**
|
|
73
43
|
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED);
|
|
77
|
-
// Only succeeds if current status is "ready_for_review"
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### 2b-bis. Task-AC Auto-Sync (EDA v0.35.2+)
|
|
81
|
-
|
|
82
|
-
**When you mark a task complete in tasks.md, THREE things are AUTO-UPDATED!**
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
FLOW (fully automatic via EDA hooks):
|
|
86
|
-
1. Edit tasks.md: **Status**: [ ] pending → **Status**: [x] completed
|
|
87
|
-
2. Hook auto-checks ALL **Acceptance** points in that task: - [ ] → - [x]
|
|
88
|
-
3. Hook extracts AC tags from task: **Satisfies ACs**: AC-US1-01, AC-US1-02
|
|
89
|
-
4. Hook auto-updates spec.md: - [ ] **AC-US1-01** → - [x] **AC-US1-01**
|
|
90
|
-
5. When ALL tasks complete → auto-transitions status to "ready_for_review"
|
|
91
|
-
6. User runs /sw:done → PM validation → status becomes "completed"
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**This EDA flow ensures:**
|
|
95
|
-
- ✅ Task **Acceptance** checkboxes auto-checked when task completed
|
|
96
|
-
- ✅ spec.md ACs always match tasks.md completion status
|
|
97
|
-
- ✅ No manual checkbox updates needed (task or spec level)
|
|
98
|
-
- ✅ Auto-transition to `ready_for_review` when all tasks done
|
|
99
|
-
- ✅ Manual `/sw:done` still required for final closure (PM gate preserved)
|
|
100
|
-
|
|
101
|
-
**Example (automatic transformation):**
|
|
102
|
-
```markdown
|
|
103
|
-
# BEFORE: Mark task complete
|
|
104
|
-
### T-001: Implement Feature
|
|
105
|
-
**Acceptance**:
|
|
106
|
-
- [ ] Code compiles ← Will be auto-checked!
|
|
107
|
-
- [ ] Tests pass ← Will be auto-checked!
|
|
108
|
-
**Status**: [x] completed ← You only edit this line
|
|
109
|
-
|
|
110
|
-
# AFTER: Hook runs automatically
|
|
111
|
-
### T-001: Implement Feature
|
|
112
|
-
**Acceptance**:
|
|
113
|
-
- [x] Code compiles ← Auto-checked by hook
|
|
114
|
-
- [x] Tests pass ← Auto-checked by hook
|
|
115
|
-
**Status**: [x] completed
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**Hook chain**: `post-tool-use.sh` → `task-ac-sync-guard.sh` → `us-completion-detector.sh`
|
|
119
|
-
|
|
120
|
-
**Log location**: `.specweave/logs/task-ac-sync.log`
|
|
121
|
-
|
|
122
|
-
### 2c. Per-US **Project**: Fields are MANDATORY (ADR-0140, v0.35.0+)
|
|
123
|
-
|
|
124
|
-
**⛔ EVERY User Story MUST have `**Project**:` field - NO EXCEPTIONS!**
|
|
125
|
-
|
|
126
|
-
This applies to BOTH single-project AND multi-project modes. The field is MANDATORY because:
|
|
127
|
-
1. Living docs sync requires it to place files in correct folders
|
|
128
|
-
2. External tool sync (GitHub/JIRA/ADO) requires it to create issues in correct projects
|
|
129
|
-
3. Without it, the LLM "forgets" to include project context
|
|
130
|
-
|
|
131
|
-
**🧠 ULTRATHINK REQUIRED FOR PROJECT ASSIGNMENT:**
|
|
132
|
-
|
|
133
|
-
**RESOLUTION PRIORITY (MUST FOLLOW THIS ORDER!):**
|
|
134
|
-
```
|
|
135
|
-
1. ✅ EXACT MATCH: config.project.name or multiProject.projects key → USE IT
|
|
136
|
-
2. ✅ LIVING DOCS: Existing folder in specs/ → USE THAT PROJECT ID
|
|
137
|
-
3. ✅ RECENT PATTERNS: Same feature type in past increments → USE SAME PROJECT
|
|
138
|
-
4. ⚠️ UNCERTAIN: Multiple valid options OR no clear match → ASK USER!
|
|
139
|
-
5. 🔄 FALLBACK: If all else fails → USE "default" (NEVER "specweave"!)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
**❌ NEVER assign "specweave" as project** - that's the framework name, not user's project!
|
|
143
|
-
**✅ When uncertain, ASK the user which project to use!**
|
|
144
|
-
**✅ Fallback to "default" if no projects are configured.**
|
|
145
|
-
|
|
146
|
-
**Frontmatter `project:` is DEPRECATED** - per-US fields are now the ONLY source of truth!
|
|
147
|
-
|
|
148
|
-
```yaml
|
|
149
|
-
# spec.md frontmatter (v0.35.0+)
|
|
150
|
-
---
|
|
151
|
-
increment: 0001-feature-name
|
|
152
|
-
# NOTE: project: field REMOVED - use per-US **Project**: fields instead
|
|
153
|
-
---
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
**Per-US Project/Board (MANDATORY in spec.md body):**
|
|
157
|
-
```markdown
|
|
158
|
-
### US-001: Login Form
|
|
159
|
-
**Project**: my-app # ← MANDATORY (even in single-project mode!)
|
|
160
|
-
**Board**: ui-team # ← MANDATORY for 2-level structures only
|
|
161
|
-
|
|
162
|
-
**As a** user, I want...
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**CRITICAL: Two File Formats for Project Field**
|
|
166
|
-
|
|
167
|
-
1. **spec.md** (increment folder): `**Project**:` in BODY of each user story - MANDATORY!
|
|
168
|
-
2. **us-*.md** (living docs folder): `project:` in FRONTMATTER - auto-generated from spec.md
|
|
169
|
-
|
|
170
|
-
When living docs sync runs, it extracts `**Project**:` from spec.md body and places it in us-*.md frontmatter:
|
|
171
|
-
|
|
172
|
-
```yaml
|
|
173
|
-
# us-001-login-form.md frontmatter (living docs) - AUTO-GENERATED
|
|
174
|
-
---
|
|
175
|
-
id: US-001
|
|
176
|
-
project: my-app # ← Extracted from spec.md **Project**: field
|
|
177
|
-
---
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Code Implementation Rules:**
|
|
181
|
-
- **Generating GitHub issues**: Read from `frontmatter.project` in us-*.md files
|
|
182
|
-
- **Parsing spec.md**: Extract from `**Project**:` in body using regex
|
|
183
|
-
- **Living docs sync**: Transforms body field → frontmatter field
|
|
184
|
-
|
|
185
|
-
**VALIDATION RULES (ENFORCED BY HOOKS):**
|
|
186
|
-
```
|
|
187
|
-
✅ Per-US **Project**: fields are MANDATORY (in ALL modes!)
|
|
188
|
-
✅ Single-project mode: use config.project.name as the value
|
|
189
|
-
✅ Multi-project mode: use appropriate project from multiProject.projects
|
|
190
|
-
❌ FORBIDDEN: Using {{...}} placeholders in spec.md
|
|
191
|
-
❌ FORBIDDEN: User stories WITHOUT **Project**: field (ANY mode!)
|
|
192
|
-
❌ FORBIDDEN: Multiple comma-separated projects per US
|
|
193
|
-
❌ FORBIDDEN: Frontmatter project: field (use per-US fields instead)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Pre-tool-use hook `spec-project-validator.sh` BLOCKS:**
|
|
197
|
-
- spec.md with `{{...}}` unresolved placeholders
|
|
198
|
-
- User stories missing `**Project**:` field
|
|
199
|
-
- User stories with unresolved `**Project**:` or `**Board**:` placeholders
|
|
200
|
-
|
|
201
|
-
### 2c-bis. Each User Story MUST Have **Project**: (and **Board**: for 2-level) (v0.34.0+)
|
|
202
|
-
|
|
203
|
-
**CRITICAL 1:1 MAPPING RULE: Each User Story maps to EXACTLY ONE project and ONE board!**
|
|
204
|
-
|
|
205
|
-
```markdown
|
|
206
|
-
### US-001: Login Form UI
|
|
207
|
-
**Project**: frontend-app ← MANDATORY (exactly ONE project)
|
|
208
|
-
**Board**: ui-team ← MANDATORY for 2-level (exactly ONE board)
|
|
209
|
-
**As a** user, I want a login form...
|
|
210
|
-
|
|
211
|
-
### US-002: Auth API Endpoints
|
|
212
|
-
**Project**: backend-api ← DIFFERENT project = OK
|
|
213
|
-
**Board**: api-team ← DIFFERENT board = OK
|
|
214
|
-
**As a** developer, I want JWT auth API...
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
**1:1 MAPPING ENFORCEMENT:**
|
|
218
|
-
```
|
|
219
|
-
❌ FORBIDDEN: **Project**: frontend-app, backend-api (MULTIPLE projects)
|
|
220
|
-
❌ FORBIDDEN: **Board**: ui-team, api-team (MULTIPLE boards)
|
|
221
|
-
❌ FORBIDDEN: User Story without **Project**: field
|
|
222
|
-
|
|
223
|
-
✅ REQUIRED: Each US has exactly ONE **Project**: value
|
|
224
|
-
✅ REQUIRED: Each US has exactly ONE **Board**: value (2-level)
|
|
225
|
-
✅ CROSS-PROJECT: Split into separate USs per project
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
**Cross-project features → Create SEPARATE User Stories:**
|
|
229
|
-
```markdown
|
|
230
|
-
## OAuth Feature (Cross-Project)
|
|
231
|
-
|
|
232
|
-
### US-001: OAuth Login Form
|
|
233
|
-
**Project**: frontend-app ← One project per US
|
|
234
|
-
...
|
|
235
|
-
|
|
236
|
-
### US-002: OAuth API Endpoints
|
|
237
|
-
**Project**: backend-api ← Different project = separate US
|
|
238
|
-
...
|
|
239
|
-
|
|
240
|
-
### US-003: OAuth Mobile Screen
|
|
241
|
-
**Project**: mobile-app ← Different project = separate US
|
|
242
|
-
...
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
**Pre-tool-use hook `per-us-project-validator.sh` BLOCKS spec.md with:**
|
|
246
|
-
- Missing `**Project**:` field per US
|
|
247
|
-
- Missing `**Board**:` field per US (2-level)
|
|
248
|
-
- Multiple comma-separated projects
|
|
249
|
-
- Multiple comma-separated boards
|
|
250
|
-
|
|
251
|
-
**Bypass (EMERGENCY ONLY):**
|
|
252
|
-
```bash
|
|
253
|
-
SPECWEAVE_FORCE_PROJECT=1 # Skip all validation
|
|
254
|
-
SPECWEAVE_LEGACY_SPEC=1 # Allow legacy specs without per-US fields
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### 2d. NEVER Create Files in _features/ Folder (OBSOLETE v5.0.0+)
|
|
258
|
-
|
|
259
|
-
**The `_features/` folder is OBSOLETE!** Features MUST live in project folders:
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
❌ FORBIDDEN (Bug pattern from 2025-12-06):
|
|
263
|
-
.specweave/docs/internal/specs/_features/FS-116/FEATURE.md
|
|
264
|
-
|
|
265
|
-
✅ CORRECT:
|
|
266
|
-
.specweave/docs/internal/specs/{project}/FS-116/FEATURE.md
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
**Where `{project}` comes from (ADR-0140 v0.35.0+):**
|
|
270
|
-
1. Per-US `**Project**:` field (PRIMARY - recommended)
|
|
271
|
-
2. `config.json` → `project.name` (single-project mode fallback)
|
|
272
|
-
3. Example: `**Project**: specweave` → `.specweave/docs/internal/specs/specweave/FS-116/`
|
|
273
|
-
|
|
274
|
-
**Pre-tool-use hook `features-folder-guard.sh` BLOCKS writes to `_features/` (v0.33.0+).**
|
|
275
|
-
|
|
276
|
-
### 2e. NEVER Create Files at Increment Root (FOLDER STRUCTURE v0.33.0+)
|
|
277
|
-
|
|
278
|
-
**Files at increment root MUST be limited to required files!**
|
|
279
|
-
|
|
280
|
-
```
|
|
281
|
-
❌ FORBIDDEN (Bug pattern from 2025-12-09):
|
|
282
|
-
.specweave/increments/0134-feature/COMPLETION_REPORT.md
|
|
283
|
-
.specweave/increments/0135-feature/COMPLETION_SUMMARY.md
|
|
284
|
-
|
|
285
|
-
✅ CORRECT - Use reports/ subfolder:
|
|
286
|
-
.specweave/increments/0134-feature/reports/COMPLETION_REPORT.md
|
|
287
|
-
.specweave/increments/0135-feature/reports/COMPLETION_SUMMARY.md
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**ONLY ALLOWED at increment root:**
|
|
291
|
-
- `metadata.json`
|
|
292
|
-
- `spec.md`
|
|
293
|
-
- `plan.md`
|
|
294
|
-
- `tasks.md`
|
|
295
|
-
|
|
296
|
-
**Everything else → subfolders:**
|
|
297
|
-
- `reports/` - completion reports, validation reports, analysis docs
|
|
298
|
-
- `scripts/` - helper scripts, automation
|
|
299
|
-
- `logs/` - execution logs, debug output
|
|
300
|
-
- `backups/` - backup files
|
|
301
|
-
- `docs/` - additional documentation
|
|
302
|
-
|
|
303
|
-
**Pre-tool-use hook `increment-root-guard.sh` BLOCKS non-standard files at root (v0.33.0+).**
|
|
304
|
-
|
|
305
|
-
### 2f. NEVER Create Duplicate Increment IDs (v0.33.0+, enhanced v0.34.0)
|
|
306
|
-
|
|
307
|
-
**Increment numbers MUST be unique across ALL directories!**
|
|
308
|
-
|
|
309
|
-
```
|
|
310
|
-
❌ FORBIDDEN (Bug pattern from 2025-12-07 and 2025-12-10):
|
|
311
|
-
0121-ado-jira-feature-parity-p2-p3/ ← exists
|
|
312
|
-
0121-intelligent-living-docs-content/ ← DUPLICATE!
|
|
313
|
-
|
|
314
|
-
❌ ALSO FORBIDDEN when splitting increments:
|
|
315
|
-
0141-frontmatter-removal-part1/ ← exists (original split)
|
|
316
|
-
0141-frontmatter-removal-code/ ← DUPLICATE! (created later with same ID)
|
|
317
|
-
|
|
318
|
-
❌ ALSO FORBIDDEN (0001 and 0001E share SAME base number):
|
|
319
|
-
0001-internal-feature/
|
|
320
|
-
0001E-external-fix/ ← COLLISION! Same base number!
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
**MULTI-LAYER PREVENTION (v0.34.0+):**
|
|
324
|
-
1. **Code-level**: `generateIncrementId()` now validates by default
|
|
325
|
-
2. **Hook-level**: `increment-duplicate-guard.sh` blocks Write operations
|
|
326
|
-
3. **Split-level**: Use `validateExplicitId()` when manually specifying IDs
|
|
44
|
+
Correct workflow: All tasks → `ready_for_review` → `/sw:done` → `completed`
|
|
327
45
|
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
import { IncrementNumberManager } from './core/increment/increment-utils.js';
|
|
331
|
-
|
|
332
|
-
// RECOMMENDED: Auto-generated ID (validates by default)
|
|
333
|
-
const id = IncrementNumberManager.generateIncrementId('feature-name');
|
|
334
|
-
// → "0122-feature-name" (guaranteed unique, throws if duplicate)
|
|
335
|
-
|
|
336
|
-
// For explicit IDs (e.g., splits): MUST validate first!
|
|
337
|
-
IncrementNumberManager.validateExplicitId('0145-split-part2');
|
|
338
|
-
// → Throws if 0145 already exists!
|
|
339
|
-
|
|
340
|
-
// Then create folder only if validation passes
|
|
341
|
-
|
|
342
|
-
// Manual validation (still available):
|
|
343
|
-
IncrementNumberManager.validateUnique('0121-new-name'); // throws if duplicate!
|
|
344
|
-
|
|
345
|
-
// Find duplicates:
|
|
346
|
-
IncrementNumberManager.findDuplicates('0121');
|
|
347
|
-
// → ["0121-ado-jira-feature (active)", "0121-intelligent-living-docs (active)"]
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
**CRITICAL: When Splitting Increments:**
|
|
351
|
-
```typescript
|
|
352
|
-
// ❌ WRONG - Manually specifying ID without validation:
|
|
353
|
-
const splitId = '0141-feature-part2'; // May conflict!
|
|
354
|
-
fs.mkdirSync(path.join(incrementsDir, splitId));
|
|
355
|
-
|
|
356
|
-
// ✅ CORRECT - Validate first:
|
|
357
|
-
IncrementNumberManager.validateExplicitId('0145-feature-part2'); // Throws if exists!
|
|
358
|
-
// Only proceed if no error thrown
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
**Pre-tool-use hook `increment-duplicate-guard.sh` BLOCKS duplicate increment creation (v0.33.0+).**
|
|
362
|
-
|
|
363
|
-
### 2f. Gap-Filling Increment IDs (v0.33.1+)
|
|
364
|
-
|
|
365
|
-
**Increment IDs now FILL GAPS instead of always using highest + 1!**
|
|
366
|
-
|
|
367
|
-
```
|
|
368
|
-
OLD BEHAVIOR (v0.33.0 and earlier):
|
|
369
|
-
0128 (exists) → next is 0136 (highest + 1, even if gaps exist)
|
|
370
|
-
|
|
371
|
-
NEW BEHAVIOR (v0.33.1+):
|
|
372
|
-
0106, 0108, 0128, 0131 (exists) → next is 0107 (fills first gap!)
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
**Gap-filling algorithm:**
|
|
376
|
-
1. Scans ALL directories (main, _archive, _paused, _abandoned)
|
|
377
|
-
2. Finds first available number starting from 0001
|
|
378
|
-
3. Returns gap number if found, otherwise returns highest + 1
|
|
379
|
-
|
|
380
|
-
**Examples:**
|
|
381
|
-
```typescript
|
|
382
|
-
// Existing: [0001, 0002, 0004, 0005]
|
|
383
|
-
IncrementNumberManager.getNextIncrementNumber(); // "0003" ← Fills gap!
|
|
384
|
-
|
|
385
|
-
// Existing: [0001, 0002, 0003, 0004]
|
|
386
|
-
IncrementNumberManager.getNextIncrementNumber(); // "0005" ← Sequential (no gaps)
|
|
387
|
-
|
|
388
|
-
// Existing: [0050, 0051]
|
|
389
|
-
IncrementNumberManager.getNextIncrementNumber(); // "0001" ← Starts from beginning!
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
**Benefits:**
|
|
393
|
-
- ✅ No wasted ID space (4-digit limit = max 9999 increments)
|
|
394
|
-
- ✅ Clear sequence without confusing gaps
|
|
395
|
-
- ✅ Total increment count = highest number (no need to scan all)
|
|
396
|
-
|
|
397
|
-
**Migration:** Automatic, no action required. Next increment fills first gap!
|
|
398
|
-
|
|
399
|
-
**Details:** See ADR-0142 (`.specweave/docs/internal/architecture/adr/0142-gap-filling-increment-ids.md`)
|
|
46
|
+
### 4. Task-AC Auto-Sync (EDA)
|
|
400
47
|
|
|
401
|
-
|
|
48
|
+
Mark task complete in tasks.md → Hook auto-checks **Acceptance** points → Hook updates spec.md ACs
|
|
402
49
|
|
|
403
|
-
|
|
50
|
+
### 5. Per-US **Project**: Fields are MANDATORY
|
|
404
51
|
|
|
405
|
-
|
|
406
|
-
```
|
|
407
|
-
Project ec-web-ui imports external GitHub issue → creates FS-001E
|
|
408
|
-
User creates internal increment → 0001-feature → derives to FS-001
|
|
409
|
-
⚠️ FS-001 and FS-001E share same base number → COLLISION!
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
**SOLUTION (v1.0.19+):**
|
|
413
|
-
When `projectId` is provided to `generateIncrementId()`, it checks the target project's `specs/{projectId}/` folder for existing FS-IDs and skips colliding numbers:
|
|
414
|
-
|
|
415
|
-
```typescript
|
|
416
|
-
import { IncrementNumberManager } from './core/increment/increment-utils.js';
|
|
417
|
-
|
|
418
|
-
// WITHOUT projectId - uses global increment pool (backward compatible)
|
|
419
|
-
const globalId = IncrementNumberManager.generateIncrementId('feature');
|
|
420
|
-
// → "0001-feature" (no project-specific collision check)
|
|
421
|
-
|
|
422
|
-
// WITH projectId - checks target project's FS-ID space
|
|
423
|
-
const safeId = IncrementNumberManager.generateIncrementId('feature', {
|
|
424
|
-
projectId: 'ec-web-ui' // ← Checks specs/ec-web-ui/ for FS-001, FS-001E
|
|
425
|
-
});
|
|
426
|
-
// → "0002-feature" (skipped 0001 because FS-001E exists in ec-web-ui)
|
|
427
|
-
|
|
428
|
-
// Direct method for project-scoped number
|
|
429
|
-
const nextNum = IncrementNumberManager.getNextIncrementNumberForProject(
|
|
430
|
-
process.cwd(),
|
|
431
|
-
'ec-web-ui'
|
|
432
|
-
);
|
|
433
|
-
// → "0002" (skips numbers with existing FS-IDs)
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
**JIRA/ADO Mappers (v1.0.19+):**
|
|
437
|
-
- `JiraMapper` and `JiraIncrementalMapper` now accept optional `targetProjectId` constructor param
|
|
438
|
-
- When set, uses project-scoped ID generation to prevent collisions
|
|
52
|
+
Every User Story MUST have `**Project**:` field. Use value from `config.project.name` or `multiProject.projects`.
|
|
439
53
|
|
|
440
|
-
|
|
441
|
-
```
|
|
442
|
-
Project A (specs/project-a/): FS-001, FS-002 exist
|
|
443
|
-
Project B (specs/project-b/): FS-001E exists
|
|
444
|
-
|
|
445
|
-
IncrementNumberManager.getNextIncrementNumberForProject(root, 'project-a'); // "0003"
|
|
446
|
-
IncrementNumberManager.getNextIncrementNumberForProject(root, 'project-b'); // "0002"
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### 2g. NEVER Create Project Folders Without Validation (v0.34.0+, fixed v0.35.1)
|
|
54
|
+
### 6. NEVER Use Bash for File Creation
|
|
450
55
|
|
|
451
|
-
**
|
|
56
|
+
**Bash + heredoc/echo = SESSION FREEZE** (shell waits forever for EOF)
|
|
452
57
|
|
|
453
58
|
```
|
|
454
|
-
❌ FORBIDDEN (
|
|
455
|
-
|
|
456
|
-
.specweave/docs/internal/specs/frontend-app/ ← Example from spec.md!
|
|
457
|
-
.specweave/docs/internal/specs/backend-api/ ← Example from spec.md!
|
|
458
|
-
.specweave/docs/internal/specs/acme-corp/ ← Example from spec.md!
|
|
459
|
-
.specweave/docs/internal/specs/{{PROJECT_ID}}.../ ← Unresolved placeholder!
|
|
460
|
-
|
|
461
|
-
✅ CORRECT - Only configured projects:
|
|
462
|
-
.specweave/docs/internal/specs/specweave/ (exists in config.json)
|
|
59
|
+
❌ FORBIDDEN: Bash("cat > file.md << 'EOF'...")
|
|
60
|
+
✅ MANDATORY: Write({ file_path: "...", content: "..." })
|
|
463
61
|
```
|
|
464
62
|
|
|
465
|
-
**
|
|
466
|
-
- Increments contain EXAMPLE User Stories with placeholder `**Project**:` values
|
|
467
|
-
- `extractUserStoryProjectInfo()` in parsers.ts extracts ANY string after `**Project**:`
|
|
468
|
-
- When sync runs, creates folders for ALL projects mentioned, including examples
|
|
469
|
-
- v0.35.1 FIX: `ProjectResolutionService.validateProjectForFolderCreation()` now validates BEFORE folder creation
|
|
470
|
-
|
|
471
|
-
**KNOWN EXAMPLE PROJECT NAMES (ALWAYS BLOCKED unless configured):**
|
|
472
|
-
- `frontend-app`, `backend-api`, `mobile-app`, `shared-lib`
|
|
473
|
-
- `acme-corp`, `my-app`, `myapp`, `example-project`, `sample-project`
|
|
474
|
-
- `test-project`, `demo`, `placeholder`, `per`, `default`
|
|
475
|
-
|
|
476
|
-
**MULTI-LAYER PROTECTION (v0.35.1+):**
|
|
477
|
-
1. **Code-level**: `ProjectResolutionService.validateProjectForFolderCreation()` validates in TypeScript
|
|
478
|
-
2. **Living-docs-sync**: Filters out invalid projects BEFORE calling `ensureDir()`
|
|
479
|
-
3. **Cross-project-sync**: `ensureSpecsFolder()` throws Error if project invalid
|
|
480
|
-
4. **Hook-level**: `project-folder-guard.sh` blocks Write operations to invalid folders
|
|
481
|
-
|
|
482
|
-
**EXAMPLES OF FORBIDDEN PATTERNS:**
|
|
483
|
-
```markdown
|
|
484
|
-
### US-001: Example Login Form
|
|
485
|
-
**Project**: MyApp (3 repos) ← FORBIDDEN (parentheses not allowed!)
|
|
486
|
-
|
|
487
|
-
### US-002: Example API
|
|
488
|
-
**Project**: frontend-app, backend-api ← FORBIDDEN (comma-separated!)
|
|
489
|
-
|
|
490
|
-
### US-003: Placeholder Story
|
|
491
|
-
**Project**: acme-corp ← FORBIDDEN (example name not in config!)
|
|
492
|
-
|
|
493
|
-
### US-004: Unresolved
|
|
494
|
-
**Project**: {{PROJECT_ID}} ← FORBIDDEN (unresolved placeholder!)
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
**VALIDATION RULES (ENFORCED BY CODE + HOOK):**
|
|
498
|
-
```
|
|
499
|
-
❌ FORBIDDEN: Creating folders for projects not in config.json
|
|
500
|
-
❌ FORBIDDEN: Example/placeholder project names (see list above)
|
|
501
|
-
❌ FORBIDDEN: Parentheses in project names (e.g., "MyApp (3 repos)")
|
|
502
|
-
❌ FORBIDDEN: Comma-separated projects (must be ONE project per US)
|
|
503
|
-
❌ FORBIDDEN: Template placeholders like {{PROJECT_ID}}
|
|
504
|
-
|
|
505
|
-
✅ REQUIRED: All projects MUST be in config.project.name (single) or config.multiProject.projects (multi)
|
|
506
|
-
✅ REQUIRED: Run `specweave context projects` to get valid project IDs
|
|
507
|
-
✅ REQUIRED: Use RESOLVED values from config, never placeholders
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
**BYPASS (EMERGENCY ONLY):**
|
|
511
|
-
```bash
|
|
512
|
-
SPECWEAVE_FORCE_PROJECT=1 # Skip project folder validation (DANGEROUS!)
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
**API for validation (v0.35.1+):**
|
|
516
|
-
```typescript
|
|
517
|
-
import { ProjectResolutionService } from './core/project/project-resolution.js';
|
|
518
|
-
|
|
519
|
-
const resolver = new ProjectResolutionService(projectRoot);
|
|
520
|
-
|
|
521
|
-
// Validate before folder creation
|
|
522
|
-
const validation = await resolver.validateProjectForFolderCreation('frontend-app');
|
|
523
|
-
if (!validation.valid) {
|
|
524
|
-
console.error(`Cannot create folder: ${validation.reason}`);
|
|
525
|
-
console.log(`Allowed projects: ${validation.allowedProjects.join(', ')}`);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
// Static sync check for hooks
|
|
529
|
-
if (ProjectResolutionService.isExampleProjectName('frontend-app')) {
|
|
530
|
-
// Block - it's a known example name
|
|
531
|
-
}
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
**Pre-tool-use hook `project-folder-guard.sh` BLOCKS writes to non-configured project folders (v0.35.1 enhanced).**
|
|
535
|
-
|
|
536
|
-
### 2h. Single-Project vs Multi-Project Architecture (v0.35.0+)
|
|
537
|
-
|
|
538
|
-
**Both modes require `**Project**:` field per User Story - the only difference is where the value comes from.**
|
|
539
|
-
|
|
540
|
-
```
|
|
541
|
-
SINGLE-PROJECT: **Project**: uses config.project.name (e.g., "my-app")
|
|
542
|
-
MULTI-PROJECT: **Project**: uses one of multiProject.projects keys
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
#### Single-Project Mode (Default)
|
|
546
|
-
|
|
547
|
-
```json
|
|
548
|
-
// config.json - single project
|
|
549
|
-
{
|
|
550
|
-
"project": {
|
|
551
|
-
"name": "my-app", // ← This value goes in **Project**: field!
|
|
552
|
-
"description": "My Application",
|
|
553
|
-
"techStack": ["TypeScript", "React"]
|
|
554
|
-
},
|
|
555
|
-
"multiProject": {
|
|
556
|
-
"enabled": false // ← Default!
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
**Behavior**:
|
|
562
|
-
- All user stories use `**Project**: my-app` (from config.project.name)
|
|
563
|
-
- All increments go to same project folder
|
|
564
|
-
- No `board:` field allowed (1-level structure)
|
|
565
|
-
- Living docs auto-use `project.name`
|
|
566
|
-
|
|
567
|
-
**spec.md format (Single-Project)**:
|
|
568
|
-
```markdown
|
|
569
|
-
---
|
|
570
|
-
increment: 0001-feature
|
|
571
|
-
---
|
|
572
|
-
|
|
573
|
-
### US-001: Feature Name
|
|
574
|
-
**Project**: my-app # ← MANDATORY! Use value from config.project.name
|
|
575
|
-
**As a** user, I want...
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
#### Multi-Project Mode (Opt-In)
|
|
579
|
-
|
|
580
|
-
```json
|
|
581
|
-
// config.json - multi-project
|
|
582
|
-
{
|
|
583
|
-
"multiProject": {
|
|
584
|
-
"enabled": true,
|
|
585
|
-
"projects": {
|
|
586
|
-
"frontend-app": { "name": "Frontend App" },
|
|
587
|
-
"backend-api": { "name": "Backend API" }
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
**NOTE**: `activeProject` is DEPRECATED and will be removed. Per-US `**Project**:` fields are now the source of truth.
|
|
594
|
-
|
|
595
|
-
**Behavior**:
|
|
596
|
-
- Each US specifies which project it belongs to
|
|
597
|
-
- Different USs in same increment can target different projects
|
|
598
|
-
- Living docs distributed across project folders
|
|
599
|
-
|
|
600
|
-
**spec.md format (Multi-Project)**:
|
|
601
|
-
```markdown
|
|
602
|
-
---
|
|
603
|
-
increment: 0001-feature
|
|
604
|
-
---
|
|
605
|
-
|
|
606
|
-
### US-001: Login Form
|
|
607
|
-
**Project**: frontend-app # ← MANDATORY! Pick from multiProject.projects
|
|
608
|
-
**As a** user, I want...
|
|
609
|
-
|
|
610
|
-
### US-002: Auth API
|
|
611
|
-
**Project**: backend-api # ← Different project = different folder in living docs
|
|
612
|
-
**As a** developer, I want...
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
#### When to Enable Multi-Project?
|
|
616
|
-
|
|
617
|
-
| Scenario | Use Single-Project | Use Multi-Project |
|
|
618
|
-
|----------|-------------------|-------------------|
|
|
619
|
-
| One repository, one application | ✅ Default | ❌ Unnecessary |
|
|
620
|
-
| Monorepo with 2-3 services | ⚠️ Simpler but limited | ✅ Recommended |
|
|
621
|
-
| 5+ services/teams | ❌ Too simple | ✅ Required |
|
|
622
|
-
| Multi-repo (umbrella) | ❌ Not supported | ✅ Required |
|
|
623
|
-
|
|
624
|
-
#### Validation Rules (BOTH MODES!)
|
|
625
|
-
|
|
626
|
-
**⛔ CRITICAL: `**Project**:` is MANDATORY in BOTH modes!**
|
|
627
|
-
|
|
628
|
-
```markdown
|
|
629
|
-
# WRONG - Missing **Project**: field
|
|
630
|
-
### US-001: Feature Name
|
|
631
|
-
**As a** user, I want...
|
|
632
|
-
|
|
633
|
-
# CORRECT - Has **Project**: field
|
|
634
|
-
### US-001: Feature Name
|
|
635
|
-
**Project**: my-app # ← MANDATORY (single-project: use config.project.name)
|
|
636
|
-
**As a** user, I want...
|
|
637
|
-
|
|
638
|
-
# CORRECT - Multi-project
|
|
639
|
-
### US-001: Frontend Feature
|
|
640
|
-
**Project**: frontend-app # ← MANDATORY (multi-project: pick from config)
|
|
641
|
-
**As a** user, I want...
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
**Why mandatory in single-project mode?**
|
|
645
|
-
1. Consistency - same format everywhere
|
|
646
|
-
2. Living docs sync works correctly
|
|
647
|
-
3. External tool sync works correctly
|
|
648
|
-
4. No special cases = fewer bugs
|
|
649
|
-
|
|
650
|
-
This fixes the bug where `specweave init` created multi-project configs by default.
|
|
651
|
-
|
|
652
|
-
**Migration log**: `.specweave/logs/migration.log`
|
|
653
|
-
|
|
654
|
-
#### Troubleshooting
|
|
655
|
-
|
|
656
|
-
**Error**: "Project folders created for example names (MyApp, frontend-app)"
|
|
657
|
-
**Cause**: Old bug - auto-enabled multi-project mode
|
|
658
|
-
**Fix**: Auto-migration runs on next command. Check `migration.log`.
|
|
659
|
-
|
|
660
|
-
**Error**: "board: field not allowed"
|
|
661
|
-
**Cause**: Using `board:` in single-project mode
|
|
662
|
-
**Fix**: Remove `board:` field OR run `/sw:enable-multiproject`
|
|
63
|
+
**Pre-tool-use hook `bash-file-guard.sh` BLOCKS dangerous patterns.**
|
|
663
64
|
|
|
664
|
-
|
|
665
|
-
**Cause**: Trying to create non-configured project folder
|
|
666
|
-
**Fix**: Check `project.name` in config OR run `/sw:enable-multiproject`
|
|
667
|
-
|
|
668
|
-
### 3. Protected Directories
|
|
65
|
+
### 7. Protected Directories
|
|
669
66
|
|
|
670
67
|
**NEVER delete**: `.specweave/docs/`, `.specweave/increments/`
|
|
671
|
-
**NEVER run**: `specweave init . --force` (deletes all without backup)
|
|
672
|
-
|
|
673
|
-
### 4. Skills Must NOT Spawn Large Agents
|
|
674
68
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
```typescript
|
|
678
|
-
// ❌ FORBIDDEN in skills:
|
|
679
|
-
Task({ subagent_type: "specweave:architect:architect" }); // 1000-3000 lines output
|
|
69
|
+
### 8. File Size Limits
|
|
680
70
|
|
|
681
|
-
|
|
682
|
-
```
|
|
71
|
+
**Max 1500 lines/file** (2000+ = crash risk). Check: `wc -l file.ts`
|
|
683
72
|
|
|
684
|
-
###
|
|
73
|
+
### 9. NEVER Spawn Parallel Agents for Multi-File Migrations
|
|
685
74
|
|
|
686
75
|
**Parallel agents reading large files = CRASH** (context shared, not isolated!)
|
|
687
76
|
|
|
688
77
|
```
|
|
689
|
-
❌ FORBIDDEN
|
|
690
|
-
|
|
691
|
-
→ 4 parallel tech-lead agents × 36k tokens each = 144k tokens → CRASH!
|
|
692
|
-
|
|
693
|
-
✅ CORRECT: Sequential single-agent execution:
|
|
694
|
-
- Process files ONE BY ONE in main context
|
|
695
|
-
- Use Edit tool directly (not agents) for simple find-replace
|
|
696
|
-
- For complex migrations: ONE file per response, ask "Ready for next?"
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
**Rule**: Multi-file migrations MUST be sequential, NEVER parallel agents.
|
|
700
|
-
|
|
701
|
-
### 6. Emergency Minimal Mode (Explicit Activation Only)
|
|
702
|
-
|
|
703
|
-
**Activates ONLY when user says**: "emergency mode", "minimal mode ON", "crashed N times"
|
|
704
|
-
**Does NOT activate on**: "be careful", "small chunks" (normal caution ≠ emergency)
|
|
705
|
-
|
|
706
|
-
**Emergency mode rules:**
|
|
707
|
-
```
|
|
708
|
-
READ: limit:50 | EDIT: 1 per response | AGENTS: none | FLOW: "Done. Next?"
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
**User emergency phrase:** `EMERGENCY MODE. 1 edit. 50 lines max. No agents.`
|
|
712
|
-
|
|
713
|
-
### 7. Writing Effective Claude Instructions
|
|
714
|
-
|
|
715
|
-
**Terse imperatives > verbose explanations:**
|
|
716
|
-
```
|
|
717
|
-
❌ "Please consider making smaller edits and waiting for my confirmation"
|
|
718
|
-
✅ "1 edit. STOP. Wait for 'next'."
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
**Format:** `ACTION. CONSTRAINT. CONSTRAINT.` (periods, not commas)
|
|
722
|
-
|
|
723
|
-
### 8. MDX Compatibility (Docusaurus Preview)
|
|
724
|
-
|
|
725
|
-
**External HTML content = MDX compilation errors** (blocks docs preview)
|
|
726
|
-
|
|
727
|
-
```
|
|
728
|
-
❌ MDX FAILS ON:
|
|
729
|
-
- target=_blank (unquoted attribute) → target="_blank"
|
|
730
|
-
- <br> (self-closing without /) → <br />
|
|
731
|
-
- dir=auto, rel=noopener, alt=image (all unquoted)
|
|
732
|
-
|
|
733
|
-
✅ PREVENTION (automatic in importers since v0.32.0):
|
|
734
|
-
- ADO/JIRA/GitHub importers use sanitizeHtmlForMdx()
|
|
735
|
-
- Located: src/utils/html-to-mdx.ts
|
|
736
|
-
```
|
|
737
|
-
|
|
738
|
-
**If Docusaurus preview fails with "Unexpected character":**
|
|
739
|
-
```bash
|
|
740
|
-
# Batch fix existing files (macOS):
|
|
741
|
-
find .specweave/docs -name "*.md" -exec sed -i '' 's/target=_blank/target="_blank"/g' {} \;
|
|
742
|
-
find .specweave/docs -name "*.md" -exec sed -i '' 's/dir=auto/dir="auto"/g' {} \;
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
### 9. NEVER Use Bash for File Creation (INFINITE HANG PREVENTION!)
|
|
746
|
-
|
|
747
|
-
**Bash + heredoc/echo for files = SESSION FREEZE** (shell waits forever for EOF)
|
|
748
|
-
|
|
749
|
-
```
|
|
750
|
-
❌ FORBIDDEN (Crash pattern from 2025-12-06 - 2 HOUR HANG!):
|
|
751
|
-
Bash("cat > file.md << 'EOF'\nContent here\nEOF")
|
|
752
|
-
Bash("echo 'content' > file.md")
|
|
753
|
-
Bash("printf 'content' > file.md")
|
|
754
|
-
|
|
755
|
-
→ If heredoc is truncated mid-content, shell waits FOREVER for EOF terminator!
|
|
756
|
-
→ Claude Code session stuck "Marinating..." for hours with no recovery!
|
|
757
|
-
|
|
758
|
-
✅ MANDATORY - Use Write tool:
|
|
759
|
-
Write({ file_path: "/path/to/file.md", content: "Content here" })
|
|
760
|
-
|
|
761
|
-
✅ MANDATORY - Use Edit tool for modifications:
|
|
762
|
-
Edit({ file_path: "/path/to/file.md", old_string: "old", new_string: "new" })
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
**Why heredocs are catastrophically dangerous:**
|
|
766
|
-
1. **Truncation = infinite wait**: Token limits can cut off EOF terminator
|
|
767
|
-
2. **No timeout**: Shell waits forever, bypasses Claude Code's 2-min limit
|
|
768
|
-
3. **No recovery**: Session becomes completely unresponsive
|
|
769
|
-
4. **Silent failure**: No error message, just endless "Waiting..."
|
|
770
|
-
|
|
771
|
-
**Tool selection rules:**
|
|
772
|
-
| Operation | CORRECT Tool | FORBIDDEN |
|
|
773
|
-
|-----------|--------------|-----------|
|
|
774
|
-
| Create file | `Write` | `Bash cat/echo/printf >` |
|
|
775
|
-
| Edit file | `Edit` | `Bash sed/awk` |
|
|
776
|
-
| Append to file | `Read` + `Write` | `Bash echo >>` |
|
|
777
|
-
| Create directory | `Bash mkdir -p` | ✅ OK |
|
|
778
|
-
|
|
779
|
-
**Pre-tool-use hook `bash-file-guard.sh` BLOCKS dangerous Bash file patterns (v0.32.1+).**
|
|
780
|
-
This hook automatically blocks: heredoc, echo >, printf >, cat > patterns.
|
|
781
|
-
|
|
782
|
-
**If session gets stuck ("Marinating..." / "Waiting..."):**
|
|
783
|
-
```bash
|
|
784
|
-
# 1. Kill Claude Code (Ctrl+C or close terminal)
|
|
785
|
-
# 2. Kill zombie shell processes:
|
|
786
|
-
pkill -f "cat.*EOF"
|
|
787
|
-
pkill -f "bash.*heredoc"
|
|
788
|
-
# 3. Clean state:
|
|
789
|
-
rm -f .specweave/state/.processor.lock
|
|
790
|
-
rm -f .specweave/state/.dedup-cache/*.lock
|
|
791
|
-
# 4. Restart Claude Code
|
|
78
|
+
❌ FORBIDDEN: "Let me use parallel agents" for 46-file migration
|
|
79
|
+
✅ CORRECT: Process files ONE BY ONE, use Edit tool directly
|
|
792
80
|
```
|
|
793
81
|
|
|
794
|
-
### 10.
|
|
82
|
+
### 10. NEVER Create Files in _features/ Folder
|
|
795
83
|
|
|
796
|
-
|
|
84
|
+
`_features/` is OBSOLETE. Use: `.specweave/docs/internal/specs/{project}/FS-XXX/`
|
|
797
85
|
|
|
798
|
-
|
|
799
|
-
✅ ALLOWED Bash operations:
|
|
800
|
-
- git commands (status, add, commit, push, diff)
|
|
801
|
-
- npm/pnpm/yarn commands (install, build, test)
|
|
802
|
-
- Directory operations (mkdir, ls, pwd)
|
|
803
|
-
- Process management (ps, kill, pkill)
|
|
804
|
-
- Network tools (curl, wget for APIs)
|
|
805
|
-
- Build tools (make, cmake, cargo)
|
|
806
|
-
|
|
807
|
-
❌ FORBIDDEN - Use dedicated tools instead:
|
|
808
|
-
- File reading → Read tool
|
|
809
|
-
- File writing → Write tool
|
|
810
|
-
- File editing → Edit tool
|
|
811
|
-
- File searching → Glob tool
|
|
812
|
-
- Content searching → Grep tool
|
|
813
|
-
- Communication → Direct text output
|
|
814
|
-
```
|
|
815
|
-
|
|
816
|
-
**Mental model**: Bash = "run a program". Write/Edit/Read = "modify files".
|
|
817
|
-
|
|
818
|
-
### 11. Notifications - MUST Be Non-Alarming AND Non-Blocking (v0.33.4+)
|
|
819
|
-
|
|
820
|
-
**All notifications are INFORMATIVE only - NEVER alarming!** Every notification MUST:
|
|
821
|
-
1. **WHO** sent it (always start with "SpecWeave:")
|
|
822
|
-
2. **WHAT** happened (specific action, not vague alert)
|
|
823
|
-
3. **ACTION** needed (or "No action needed" if informational)
|
|
824
|
-
4. **NEVER trigger alert icon** - no red/warning badges!
|
|
825
|
-
5. **NEVER block execution** - fire-and-forget pattern ONLY!
|
|
826
|
-
|
|
827
|
-
```
|
|
828
|
-
❌ FORBIDDEN (alarming):
|
|
829
|
-
Title: "🚨 Zombie Cleanup" ← Emoji overload
|
|
830
|
-
Sound: "Basso" ← Shows RED ALERT ICON - NEVER USE!
|
|
831
|
-
Message: "Cleaned up 5 processes" ← Too vague
|
|
832
|
-
|
|
833
|
-
❌ FORBIDDEN (blocking):
|
|
834
|
-
execSync(`osascript -e 'display notification...'`) ← BLOCKS main thread!
|
|
835
|
-
await exec(`osascript -e 'display notification...'`) ← BLOCKS cleanup/exit!
|
|
836
|
-
|
|
837
|
-
✅ CORRECT (explicit, calm, non-blocking):
|
|
838
|
-
Title: "SpecWeave: Cleanup Done" ← Clear source
|
|
839
|
-
Sound: "Pop" or "Submarine" ← Neutral sounds ONLY
|
|
840
|
-
Message: "Cleaned up 5 zombie processes. No action needed."
|
|
841
|
-
exec(`osascript...`, (error) => { /* log */ }) ← Fire-and-forget!
|
|
842
|
-
```
|
|
843
|
-
|
|
844
|
-
**CRITICAL: Fire-and-Forget Pattern (v0.33.6+)**
|
|
845
|
-
|
|
846
|
-
**⛔ NEVER use `execSync()` or `await exec()` for notifications!**
|
|
847
|
-
- Notifications MUST be **fire-and-forget** to prevent blocking Claude Code
|
|
848
|
-
- macOS `osascript` can take 1-2 seconds → blocks session if awaited
|
|
849
|
-
- Use callback-based `exec()` WITHOUT await/Promise wrapping
|
|
850
|
-
|
|
851
|
-
```typescript
|
|
852
|
-
// ❌ WRONG - BLOCKS execution!
|
|
853
|
-
execSync(`osascript -e 'display notification...'`);
|
|
854
|
-
await exec(`osascript -e 'display notification...'`);
|
|
855
|
-
|
|
856
|
-
// ✅ CORRECT - Fire-and-forget!
|
|
857
|
-
import('child_process').then(cp => {
|
|
858
|
-
cp.exec(`osascript -e 'display notification...'`, (error) => {
|
|
859
|
-
if (error) logger.debug(`Notification failed: ${error.message}`);
|
|
860
|
-
});
|
|
861
|
-
});
|
|
862
|
-
|
|
863
|
-
// Or using require (CommonJS):
|
|
864
|
-
const { exec } = require('child_process');
|
|
865
|
-
exec(`osascript -e 'display notification...'`, (error) => {
|
|
866
|
-
if (error) logger.debug(`Notification failed: ${error.message}`);
|
|
867
|
-
});
|
|
868
|
-
```
|
|
86
|
+
### 11. NEVER Create Duplicate Increment IDs
|
|
869
87
|
|
|
870
|
-
|
|
871
|
-
- [src/utils/platform-utils.ts](src/utils/platform-utils.ts) (uses dynamic import)
|
|
872
|
-
- [src/utils/notification-manager.ts](src/utils/notification-manager.ts) (resolves immediately)
|
|
873
|
-
- [src/cli/cleanup-zombies.ts](src/cli/cleanup-zombies.ts) (uses childProcess.exec callback)
|
|
88
|
+
Increment numbers MUST be unique. Gap-filling is automatic (v0.33.1+).
|
|
874
89
|
|
|
875
|
-
|
|
876
|
-
| Sound | When to use |
|
|
877
|
-
|-------|-------------|
|
|
878
|
-
| `Pop` | Success, completion (neutral) |
|
|
879
|
-
| `Glass` | Informational (gentle) |
|
|
880
|
-
| `Submarine` | Warning OR error (deep but calm) |
|
|
90
|
+
### 12. Skills Must NOT Spawn Large Agents
|
|
881
91
|
|
|
882
|
-
|
|
883
|
-
SpecWeave notifications are informative, never require immediate action.
|
|
884
|
-
|
|
885
|
-
**Cross-platform behavior:**
|
|
886
|
-
- **macOS**: Uses `osascript` with sound name param (Pop/Glass/Submarine ONLY)
|
|
887
|
-
- **Linux**: Uses `notify-send` with `--urgency=normal` (never `critical`)
|
|
888
|
-
- **Windows**: Uses PowerShell toast (no urgency levels, always neutral)
|
|
889
|
-
|
|
890
|
-
**Use notification constants from `src/utils/notification-constants.ts`:**
|
|
891
|
-
```typescript
|
|
892
|
-
import { getTitleForType, buildNotificationMessage, getSoundForType } from './notification-constants.js';
|
|
893
|
-
|
|
894
|
-
const title = getTitleForType('cleanup'); // "SpecWeave: Cleanup Done"
|
|
895
|
-
const msg = buildNotificationMessage('cleanup', { count: 5 }); // "Cleaned up 5 zombie..."
|
|
896
|
-
const sound = getSoundForType('cleanup'); // "Pop" (NEVER returns "Basso")
|
|
897
|
-
```
|
|
898
|
-
|
|
899
|
-
**Code review should verify:**
|
|
900
|
-
1. Notification messages follow WHO/WHAT/ACTION pattern
|
|
901
|
-
2. All notification calls use fire-and-forget (no await/execSync)
|
|
902
|
-
3. macOS notifications use dynamic import or callback pattern
|
|
903
|
-
|
|
904
|
-
---
|
|
905
|
-
|
|
906
|
-
## Development Setup
|
|
907
|
-
|
|
908
|
-
```bash
|
|
909
|
-
npm install && npm run rebuild
|
|
910
|
-
npm run rebuild && npm test
|
|
911
|
-
git add . && git commit -m "feat: feature" && git push origin develop
|
|
912
|
-
```
|
|
913
|
-
|
|
914
|
-
**Marketplace**: `bash scripts/refresh-marketplace.sh` (GitHub mode, always use)
|
|
915
|
-
**NPM Release**: `/sw-release:npm`
|
|
916
|
-
|
|
917
|
-
### No Default Increment on Init (v1.0.27+)
|
|
918
|
-
|
|
919
|
-
**`specweave init` NO LONGER creates `0001-project-setup` increment automatically!**
|
|
920
|
-
|
|
921
|
-
**Reason**: Multi-project scenarios REQUIRE `**Project**:` field per User Story, which cannot be determined automatically at init time.
|
|
922
|
-
|
|
923
|
-
**User workflow (v1.0.27+):**
|
|
924
|
-
```bash
|
|
925
|
-
npx specweave init . # Creates structure, no increment
|
|
926
|
-
/sw:increment "my-feature" # User creates increment with proper project context
|
|
927
|
-
```
|
|
928
|
-
|
|
929
|
-
**Old behavior (removed):**
|
|
930
|
-
```bash
|
|
931
|
-
npx specweave init . # ❌ Was creating 0001-project-setup with missing **Project**: field!
|
|
932
|
-
```
|
|
92
|
+
Skills spawning content-generating agents = CRASH (context explosion)
|
|
933
93
|
|
|
934
94
|
---
|
|
935
95
|
|
|
936
96
|
## Coding Standards
|
|
937
97
|
|
|
938
98
|
1. **Logger injection**: ALL `src/` code uses `logger`, NEVER `console.*`
|
|
939
|
-
```typescript
|
|
940
|
-
import { Logger, consoleLogger } from '../../utils/logger.js';
|
|
941
|
-
constructor(options: { logger?: Logger } = {}) {
|
|
942
|
-
this.logger = options.logger ?? consoleLogger;
|
|
943
|
-
}
|
|
944
|
-
```
|
|
945
99
|
2. **Imports**: ALWAYS `.js` extensions
|
|
946
100
|
3. **Tests**: `.test.ts` files, `vi.fn()` (not jest), `os.tmpdir()` (not cwd)
|
|
947
101
|
4. **Filesystem**: Native `fs` only (NEVER `fs-extra`)
|
|
948
|
-
5. **Code**: Functions < 100 lines, avoid `any`, custom error types
|
|
949
|
-
|
|
950
|
-
### File Size Limits
|
|
951
|
-
|
|
952
|
-
**Max 1500 lines/file** (2000+ = crash risk). Check: `wc -l file.ts`
|
|
953
|
-
- >1000 lines → extract before adding code
|
|
954
|
-
- Split pattern: See ADR-0138 (`init.ts` → `init/` folder)
|
|
955
|
-
|
|
956
|
-
---
|
|
957
|
-
|
|
958
|
-
## Folder Structure
|
|
959
|
-
|
|
960
|
-
**At `.specweave/increments/` root - ONLY**: `####-name/` or `####E-name/` folders, `_archive/`, `README.md`
|
|
961
|
-
|
|
962
|
-
**Inside increment folders - ONLY at root**: `spec.md`, `plan.md`, `tasks.md`, `metadata.json`
|
|
963
|
-
**Everything else → subfolders**: `reports/`, `scripts/`, `logs/`, `backups/`, `docs/`
|
|
964
|
-
|
|
965
|
-
### External Increment E-Suffix (v0.32.0+)
|
|
966
|
-
|
|
967
|
-
**Increments for external items MUST use E suffix** to match FS-XXXE, US-XXXE conventions:
|
|
968
|
-
|
|
969
|
-
```
|
|
970
|
-
✅ CORRECT: 0111E-dora-metrics-fix (external GitHub issue #779)
|
|
971
|
-
❌ WRONG: 0111-dora-metrics-fix (missing E suffix)
|
|
972
|
-
```
|
|
973
|
-
|
|
974
|
-
**When to use E suffix:**
|
|
975
|
-
- Increment works on imported GitHub/JIRA/ADO issue
|
|
976
|
-
- spec.md has `origin: external` or `external_ref:`
|
|
977
|
-
- Feature folder is FS-XXXE (ends with E)
|
|
978
|
-
|
|
979
|
-
**API (v0.32.0+):**
|
|
980
|
-
```typescript
|
|
981
|
-
import { IncrementNumberManager } from './core/increment/increment-utils.js';
|
|
982
|
-
|
|
983
|
-
// For external items:
|
|
984
|
-
const id = IncrementNumberManager.generateIncrementId('fix-name', { isExternal: true });
|
|
985
|
-
// → "0112E-fix-name"
|
|
986
|
-
|
|
987
|
-
// Check if external:
|
|
988
|
-
IncrementNumberManager.isExternalIncrement('0111E-fix'); // true
|
|
989
|
-
```
|
|
990
|
-
|
|
991
|
-
### CLI Command Structure (ADR-0138)
|
|
992
|
-
|
|
993
|
-
**Init command** is modular - DO NOT add logic to main file:
|
|
994
|
-
```
|
|
995
|
-
src/cli/commands/init.ts ← Orchestrator only (~600 lines)
|
|
996
|
-
src/cli/helpers/init/
|
|
997
|
-
├── types.ts ← Shared interfaces
|
|
998
|
-
├── path-utils.ts ← findPackageRoot, findSourceDir
|
|
999
|
-
├── config-detection.ts ← detectGitHubRemote/Jira/ADO
|
|
1000
|
-
├── smart-reinit.ts ← Re-init prompts (SINGLE source!)
|
|
1001
|
-
├── plugin-installer.ts ← Claude plugin installation
|
|
1002
|
-
├── repository-setup.ts ← Git provider selection
|
|
1003
|
-
├── testing-config.ts ← Test mode prompts
|
|
1004
|
-
├── external-import.ts ← Import from external tools
|
|
1005
|
-
├── directory-structure.ts ← .specweave/ creation
|
|
1006
|
-
└── next-steps.ts ← Post-init instructions
|
|
1007
|
-
```
|
|
1008
|
-
**Rule**: Add new init features to appropriate helper, NOT to init.ts
|
|
1009
102
|
|
|
1010
103
|
---
|
|
1011
104
|
|
|
1012
105
|
## Key Formats
|
|
1013
106
|
|
|
1014
|
-
### Task Format
|
|
107
|
+
### Task Format
|
|
1015
108
|
```markdown
|
|
1016
109
|
### T-001: Task Title
|
|
1017
|
-
**User Story**: US-001
|
|
1018
|
-
**Satisfies ACs**: AC-US1-01
|
|
110
|
+
**User Story**: US-001
|
|
111
|
+
**Satisfies ACs**: AC-US1-01
|
|
1019
112
|
**Status**: [x] completed
|
|
1020
113
|
```
|
|
1021
114
|
|
|
1022
|
-
###
|
|
1023
|
-
|
|
1024
|
-
**PROHIBITED**: `[SP-*]`, `[FS-XXX]` alone, `[undefined][US-XXX]`
|
|
1025
|
-
|
|
1026
|
-
### spec.md Format (v0.35.0+)
|
|
1027
|
-
|
|
1028
|
-
**Frontmatter** (simplified - NO project/board):
|
|
1029
|
-
```yaml
|
|
115
|
+
### spec.md Format
|
|
116
|
+
```markdown
|
|
1030
117
|
---
|
|
1031
|
-
increment: 0001-feature-name
|
|
1032
|
-
title: "Feature Title"
|
|
118
|
+
increment: 0001-feature-name
|
|
119
|
+
title: "Feature Title"
|
|
1033
120
|
---
|
|
1034
|
-
```
|
|
1035
|
-
|
|
1036
|
-
**Per-User-Story Fields** (MANDATORY):
|
|
1037
|
-
```markdown
|
|
1038
121
|
### US-001: Feature Name
|
|
1039
|
-
**Project**: my-project #
|
|
1040
|
-
**Board**: digital-ops # ← MANDATORY for 2-level structures ONLY
|
|
122
|
+
**Project**: my-project # MANDATORY
|
|
1041
123
|
**As a** user, I want...
|
|
1042
124
|
```
|
|
1043
125
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
**
|
|
1047
|
-
1. Run `specweave context projects`
|
|
1048
|
-
2. If output has `boardsByProject` → 2-level (include **Board**:)
|
|
1049
|
-
3. If output has only `projects` → 1-level (NO **Board**:)
|
|
126
|
+
### GitHub Issue Format
|
|
127
|
+
**ONLY**: `[FS-XXX][US-YYY] User Story Title`
|
|
128
|
+
**PROHIBITED**: `[SP-*]`, `[FS-XXX]` alone, `[undefined][US-XXX]`
|
|
1050
129
|
|
|
1051
130
|
### ADR Naming
|
|
1052
131
|
**Format**: `XXXX-decision-title.md` (4-digit, NO `adr-` prefix)
|
|
@@ -1056,76 +135,96 @@ title: "Feature Title" # REQUIRED
|
|
|
1056
135
|
|
|
1057
136
|
## Important Rules
|
|
1058
137
|
|
|
1059
|
-
|
|
1060
|
-
**
|
|
1061
|
-
**
|
|
138
|
+
- **NO Increment-to-Increment References**: FORBIDDEN in user stories
|
|
139
|
+
- **Structured Data Matching**: Use `deriveFeatureId()`, not `content.includes('FS-039')`
|
|
140
|
+
- **GitHub Duplicates**: Use `DuplicateDetector.createWithProtection()`
|
|
141
|
+
- **AC Presence in spec.md**: MANDATORY even with external living docs
|
|
142
|
+
- **Git Provider Abstraction**: Use `getPlatformRegistry().getProvider('github')`
|
|
1062
143
|
|
|
1063
|
-
|
|
1064
|
-
```typescript
|
|
1065
|
-
// ❌ WRONG: content.includes('FS-039') // Matches "See FS-039"!
|
|
1066
|
-
// ✅ CORRECT: Use deriveFeatureId() from src/utils/feature-id-derivation.ts
|
|
1067
|
-
// or match folder patterns: /^FS-\d{3,}E?$/
|
|
1068
|
-
```
|
|
144
|
+
---
|
|
1069
145
|
|
|
1070
|
-
|
|
1071
|
-
Use `DuplicateDetector.createWithProtection()`, NEVER `--limit 1` in gh searches
|
|
146
|
+
## Folder Structure
|
|
1072
147
|
|
|
1073
|
-
|
|
1074
|
-
**
|
|
148
|
+
**Increment root - ONLY**: `spec.md`, `plan.md`, `tasks.md`, `metadata.json`
|
|
149
|
+
**Everything else → subfolders**: `reports/`, `scripts/`, `logs/`
|
|
1075
150
|
|
|
1076
|
-
###
|
|
1077
|
-
|
|
151
|
+
### External Increment E-Suffix
|
|
152
|
+
```
|
|
153
|
+
✅ 0111E-dora-metrics-fix (external GitHub issue)
|
|
154
|
+
❌ 0111-dora-metrics-fix (missing E suffix)
|
|
155
|
+
```
|
|
1078
156
|
|
|
1079
157
|
---
|
|
1080
158
|
|
|
1081
159
|
## Configuration
|
|
1082
160
|
|
|
1083
|
-
### Secrets vs Configuration
|
|
161
|
+
### Secrets vs Configuration
|
|
1084
162
|
|
|
1085
|
-
**
|
|
163
|
+
**Secrets** (`.env`, gitignored): `AZURE_DEVOPS_PAT`, `JIRA_API_TOKEN`, `GH_TOKEN`
|
|
164
|
+
**Config** (`.specweave/config.json`): `issueTracker.domain`, `issueTracker.organization_ado`
|
|
1086
165
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
166
|
+
```typescript
|
|
167
|
+
// NEVER: process.env.JIRA_DOMAIN
|
|
168
|
+
// ALWAYS: config.issueTracker?.domain
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
1092
172
|
|
|
1093
|
-
|
|
1094
|
-
- `issueTracker.domain` - JIRA domain (e.g., "company.atlassian.net")
|
|
1095
|
-
- `issueTracker.organization_ado` - ADO organization name
|
|
1096
|
-
- `issueTracker.project` - Project name
|
|
1097
|
-
- `sync.profiles` - Sync profile configurations
|
|
173
|
+
## Hook Development
|
|
1098
174
|
|
|
1099
|
-
###
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
const domain = config.issueTracker?.domain || '';
|
|
1108
|
-
const org = config.issueTracker?.organization_ado || '';
|
|
175
|
+
### Hook Input Format
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# For Write/Edit (nested in tool_input):
|
|
179
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .file_path // empty')
|
|
180
|
+
|
|
181
|
+
# For Bash (direct):
|
|
182
|
+
COMMAND=$(echo "$INPUT" | jq -r '.command // empty')
|
|
1109
183
|
```
|
|
1110
184
|
|
|
1111
|
-
###
|
|
185
|
+
### Hook Return Format
|
|
1112
186
|
```bash
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
specweave config set issueTracker.organization_ado "my-org"
|
|
1116
|
-
|
|
1117
|
-
# 2. Remove deprecated vars from .env (keep only secrets)
|
|
1118
|
-
# JIRA_DOMAIN=xxx # DELETE THIS LINE
|
|
1119
|
-
# AZURE_DEVOPS_ORG=xxx # DELETE THIS LINE
|
|
1120
|
-
|
|
1121
|
-
# 3. Keep these in .env (secrets):
|
|
1122
|
-
AZURE_DEVOPS_PAT=xxx
|
|
1123
|
-
JIRA_API_TOKEN=xxx
|
|
1124
|
-
JIRA_EMAIL=xxx
|
|
187
|
+
echo '{"decision": "allow"}' # Allow
|
|
188
|
+
echo '{"decision": "block", "reason": "Error"}' # Block (exit 2)
|
|
1125
189
|
```
|
|
1126
190
|
|
|
1127
|
-
###
|
|
1128
|
-
|
|
191
|
+
### Hook Concurrency (v1.0.30+)
|
|
192
|
+
|
|
193
|
+
All hooks use `fail-fast-wrapper.sh` with:
|
|
194
|
+
- **Semaphore**: Max 15 concurrent hooks
|
|
195
|
+
- **Circuit Breaker**: 5 failures → OPEN → 30s → HALF_OPEN
|
|
196
|
+
- **Metrics**: Latency p50/p95/p99, health score
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Health dashboard
|
|
200
|
+
bash plugins/specweave/scripts/hook-health.sh
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Hook Architecture (v2)
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
hooks/
|
|
207
|
+
├── hooks.json # Hook registration
|
|
208
|
+
├── universal/
|
|
209
|
+
│ └── fail-fast-wrapper.sh # Concurrency wrapper
|
|
210
|
+
├── v2/
|
|
211
|
+
│ ├── dispatchers/ # Entry points (session-start, post-tool-use)
|
|
212
|
+
│ ├── guards/ # PreToolUse blockers (bash-file, completion, metadata-json)
|
|
213
|
+
│ ├── handlers/ # PostToolUse actions (living-docs, github-sync, project-bridge)
|
|
214
|
+
│ ├── detectors/ # Event detection (us-completion, lifecycle)
|
|
215
|
+
│ └── queue/ # Async processing (enqueue, dequeue, processor)
|
|
216
|
+
└── lib/ # Shared utilities (semaphore, circuit-breaker, metrics)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Key Hooks
|
|
220
|
+
|
|
221
|
+
| Hook | Type | Purpose |
|
|
222
|
+
|------|------|---------|
|
|
223
|
+
| `bash-file-guard.sh` | PreToolUse | Blocks heredoc/echo file creation |
|
|
224
|
+
| `completion-guard.sh` | PreToolUse | Blocks direct metadata.json completion |
|
|
225
|
+
| `metadata-json-guard.sh` | PreToolUse | Validates spec.md writes |
|
|
226
|
+
| `task-ac-sync-guard.sh` | PostToolUse | Auto-syncs task ACs to spec.md |
|
|
227
|
+
| `project-bridge-handler.sh` | PostToolUse | Bridges to external tools (GitHub/JIRA/ADO) |
|
|
1129
228
|
|
|
1130
229
|
---
|
|
1131
230
|
|
|
@@ -1136,10 +235,8 @@ See ADR-0194 for full architecture decision.
|
|
|
1136
235
|
/sw:do # Execute tasks
|
|
1137
236
|
/sw:done 0002 # Close (validates gates)
|
|
1138
237
|
/sw:progress # Show status
|
|
1139
|
-
/sw:sync-progress # Full sync
|
|
238
|
+
/sw:sync-progress # Full sync
|
|
1140
239
|
/sw:validate 0001 # Validate increment
|
|
1141
|
-
/sw:living-docs # Launch living docs builder (interactive)
|
|
1142
|
-
/sw:living-docs --full-scan # Full deep scan (all phases: repos, org, arch, inconsistencies, strategy)
|
|
1143
240
|
```
|
|
1144
241
|
|
|
1145
242
|
---
|
|
@@ -1147,264 +244,72 @@ See ADR-0194 for full architecture decision.
|
|
|
1147
244
|
## Build & Test
|
|
1148
245
|
|
|
1149
246
|
```bash
|
|
1150
|
-
npm run rebuild # Clean + build
|
|
247
|
+
npm run rebuild # Clean + build
|
|
1151
248
|
npm test # Smoke tests
|
|
1152
|
-
npm run test:all # All tests (30%+ coverage
|
|
249
|
+
npm run test:all # All tests (30%+ coverage)
|
|
1153
250
|
```
|
|
1154
251
|
|
|
1155
|
-
**Plugin validation**: `bash scripts/validation/validate-marketplace-plugins.sh`
|
|
1156
|
-
|
|
1157
252
|
---
|
|
1158
253
|
|
|
1159
254
|
## Emergency
|
|
1160
255
|
|
|
1161
|
-
### Session Stuck ("Marinating..."
|
|
1162
|
-
|
|
1163
|
-
**Cause**: Heredoc command truncated, shell waiting forever for EOF.
|
|
256
|
+
### Session Stuck ("Marinating...")
|
|
1164
257
|
|
|
1165
258
|
```bash
|
|
1166
|
-
# 1. Force quit Claude Code
|
|
1167
|
-
|
|
1168
|
-
# 2. Kill zombie processes:
|
|
259
|
+
# 1. Force quit Claude Code
|
|
260
|
+
# 2. Kill zombies:
|
|
1169
261
|
pkill -f "cat.*EOF"
|
|
1170
262
|
pkill -9 -f "bash.*specweave"
|
|
1171
|
-
|
|
1172
263
|
# 3. Clean locks:
|
|
1173
|
-
rm -f .specweave/state/.processor.lock
|
|
1174
264
|
rm -f .specweave/state/*.lock
|
|
1175
265
|
rm -rf .specweave/state/.dedup-cache/*.lock
|
|
1176
|
-
|
|
1177
|
-
# 4. Restart Claude Code
|
|
1178
|
-
```
|
|
1179
|
-
|
|
1180
|
-
**Prevention**: NEVER use `Bash("cat > file << EOF")` - use `Write` tool instead!
|
|
1181
|
-
|
|
1182
|
-
### Marketplace Plugin Desync (v1.0.21+)
|
|
1183
|
-
|
|
1184
|
-
**Symptoms**: `/plugin` shows "Plugin 'specweave' not found in marketplace 'specweave'" errors
|
|
1185
|
-
**Root Cause**: `npm run rebuild` regenerates local `dist/`, but marketplace cache points to GitHub clone
|
|
1186
|
-
|
|
1187
|
-
**Quick Fix:**
|
|
1188
|
-
```bash
|
|
1189
|
-
# Refresh marketplace from GitHub and reinstall all plugins
|
|
1190
|
-
bash scripts/refresh-marketplace.sh
|
|
1191
|
-
|
|
1192
|
-
# Verify fix
|
|
1193
|
-
npm test
|
|
1194
|
-
|
|
1195
|
-
# Restart Claude Code for changes to take effect
|
|
1196
|
-
```
|
|
1197
|
-
|
|
1198
|
-
**Detection**:
|
|
1199
|
-
```bash
|
|
1200
|
-
# Check marketplace last update
|
|
1201
|
-
cat ~/.claude/plugins/known_marketplaces.json | jq '.specweave.lastUpdated'
|
|
1202
|
-
|
|
1203
|
-
# Check installed plugin count (should be 24)
|
|
1204
|
-
cat ~/.claude/plugins/installed_plugins.json | jq '.plugins | keys | length'
|
|
1205
|
-
```
|
|
1206
|
-
|
|
1207
|
-
**Prevention**:
|
|
1208
|
-
- Always run `bash scripts/refresh-marketplace.sh` after major changes
|
|
1209
|
-
- Push changes to develop branch to keep GitHub marketplace in sync
|
|
1210
|
-
- Use `/specweave-validate-status` command to check sync status
|
|
1211
|
-
|
|
1212
|
-
### MCP IDE Connection Drops (v0.32.1+)
|
|
1213
|
-
|
|
1214
|
-
**Symptoms**: Session hangs, commands not responding, "Waiting..." forever, UI frozen
|
|
1215
|
-
**Root Cause**: VSCode MCP server WebSocket connection drops after ~2 seconds
|
|
1216
|
-
|
|
1217
|
-
**Detection** (check `~/.claude/debug/latest`):
|
|
1218
|
-
```
|
|
1219
|
-
MCP server "ide": WS-IDE connection dropped after 2s uptime
|
|
1220
|
-
MCP server "ide": Connection error: Received a response for an unknown message ID
|
|
266
|
+
# 4. Restart
|
|
1221
267
|
```
|
|
1222
268
|
|
|
1223
|
-
|
|
269
|
+
### Disable Hooks
|
|
1224
270
|
```bash
|
|
1225
|
-
|
|
1226
|
-
#
|
|
1227
|
-
|
|
1228
|
-
# 2. Reduce diagnostics payload (close extra tabs/files in VS Code)
|
|
1229
|
-
|
|
1230
|
-
# 3. If persists, run Claude Code in plain terminal (not VS Code integrated):
|
|
1231
|
-
cd /path/to/project && claude
|
|
1232
|
-
|
|
1233
|
-
# 4. Run cleanup script:
|
|
1234
|
-
bash plugins/specweave/scripts/cleanup-state.sh
|
|
271
|
+
export SPECWEAVE_DISABLE_HOOKS=1
|
|
272
|
+
# OR rename: mv plugins/specweave/hooks/hooks.json hooks.json.bak
|
|
1235
273
|
```
|
|
1236
274
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
- Update Claude Code VS Code extension regularly
|
|
1240
|
-
- Use terminal mode for long-running sessions
|
|
275
|
+
### Zombie Processes (AUTO-CLEANUP v0.33.0+)
|
|
276
|
+
Session watchdog cleans zombies every 60s automatically.
|
|
1241
277
|
|
|
1242
|
-
###
|
|
1243
|
-
|
|
1244
|
-
**Status**: ✅ AUTOMATED - No manual intervention needed!
|
|
1245
|
-
|
|
1246
|
-
**How it works:**
|
|
1247
|
-
- SessionStart hook registers all Claude Code sessions
|
|
1248
|
-
- Heartbeat process monitors parent health every 5s
|
|
1249
|
-
- Session watchdog cleans up zombies every 60s
|
|
1250
|
-
- Automatic cleanup within 60s of session termination
|
|
1251
|
-
|
|
1252
|
-
**Session Registry**: `.specweave/state/.session-registry.json`
|
|
1253
|
-
|
|
1254
|
-
**Logs**:
|
|
278
|
+
### Marketplace Plugin Desync
|
|
1255
279
|
```bash
|
|
1256
|
-
#
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
# Cleanup logs
|
|
1260
|
-
cat .specweave/logs/cleanup.log
|
|
1261
|
-
|
|
1262
|
-
# Heartbeat logs
|
|
1263
|
-
cat .specweave/logs/heartbeat-*.log
|
|
1264
|
-
```
|
|
1265
|
-
|
|
1266
|
-
**Manual Cleanup (if needed)**:
|
|
1267
|
-
```bash
|
|
1268
|
-
# Kill all zombie processes
|
|
1269
|
-
node dist/src/cli/cleanup-zombies.js 60
|
|
1270
|
-
|
|
1271
|
-
# Or use watchdog
|
|
1272
|
-
bash plugins/specweave/scripts/session-watchdog.sh
|
|
280
|
+
# Refresh marketplace and reinstall plugins
|
|
281
|
+
bash scripts/refresh-marketplace.sh
|
|
1273
282
|
```
|
|
1274
283
|
|
|
1275
|
-
|
|
1276
|
-
- If zombies persist >5 minutes: Check `.specweave/state/.session-registry.json`
|
|
1277
|
-
- If cleanup fails: Run `bash plugins/specweave/scripts/cleanup-state.sh`
|
|
1278
|
-
- For details: See `.specweave/docs/internal/troubleshooting/zombie-processes.md`
|
|
1279
|
-
|
|
1280
|
-
### Crash loop / prompt duplication
|
|
1281
|
-
|
|
1282
|
-
**Disable hooks FIRST:**
|
|
284
|
+
### MCP IDE Connection Drops
|
|
1283
285
|
```bash
|
|
1284
|
-
|
|
1285
|
-
#
|
|
1286
|
-
mv plugins/specweave/hooks/hooks.json plugins/specweave/hooks/hooks.json.bak
|
|
286
|
+
# Restart VS Code Extension Host: Cmd+Shift+P → "Developer: Restart Extension Host"
|
|
287
|
+
# Or run Claude Code in plain terminal instead of VS Code integrated terminal
|
|
1287
288
|
```
|
|
1288
289
|
|
|
1289
|
-
|
|
290
|
+
### Crash Loop / Prompt Duplication
|
|
1290
291
|
```bash
|
|
292
|
+
# Clean state:
|
|
1291
293
|
rm -f .specweave/state/.hook-*
|
|
1292
294
|
rm -rf .specweave/state/.dedup-cache
|
|
1293
295
|
npm run rebuild
|
|
1294
296
|
```
|
|
1295
297
|
|
|
1296
|
-
**Recovery docs**: `.specweave/docs/internal/emergency-procedures/`
|
|
1297
|
-
|
|
1298
|
-
---
|
|
1299
|
-
|
|
1300
|
-
## Hook Development (v1.0.27+)
|
|
1301
|
-
|
|
1302
|
-
### Claude Code Hook Input Format
|
|
1303
|
-
|
|
1304
|
-
**CRITICAL: PreToolUse hooks receive JSON with `tool_input` wrapper!**
|
|
1305
|
-
|
|
1306
|
-
```json
|
|
1307
|
-
// PreToolUse:Write/Edit receives:
|
|
1308
|
-
{
|
|
1309
|
-
"tool_name": "Write",
|
|
1310
|
-
"tool_input": {
|
|
1311
|
-
"file_path": "/path/to/file.md",
|
|
1312
|
-
"content": "file content..."
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
// PreToolUse:Bash receives (NO tool_input wrapper):
|
|
1317
|
-
{
|
|
1318
|
-
"command": "npm install"
|
|
1319
|
-
}
|
|
1320
|
-
```
|
|
1321
|
-
|
|
1322
|
-
**Correct extraction patterns:**
|
|
1323
|
-
```bash
|
|
1324
|
-
# For Write/Edit tools (nested in tool_input):
|
|
1325
|
-
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .file_path // empty')
|
|
1326
|
-
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // .tool_input.new_string // empty')
|
|
1327
|
-
|
|
1328
|
-
# For Bash tool (direct):
|
|
1329
|
-
COMMAND=$(echo "$INPUT" | jq -r '.command // empty')
|
|
1330
|
-
|
|
1331
|
-
# ⚠️ WRONG - will fail silently:
|
|
1332
|
-
FILE_PATH=$(echo "$INPUT" | jq -r '.file_path // empty') # Missing tool_input!
|
|
1333
|
-
```
|
|
1334
|
-
|
|
1335
|
-
**Hook return format (PreToolUse):**
|
|
1336
|
-
```bash
|
|
1337
|
-
# Allow the tool call:
|
|
1338
|
-
echo '{"decision": "allow"}'
|
|
1339
|
-
exit 0
|
|
1340
|
-
|
|
1341
|
-
# Block the tool call:
|
|
1342
|
-
echo '{"decision": "block", "reason": "Error message here"}'
|
|
1343
|
-
exit 2
|
|
1344
|
-
```
|
|
1345
|
-
|
|
1346
|
-
### Hook Concurrency System (v1.0.30+)
|
|
1347
|
-
|
|
1348
|
-
**All hooks use proper concurrency primitives via `fail-fast-wrapper.sh`:**
|
|
1349
|
-
|
|
1350
|
-
**Semaphore** (`hooks/lib/semaphore.sh`):
|
|
1351
|
-
- Limits concurrent hooks to `HOOK_MAX_CONCURRENT` (default: 15)
|
|
1352
|
-
- Graceful degradation when slots unavailable (returns safe default)
|
|
1353
|
-
- Auto-cleanup of stale locks (>30s old)
|
|
1354
|
-
|
|
1355
|
-
**Circuit Breaker** (`hooks/lib/circuit-breaker.sh`):
|
|
1356
|
-
- Per-hook circuit breakers (not global!)
|
|
1357
|
-
- States: CLOSED → (5 failures) → OPEN → (30s) → HALF_OPEN → (3 successes) → CLOSED
|
|
1358
|
-
- Prevents cascade failures from broken hooks
|
|
1359
|
-
|
|
1360
|
-
**Metrics** (`hooks/lib/metrics.sh`):
|
|
1361
|
-
- Tracks success/failure/timeout/skipped per hook
|
|
1362
|
-
- Calculates latency percentiles (p50, p95, p99)
|
|
1363
|
-
- Health score (0-100) per hook
|
|
1364
|
-
|
|
1365
|
-
**Configuration:**
|
|
1366
|
-
```bash
|
|
1367
|
-
HOOK_MAX_CONCURRENT=15 # Max concurrent hooks
|
|
1368
|
-
HOOK_TIMEOUT=5 # Hook execution timeout (seconds)
|
|
1369
|
-
HOOK_DEBUG=1 # Enable debug logging
|
|
1370
|
-
HOOK_ACQUIRE_TIMEOUT_MS=3000 # Semaphore acquire timeout
|
|
1371
|
-
```
|
|
1372
|
-
|
|
1373
|
-
**Health Dashboard:**
|
|
1374
|
-
```bash
|
|
1375
|
-
bash plugins/specweave/scripts/hook-health.sh # Full dashboard
|
|
1376
|
-
bash plugins/specweave/scripts/hook-health.sh --status # Quick status
|
|
1377
|
-
bash plugins/specweave/scripts/hook-health.sh --reset # Reset circuit breakers
|
|
1378
|
-
```
|
|
1379
|
-
|
|
1380
|
-
**Root Cause of Process Storm (Fixed in v1.0.30):**
|
|
1381
|
-
The old system detected "process storms" (>25 concurrent processes) and blocked ALL hooks.
|
|
1382
|
-
This caused cascading failures where even safe hooks were blocked.
|
|
1383
|
-
The new system uses proper semaphore-based concurrency limiting with graceful degradation.
|
|
1384
|
-
|
|
1385
298
|
---
|
|
1386
299
|
|
|
1387
300
|
## Quick Reference
|
|
1388
301
|
|
|
1389
302
|
| Aspect | Rule |
|
|
1390
303
|
|--------|------|
|
|
1391
|
-
| **File ops** | Write/Edit/Read tools ONLY. NEVER Bash heredoc
|
|
1392
|
-
| **
|
|
1393
|
-
|
|
|
1394
|
-
|
|
|
1395
|
-
| Hook input | Write/Edit use `.tool_input.file_path`, Bash uses `.command` |
|
|
1396
|
-
| Cache location | `.specweave/cache/` (24h TTL) |
|
|
1397
|
-
| Pre-commit | Blocks 50+ deletions, `rm -rf` on protected dirs |
|
|
1398
|
-
| Stuck session | Kill + `pkill -f "cat.*EOF"` + clean locks + restart |
|
|
1399
|
-
| MCP drops | Restart Extension Host OR use terminal mode |
|
|
304
|
+
| **File ops** | Write/Edit/Read tools ONLY. NEVER Bash heredoc! |
|
|
305
|
+
| **Hook input** | Write/Edit: `.tool_input.file_path`, Bash: `.command` |
|
|
306
|
+
| **Pre-commit** | Blocks 50+ deletions, `rm -rf` on protected dirs |
|
|
307
|
+
| **Stuck session** | Kill + `pkill -f "cat.*EOF"` + clean locks |
|
|
1400
308
|
|
|
1401
309
|
---
|
|
1402
310
|
|
|
1403
311
|
## References
|
|
1404
312
|
|
|
1405
|
-
**Internal Docs**: `.specweave/docs/internal/`
|
|
1406
|
-
-
|
|
1407
|
-
-
|
|
1408
|
-
- `emergency-procedures/` - Crash recovery guides
|
|
1409
|
-
|
|
1410
|
-
**External**: `.github/CONTRIBUTING.md`, https://spec-weave.com
|
|
313
|
+
- **Internal Docs**: `.specweave/docs/internal/`
|
|
314
|
+
- **ADRs**: `.specweave/docs/internal/architecture/adr/`
|
|
315
|
+
- **Emergency**: `.specweave/docs/internal/emergency-procedures/`
|