spec-feature 1.1.3 → 1.1.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/README.md +19 -16
- package/bin/cli.js +7 -4
- package/bin/viewer.html +152 -10
- package/package.json +3 -2
- package/spec/constitution/03-questions-and-unknowns.md +3 -1
- package/spec/constitution/06-spec-feature-workflow-guardrails.md +2 -2
- package/spec/core/clarifications.md +47 -0
- package/spec/core/hotfix.md +1 -0
- package/spec/core/plan.md +11 -7
- package/spec/core/spec.md +10 -6
- package/spec/core/tasks.md +11 -7
- package/spec/feature.md +14 -9
package/README.md
CHANGED
|
@@ -40,23 +40,25 @@ npx spec-feature view <feature-slug> --folder my-docs
|
|
|
40
40
|
|
|
41
41
|
```mermaid
|
|
42
42
|
graph TD
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
spec_root[spec/] --> readme[README.md]
|
|
44
|
+
spec_root --> feature_template[feature.md]
|
|
45
|
+
spec_root --> core_dir[core/]
|
|
46
|
+
spec_root --> features_dir[features/]
|
|
47
|
+
spec_root --> constitution_dir[constitution/]
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
core_dir --> core_spec[spec.md]
|
|
50
|
+
core_dir --> core_plan[plan.md]
|
|
51
|
+
core_dir --> core_tasks[tasks.md]
|
|
52
|
+
core_dir --> core_clarifications[clarifications.md]
|
|
53
|
+
core_dir --> core_verify[verify.md]
|
|
54
|
+
core_dir --> core_hotfix[hotfix.md]
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
features_dir --> feat[user-auth/]
|
|
57
|
+
feat --> feat_spec[spec.md]
|
|
58
|
+
feat --> feat_plan[plan.md]
|
|
59
|
+
feat --> feat_tasks[tasks.md]
|
|
60
|
+
feat --> feat_clarifications[clarifications.md]
|
|
61
|
+
feat --> feat_verify[verify-report.md]
|
|
60
62
|
```
|
|
61
63
|
|
|
62
64
|
**Templates** (core/) → **Features** (features/)
|
|
@@ -79,13 +81,14 @@ Use the template from spec/feature.md.
|
|
|
79
81
|
#feature-name# Your description here
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-
Format: `#feature# description` → creates `spec/features/feature-name/` with
|
|
84
|
+
Format: `#feature# description` → creates `spec/features/feature-name/` with up to 4 files (adds `clarifications.md` when needed):
|
|
83
85
|
|
|
84
86
|
```mermaid
|
|
85
87
|
flowchart LR
|
|
86
88
|
A[feature.md template] --> B[spec.md]
|
|
87
89
|
A --> C[plan.md]
|
|
88
90
|
A --> D[tasks.md]
|
|
91
|
+
A --> E[clarifications.md]
|
|
89
92
|
```
|
|
90
93
|
|
|
91
94
|
### 2️⃣ Execute Tasks
|
package/bin/cli.js
CHANGED
|
@@ -73,9 +73,9 @@ The \`spec/\` directory is generated by running \`npx spec-feature init\` in the
|
|
|
73
73
|
|
|
74
74
|
### Structure
|
|
75
75
|
|
|
76
|
-
- \`spec/core/\` — templates: \`spec.md\`, \`plan.md\`, \`tasks.md\`, \`verify.md\`, \`hotfix.md\`
|
|
76
|
+
- \`spec/core/\` — templates: \`spec.md\`, \`plan.md\`, \`tasks.md\`, \`clarifications.md\`, \`verify.md\`, \`hotfix.md\`
|
|
77
77
|
- \`spec/feature.md\` — unified prompt template to create/update a feature
|
|
78
|
-
- \`spec/features/<feature>/{spec.md,plan.md,tasks.md}\` — generated feature artifacts
|
|
78
|
+
- \`spec/features/<feature>/{spec.md,plan.md,tasks.md,clarifications.md}\` — generated feature artifacts
|
|
79
79
|
- \`spec/features/<feature>/verify-report.md\` — verification output (after tasks / manual verify)
|
|
80
80
|
|
|
81
81
|
### Create or update a feature
|
|
@@ -84,7 +84,7 @@ Use the template from \`spec/feature.md\` and provide input as:
|
|
|
84
84
|
|
|
85
85
|
\`#<feature># <context>\`
|
|
86
86
|
|
|
87
|
-
Result: create/update the folder \`spec/features/<feature>/\` and produce \`spec.md\` → \`plan.md\` → \`tasks.md\`.
|
|
87
|
+
Result: create/update the folder \`spec/features/<feature>/\` and produce \`clarifications.md\` (if needed) → \`spec.md\` → \`plan.md\` → \`tasks.md\`.
|
|
88
88
|
|
|
89
89
|
### Execute tasks
|
|
90
90
|
|
|
@@ -312,7 +312,7 @@ function readFeatures(featuresRoot) {
|
|
|
312
312
|
.map(dirent => {
|
|
313
313
|
const featureId = dirent.name;
|
|
314
314
|
const featurePath = path.join(featuresRoot, featureId);
|
|
315
|
-
const files = ["spec.md", "plan.md", "tasks.md", "verify-report.md"]
|
|
315
|
+
const files = ["spec.md", "plan.md", "tasks.md", "clarifications.md", "verify-report.md"]
|
|
316
316
|
.filter(name => fs.existsSync(path.join(featurePath, name)))
|
|
317
317
|
.map(name => {
|
|
318
318
|
const content = fs.readFileSync(path.join(featurePath, name), "utf8");
|
|
@@ -322,6 +322,8 @@ function readFeatures(featuresRoot) {
|
|
|
322
322
|
? "plan"
|
|
323
323
|
: name.startsWith("tasks")
|
|
324
324
|
? "tasks"
|
|
325
|
+
: name.startsWith("clarifications")
|
|
326
|
+
? "clarifications"
|
|
325
327
|
: "verify";
|
|
326
328
|
return {
|
|
327
329
|
id: type,
|
|
@@ -358,6 +360,7 @@ function describeFile(type) {
|
|
|
358
360
|
if (type === "spec") return "Specification";
|
|
359
361
|
if (type === "plan") return "Plan";
|
|
360
362
|
if (type === "tasks") return "Tasks";
|
|
363
|
+
if (type === "clarifications") return "Clarifications";
|
|
361
364
|
if (type === "verify") return "Verify report";
|
|
362
365
|
return "Document";
|
|
363
366
|
}
|
package/bin/viewer.html
CHANGED
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
const FolderGit = (p) => <IconBase {...p}><path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 2H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2Z"/><circle cx="12" cy="13" r="2"/><path d="M12 10v1"/><path d="M12 15v2"/></IconBase>;
|
|
74
74
|
const Sun = (p) => <IconBase {...p}><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></IconBase>;
|
|
75
75
|
const Moon = (p) => <IconBase {...p}><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></IconBase>;
|
|
76
|
+
const HelpCircle = (p) => <IconBase {...p}><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.82 1c0 2-3 2-3 4"/><circle cx="12" cy="17" r="1"/></IconBase>;
|
|
76
77
|
|
|
77
78
|
// --- DATA FETCHING ---
|
|
78
79
|
const fetchFeatures = async () => {
|
|
@@ -116,6 +117,124 @@
|
|
|
116
117
|
</div>
|
|
117
118
|
);
|
|
118
119
|
|
|
120
|
+
const renderFormattedText = (text) => {
|
|
121
|
+
if (!text || typeof text !== 'string') return text;
|
|
122
|
+
|
|
123
|
+
const parts = [];
|
|
124
|
+
let keyCounter = 0;
|
|
125
|
+
let lastIndex = 0;
|
|
126
|
+
|
|
127
|
+
// Find all matches (code and bold) with their positions
|
|
128
|
+
const matches = [];
|
|
129
|
+
|
|
130
|
+
// Find inline code matches - matches `text` but not `` (empty backticks)
|
|
131
|
+
// Pattern: backtick, one or more non-backtick characters, backtick
|
|
132
|
+
const codeRegex = /`([^`]+)`/g;
|
|
133
|
+
let match;
|
|
134
|
+
while ((match = codeRegex.exec(text)) !== null) {
|
|
135
|
+
// Only add non-empty matches (at least one character between backticks)
|
|
136
|
+
if (match[1] && match[1].length > 0) {
|
|
137
|
+
matches.push({
|
|
138
|
+
start: match.index,
|
|
139
|
+
end: match.index + match[0].length,
|
|
140
|
+
content: match[1],
|
|
141
|
+
type: 'code'
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Find bold text matches - matches **text**
|
|
147
|
+
// Pattern: **, one or more non-asterisk characters (non-greedy), **
|
|
148
|
+
// This handles: **bold**, but not *** or ** (empty) or **bold*text** (nested asterisks)
|
|
149
|
+
const boldRegex = /\*\*([^*]+?)\*\*/g;
|
|
150
|
+
while ((match = boldRegex.exec(text)) !== null) {
|
|
151
|
+
// Only add non-empty matches (at least one character between **)
|
|
152
|
+
if (match[1] && match[1].length > 0) {
|
|
153
|
+
matches.push({
|
|
154
|
+
start: match.index,
|
|
155
|
+
end: match.index + match[0].length,
|
|
156
|
+
content: match[1],
|
|
157
|
+
type: 'bold'
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// If no matches found, return original text
|
|
163
|
+
if (matches.length === 0) {
|
|
164
|
+
return text;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Sort matches by position
|
|
168
|
+
matches.sort((a, b) => a.start - b.start);
|
|
169
|
+
|
|
170
|
+
// Remove overlapping matches (prioritize code over bold)
|
|
171
|
+
// First pass: mark overlapping matches for removal
|
|
172
|
+
const toRemove = new Set();
|
|
173
|
+
for (let i = 0; i < matches.length; i++) {
|
|
174
|
+
if (toRemove.has(i)) continue;
|
|
175
|
+
const current = matches[i];
|
|
176
|
+
for (let j = i + 1; j < matches.length; j++) {
|
|
177
|
+
if (toRemove.has(j)) continue;
|
|
178
|
+
const other = matches[j];
|
|
179
|
+
// Check if matches overlap
|
|
180
|
+
if (current.start < other.end && current.end > other.start) {
|
|
181
|
+
// Prioritize code over bold
|
|
182
|
+
if (current.type === 'code' && other.type === 'bold') {
|
|
183
|
+
toRemove.add(j);
|
|
184
|
+
} else if (current.type === 'bold' && other.type === 'code') {
|
|
185
|
+
toRemove.add(i);
|
|
186
|
+
break; // Current is removed, no need to check further
|
|
187
|
+
} else {
|
|
188
|
+
// Same type overlapping - keep the first one
|
|
189
|
+
toRemove.add(j);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Filter out removed matches
|
|
196
|
+
const filteredMatches = matches.filter((_, index) => !toRemove.has(index));
|
|
197
|
+
|
|
198
|
+
// Build result array
|
|
199
|
+
filteredMatches.forEach(match => {
|
|
200
|
+
// Add text before match (handles case when match is at start of string)
|
|
201
|
+
if (match.start > lastIndex) {
|
|
202
|
+
const beforeText = text.substring(lastIndex, match.start);
|
|
203
|
+
if (beforeText) {
|
|
204
|
+
parts.push(beforeText);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Add formatted match (always add, even if content is empty to preserve structure)
|
|
209
|
+
if (match.type === 'code') {
|
|
210
|
+
parts.push(
|
|
211
|
+
<code key={keyCounter++} className="px-1.5 py-0.5 bg-slate-100 dark:bg-slate-700 text-slate-800 dark:text-slate-200 rounded text-sm font-mono">
|
|
212
|
+
{match.content}
|
|
213
|
+
</code>
|
|
214
|
+
);
|
|
215
|
+
} else if (match.type === 'bold') {
|
|
216
|
+
parts.push(
|
|
217
|
+
<strong key={keyCounter++} className="font-semibold text-slate-900 dark:text-slate-100">
|
|
218
|
+
{match.content}
|
|
219
|
+
</strong>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
lastIndex = match.end;
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Add remaining text (handles case when match is at end of string)
|
|
227
|
+
if (lastIndex < text.length) {
|
|
228
|
+
const remainingText = text.substring(lastIndex);
|
|
229
|
+
if (remainingText) {
|
|
230
|
+
parts.push(remainingText);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Return formatted parts or original text if something went wrong
|
|
235
|
+
return parts.length > 0 ? parts : text;
|
|
236
|
+
};
|
|
237
|
+
|
|
119
238
|
const renderBoldText = (text) => {
|
|
120
239
|
const parts = text.split('**');
|
|
121
240
|
return parts.map((part, idx) =>
|
|
@@ -124,10 +243,10 @@
|
|
|
124
243
|
};
|
|
125
244
|
|
|
126
245
|
const LinkRenderer = ({ text, onNavigate }) => {
|
|
127
|
-
const fileRegex = /(spec\.md|plan\.md|tasks\.md|verify-report\.md)/g;
|
|
246
|
+
const fileRegex = /(spec\.md|plan\.md|tasks\.md|clarifications\.md|verify-report\.md)/g;
|
|
128
247
|
const parts = text.split(fileRegex);
|
|
129
248
|
if (parts.length === 1) {
|
|
130
|
-
return <span className="text-slate-600 dark:text-slate-400">{
|
|
249
|
+
return <span className="text-slate-600 dark:text-slate-400">{renderFormattedText(text)}</span>;
|
|
131
250
|
}
|
|
132
251
|
return (
|
|
133
252
|
<span className="text-slate-600 dark:text-slate-400">
|
|
@@ -136,6 +255,7 @@
|
|
|
136
255
|
let targetId = 'spec';
|
|
137
256
|
if (part.includes('plan')) targetId = 'plan';
|
|
138
257
|
if (part.includes('tasks')) targetId = 'tasks';
|
|
258
|
+
if (part.includes('clarifications')) targetId = 'clarifications';
|
|
139
259
|
if (part.includes('verify')) targetId = 'verify';
|
|
140
260
|
return (
|
|
141
261
|
<button key={i} onClick={() => onNavigate(targetId)} className="inline-flex items-center gap-0.5 px-1.5 py-0.5 -my-1 mx-0.5 text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/50 rounded text-sm font-medium transition-colors cursor-pointer" title={`Go to ${part}`}>
|
|
@@ -143,7 +263,7 @@
|
|
|
143
263
|
</button>
|
|
144
264
|
);
|
|
145
265
|
}
|
|
146
|
-
return
|
|
266
|
+
return renderFormattedText(part);
|
|
147
267
|
})}
|
|
148
268
|
</span>
|
|
149
269
|
);
|
|
@@ -174,15 +294,15 @@
|
|
|
174
294
|
if (inCodeBlock) { codeBlockContent.push(line); continue; }
|
|
175
295
|
if (line.startsWith('# ')) {
|
|
176
296
|
const h1Text = line.replace('# ', '');
|
|
177
|
-
renderLines.push(<h1 key={i} className="text-2xl font-bold text-slate-900 dark:text-slate-100 mb-6 pb-2 border-b border-slate-200 dark:border-slate-700">{
|
|
297
|
+
renderLines.push(<h1 key={i} className="text-2xl font-bold text-slate-900 dark:text-slate-100 mb-6 pb-2 border-b border-slate-200 dark:border-slate-700">{renderFormattedText(h1Text)}</h1>);
|
|
178
298
|
}
|
|
179
299
|
else if (line.startsWith('## ')) {
|
|
180
300
|
const h2Text = line.replace('## ', '');
|
|
181
|
-
renderLines.push(<h2 key={i} className="text-lg font-bold text-slate-800 dark:text-slate-200 mt-8 mb-3 flex items-center gap-2">{
|
|
301
|
+
renderLines.push(<h2 key={i} className="text-lg font-bold text-slate-800 dark:text-slate-200 mt-8 mb-3 flex items-center gap-2">{renderFormattedText(h2Text)}</h2>);
|
|
182
302
|
}
|
|
183
303
|
else if (line.startsWith('### ')) {
|
|
184
304
|
const h3Text = line.replace('### ', '');
|
|
185
|
-
renderLines.push(<h3 key={i} className="text-md font-semibold text-slate-700 dark:text-slate-300 mt-6 mb-2">{
|
|
305
|
+
renderLines.push(<h3 key={i} className="text-md font-semibold text-slate-700 dark:text-slate-300 mt-6 mb-2">{renderFormattedText(h3Text)}</h3>);
|
|
186
306
|
}
|
|
187
307
|
else if (line.trim().startsWith('- [ ]') || line.trim().startsWith('- [x]')) {
|
|
188
308
|
const isChecked = line.trim().startsWith('- [x]');
|
|
@@ -193,7 +313,7 @@
|
|
|
193
313
|
{isChecked && <Check size={12} strokeWidth={3} />}
|
|
194
314
|
</div>
|
|
195
315
|
<span className={`${isChecked ? 'text-slate-400 dark:text-slate-500 line-through' : 'text-slate-700 dark:text-slate-300'}`}>
|
|
196
|
-
{
|
|
316
|
+
{renderFormattedText(text)}
|
|
197
317
|
</span>
|
|
198
318
|
</div>
|
|
199
319
|
);
|
|
@@ -202,7 +322,7 @@
|
|
|
202
322
|
const listText = line.replace('- ', '');
|
|
203
323
|
renderLines.push(
|
|
204
324
|
<li key={i} className="ml-5 list-disc text-slate-700 dark:text-slate-300 pl-1">
|
|
205
|
-
{
|
|
325
|
+
{renderFormattedText(listText)}
|
|
206
326
|
</li>
|
|
207
327
|
);
|
|
208
328
|
}
|
|
@@ -212,7 +332,7 @@
|
|
|
212
332
|
renderLines.push(
|
|
213
333
|
<div key={i} className="ml-5 text-slate-700 dark:text-slate-300 flex gap-2">
|
|
214
334
|
<span className="font-mono text-slate-400 dark:text-slate-500 font-bold w-4 text-right">{numMatch[1]}.</span>
|
|
215
|
-
<span>{
|
|
335
|
+
<span>{renderFormattedText(numMatch[2])}</span>
|
|
216
336
|
</div>
|
|
217
337
|
);
|
|
218
338
|
}
|
|
@@ -228,6 +348,7 @@
|
|
|
228
348
|
case 'spec': return <BookOpen size={18} className="text-blue-600" />;
|
|
229
349
|
case 'plan': return <MapIcon size={18} className="text-amber-500" />;
|
|
230
350
|
case 'tasks': return <ListTodo size={18} className="text-emerald-500" />;
|
|
351
|
+
case 'clarifications': return <HelpCircle size={18} className="text-cyan-500" />;
|
|
231
352
|
case 'verify': return <ShieldCheck size={18} className="text-purple-500" />;
|
|
232
353
|
default: return <FileText size={18} className="text-slate-400" />;
|
|
233
354
|
}
|
|
@@ -287,6 +408,26 @@
|
|
|
287
408
|
);
|
|
288
409
|
};
|
|
289
410
|
|
|
411
|
+
const PreviewText = ({ content, maxLength = 150 }) => {
|
|
412
|
+
if (!content) return <span>No description</span>;
|
|
413
|
+
|
|
414
|
+
// Extract first paragraph, remove headers and code blocks
|
|
415
|
+
const lines = content.split('\n');
|
|
416
|
+
let previewText = '';
|
|
417
|
+
for (let i = 0; i < lines.length && previewText.length < maxLength; i++) {
|
|
418
|
+
const line = lines[i].trim();
|
|
419
|
+
if (line && !line.startsWith('#') && !line.startsWith('```') && !line.startsWith('- [') && !line.startsWith('- ')) {
|
|
420
|
+
previewText += (previewText ? ' ' : '') + line;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (previewText.length > maxLength) {
|
|
425
|
+
previewText = previewText.substring(0, maxLength) + '...';
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return <span>{renderFormattedText(previewText || 'No description')}</span>;
|
|
429
|
+
};
|
|
430
|
+
|
|
290
431
|
const Dashboard = ({ features, onSelectFeature }) => {
|
|
291
432
|
return (
|
|
292
433
|
<div className="p-8 max-w-6xl mx-auto">
|
|
@@ -304,6 +445,7 @@
|
|
|
304
445
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
305
446
|
{features.map(feature => {
|
|
306
447
|
const progress = calculateProgress(feature.files);
|
|
448
|
+
const specFile = feature.files.find(f => f.type === 'spec');
|
|
307
449
|
return (
|
|
308
450
|
<div key={feature.id} onClick={() => onSelectFeature(feature.id)}
|
|
309
451
|
className="bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-xl p-5 shadow-sm hover:shadow-md hover:border-blue-300 dark:hover:border-blue-600 transition-all cursor-pointer group flex flex-col h-full">
|
|
@@ -317,7 +459,7 @@
|
|
|
317
459
|
|
|
318
460
|
<div className="flex-1">
|
|
319
461
|
<p className="text-xs text-slate-500 dark:text-slate-400 mb-4 line-clamp-2">
|
|
320
|
-
{
|
|
462
|
+
<PreviewText content={specFile?.content} maxLength={150} />
|
|
321
463
|
</p>
|
|
322
464
|
</div>
|
|
323
465
|
|
package/package.json
CHANGED
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
- success criteria are unclear,
|
|
8
8
|
- there are multiple valid implementations with different tradeoffs,
|
|
9
9
|
- actions would be destructive or expensive.
|
|
10
|
+
- MUST write all clarifying questions to `spec/features/{FEATURE}/clarifications.md` (within the feature folder). Do not embed questions in `spec.md`, `plan.md`, `tasks.md`, or chat messages.
|
|
10
11
|
- MUST prefer 1–2 high-impact questions over a long questionnaire.
|
|
11
12
|
- MUST propose sensible defaults as options (without executing them unless confirmed).
|
|
12
|
-
- MUST stop and wait if the missing information blocks a correct implementation.
|
|
13
|
+
- MUST stop and wait if the missing information blocks a correct implementation. In this case, create/update `spec/features/{FEATURE}/clarifications.md` and do not proceed with generating/updating other artifacts until answers are provided.
|
|
13
14
|
|
|
14
15
|
## How to verify
|
|
15
16
|
|
|
16
17
|
- Ambiguous inputs always produce clarifying questions and a short list of options.
|
|
17
18
|
- Blocking unknowns are not silently assumed.
|
|
19
|
+
- Questions are present in `spec/features/{FEATURE}/clarifications.md` and not duplicated elsewhere.
|
|
18
20
|
|
|
19
21
|
## Exceptions
|
|
20
22
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
- MUST keep all spec-feature artifacts under `spec/`.
|
|
6
6
|
- MUST follow the sequence:
|
|
7
|
-
- specification (`spec.md`) → plan (`plan.md`) → tasks (`tasks.md`) → execution → verification (`verify-report.md`).
|
|
7
|
+
- clarifications (`clarifications.md`, if needed) → specification (`spec.md`) → plan (`plan.md`) → tasks (`tasks.md`) → execution → verification (`verify-report.md`).
|
|
8
8
|
- MUST NOT execute implementation tasks unless the user explicitly requests execution and references `spec/features/{FEATURE}/tasks.md`.
|
|
9
|
-
- MUST keep `spec.md`, `plan.md`, and `
|
|
9
|
+
- MUST keep `spec.md`, `plan.md`, `tasks.md`, and `clarifications.md` consistent (terms, components, constraints, decisions).
|
|
10
10
|
- MUST update `tasks.md` checkboxes to reflect actual state during verification.
|
|
11
11
|
- SHOULD update the constitution when a feature introduces a new invariant or process rule.
|
|
12
12
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!-- spec-feature: clarifications -->
|
|
2
|
+
|
|
3
|
+
Template collects all clarifying questions for a feature in the **spec-feature** process.
|
|
4
|
+
|
|
5
|
+
**Parameters**
|
|
6
|
+
|
|
7
|
+
- **FEATURE** — name of the folder where the clarifications will be saved. Taken from the value between the first two `#` symbols (e.g., `#payments#` → `payments`).
|
|
8
|
+
- **CONTEXT** — main context that triggered the questions. Consider everything after the second `#` in the parameter line; context can span multiple lines.
|
|
9
|
+
|
|
10
|
+
**General rules**
|
|
11
|
+
|
|
12
|
+
- Before doing anything, read and follow `spec/constitution/*`.
|
|
13
|
+
- Work only with specification files within `/spec` directory: automatically create necessary directories and files.
|
|
14
|
+
- Do not generate application code, configuration snippets, scripts, or patches while preparing clarifications.
|
|
15
|
+
- All clarifying questions MUST be written to `spec/features/{FEATURE}/clarifications.md` (this file) and MUST NOT be embedded in `spec.md`, `plan.md`, `tasks.md`, or chat messages.
|
|
16
|
+
- Prefer 1–2 high-impact questions over a long questionnaire; provide options/defaults when possible.
|
|
17
|
+
- If the missing information blocks correct planning/specification, create/update this file and stop. Do not proceed to generate/update `spec.md`, `plan.md`, or `tasks.md` until answers are provided.
|
|
18
|
+
|
|
19
|
+
**Steps**
|
|
20
|
+
|
|
21
|
+
1. Create the directory structure `spec/features/{FEATURE}/` if it doesn't exist.
|
|
22
|
+
2. Create/update the file `spec/features/{FEATURE}/clarifications.md` using the template below:
|
|
23
|
+
- Add new questions at the end.
|
|
24
|
+
- Keep previously answered questions and do not overwrite user answers.
|
|
25
|
+
3. Ensure the document is valid Markdown and contains no placeholders.
|
|
26
|
+
|
|
27
|
+
**Result template**
|
|
28
|
+
|
|
29
|
+
```md
|
|
30
|
+
# Clarifications — {FEATURE}
|
|
31
|
+
|
|
32
|
+
**Context:** {CONTEXT}
|
|
33
|
+
|
|
34
|
+
## Open questions
|
|
35
|
+
|
|
36
|
+
| # | Question | Options / suggested default | User answer | Status |
|
|
37
|
+
|---|----------|----------------------------|------------|--------|
|
|
38
|
+
| 1 | <question> | <options or default> | <fill in> | open |
|
|
39
|
+
|
|
40
|
+
## Resolved decisions
|
|
41
|
+
|
|
42
|
+
| # | Decision | Rationale | Source question |
|
|
43
|
+
|---|----------|-----------|-----------------|
|
|
44
|
+
| 1 | <decision> | <why> | #1 |
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Write strictly in Markdown and automatically create/update the clarifications file. **Goal** — create/update file `/spec/features/{FEATURE}/clarifications.md` to capture all clarifying questions and user answers for this feature.
|
package/spec/core/hotfix.md
CHANGED
|
@@ -23,6 +23,7 @@ Template automates feature maintenance after release: records hotfixes and synch
|
|
|
23
23
|
|
|
24
24
|
- `spec.md` — update sections affected by the hotfix: clarify user scenarios, rules, or non-functional requirements, add new Assumptions when open questions arise.
|
|
25
25
|
- `plan.md` — adjust technical solutions: data sources, contracts, architectural constraints, and risks, so the plan reflects the current feature structure.
|
|
26
|
+
- `clarifications.md` — if `spec/features/{FEATURE}/clarifications.md` already exists and the hotfix introduces new open questions, append them there (do not overwrite user answers). If it does not exist, record open questions as assumptions in `spec.md` (this template forbids creating new files).
|
|
26
27
|
- `tasks.md` —
|
|
27
28
|
- Add new checkboxes for work required by the hotfix, group them in appropriate sections. Names should start with prefix `hotfix_<date>` in `YYYY-MM-DD` format.
|
|
28
29
|
- Update statuses of existing tasks (`[ ]`/`[x]`), considering actual execution and hotfix results.
|
package/spec/core/plan.md
CHANGED
|
@@ -10,11 +10,14 @@ Template helps format the feature implementation plan in the **spec-feature** pr
|
|
|
10
10
|
**General rules**
|
|
11
11
|
|
|
12
12
|
- Before doing anything, read and follow `spec/constitution/*`.
|
|
13
|
-
- If information is missing
|
|
13
|
+
- If information is missing:
|
|
14
|
+
- add a clarifying question to `spec/features/{FEATURE}/clarifications.md` (use `spec/core/clarifications.md` as a template),
|
|
15
|
+
- in this document, write `No data — needs clarification (see clarifications.md: #<n>)`,
|
|
16
|
+
- do not guess.
|
|
14
17
|
- Work only with specification files within `/spec` directory: automatically create necessary directories and files.
|
|
15
18
|
- Do not generate application code, configuration snippets, scripts, or patches while preparing the implementation plan.
|
|
16
19
|
- Use `spec/core/spec.md` as the specification source on which the plan is formed.
|
|
17
|
-
- Use `spec/features/{FEATURE}/spec.md` as additional context. If
|
|
20
|
+
- Use `spec/features/{FEATURE}/spec.md` and `spec/features/{FEATURE}/clarifications.md` (resolved answers/decisions) as additional context. If files are unavailable, continue working based on **CONTEXT**.
|
|
18
21
|
- Substitute specific values instead of placeholders (`{FEATURE}`, `{CONTEXT}`, etc.). If a section is not applicable — explicitly write `Not required — reason: <explanation>`.
|
|
19
22
|
- Form meaningful paragraphs or lists: do not leave empty headers, hint comments, and `...` markers.
|
|
20
23
|
- Follow basic software development principles: KISS, DRY, and YAGNI, so solutions remain simple, without duplication and unnecessary logic.
|
|
@@ -26,15 +29,16 @@ Template helps format the feature implementation plan in the **spec-feature** pr
|
|
|
26
29
|
- `## Contracts and interfaces` — public APIs, events, queues, UI/CLI, error formats, and validation expectations.
|
|
27
30
|
- `## Architecture / Components` — services, modules, integrations, constraints, and chosen stack (DB, API, UI, queues, background processes, etc.).
|
|
28
31
|
- `## Risks` — potential problems and mitigation methods.
|
|
29
|
-
- `## Assumptions` — explicit assumptions and
|
|
32
|
+
- `## Assumptions` — explicit assumptions and open dependencies. Do not embed clarifying questions here; link to `clarifications.md` if any.
|
|
30
33
|
|
|
31
34
|
**Steps**
|
|
32
35
|
|
|
33
36
|
1. Create the directory structure `spec/features/{FEATURE}/` if it doesn't exist.
|
|
34
|
-
2.
|
|
35
|
-
3.
|
|
36
|
-
4.
|
|
37
|
-
5.
|
|
37
|
+
2. If any clarifying questions are needed, create/update `spec/features/{FEATURE}/clarifications.md` using `spec/core/clarifications.md` and stop if unanswered questions block correct planning.
|
|
38
|
+
3. Form the plan according to the sections above, based on **CONTEXT** and available additional context. For each section, fix what exactly needs to be done, not just list components.
|
|
39
|
+
4. Create/update the file `spec/features/{FEATURE}/plan.md` with the complete plan content.
|
|
40
|
+
5. Check that the document contains no unfilled placeholders and that the output is formatted in valid Markdown.
|
|
41
|
+
6. Ensure the document is complete and ready for implementation.
|
|
38
42
|
|
|
39
43
|
**Result template**
|
|
40
44
|
|
package/spec/core/spec.md
CHANGED
|
@@ -10,7 +10,10 @@ Template helps describe a feature before implementation in the **spec-feature**
|
|
|
10
10
|
**General rules**
|
|
11
11
|
|
|
12
12
|
- Before doing anything, read and follow `spec/constitution/*`.
|
|
13
|
-
- If information is missing
|
|
13
|
+
- If information is missing:
|
|
14
|
+
- add a clarifying question to `spec/features/{FEATURE}/clarifications.md` (use `spec/core/clarifications.md` as a template),
|
|
15
|
+
- in this document, write `No data — needs clarification (see clarifications.md: #<n>)`,
|
|
16
|
+
- do not guess.
|
|
14
17
|
- Work only with specification files within `/spec` directory: automatically create necessary directories and files.
|
|
15
18
|
- Do not generate application code, configuration snippets, scripts, or patches while preparing the specification.
|
|
16
19
|
- Substitute specific values instead of placeholders (`{FEATURE}`, `{CONTEXT}`, etc.). The final document should not contain hints, examples, or `...` markers.
|
|
@@ -24,15 +27,16 @@ Template helps describe a feature before implementation in the **spec-feature**
|
|
|
24
27
|
- `## User Stories` — minimum three completed stories. For each, fix the role, action, and result/value.
|
|
25
28
|
- `## Main scenarios and rules` — key usage scenarios, constraints, error variants.
|
|
26
29
|
- `## Non-functional requirements` — SLA, performance, security, localization, accessibility, and other non-functional criteria.
|
|
27
|
-
- `## Assumptions` — explicit assumptions and questions
|
|
30
|
+
- `## Assumptions` — explicit assumptions and open dependencies. Do not embed clarifying questions here; link to `clarifications.md` if any.
|
|
28
31
|
|
|
29
32
|
**Steps**
|
|
30
33
|
|
|
31
34
|
1. Create the directory structure `spec/features/{FEATURE}/` if it doesn't exist.
|
|
32
|
-
2.
|
|
33
|
-
3.
|
|
34
|
-
4.
|
|
35
|
-
5.
|
|
35
|
+
2. If any clarifying questions are needed, create/update `spec/features/{FEATURE}/clarifications.md` using `spec/core/clarifications.md`.
|
|
36
|
+
3. Form the specification according to the sections above, based on **CONTEXT** and available additional context (including clarified answers, if present).
|
|
37
|
+
4. Create/update the file `spec/features/{FEATURE}/spec.md` with the complete specification content.
|
|
38
|
+
5. Check that the document is formatted in Markdown and contains no unfilled placeholders.
|
|
39
|
+
6. Ensure the document is complete and ready for implementation.
|
|
36
40
|
|
|
37
41
|
**Result template**
|
|
38
42
|
|
package/spec/core/tasks.md
CHANGED
|
@@ -10,11 +10,14 @@ Template helps form a task list for feature implementation in the **spec-feature
|
|
|
10
10
|
**General rules**
|
|
11
11
|
|
|
12
12
|
- Before doing anything, read and follow `spec/constitution/*`.
|
|
13
|
-
- If information is missing
|
|
13
|
+
- If information is missing:
|
|
14
|
+
- add a clarifying question to `spec/features/{FEATURE}/clarifications.md` (use `spec/core/clarifications.md` as a template),
|
|
15
|
+
- in this document, write `No data — needs clarification (see clarifications.md: #<n>)`,
|
|
16
|
+
- do not guess.
|
|
14
17
|
- Work only with specification files within `/spec` directory: automatically create necessary directories and files.
|
|
15
18
|
- Do not generate application code, configuration snippets, scripts, or patches while preparing the task list.
|
|
16
19
|
- Use `spec/core/spec.md` and `spec/core/plan.md` as base sources of specification and plan when preparing tasks.
|
|
17
|
-
- Use `spec/features/{FEATURE}/spec.md` and `spec/features/{FEATURE}/
|
|
20
|
+
- Use `spec/features/{FEATURE}/spec.md`, `spec/features/{FEATURE}/plan.md`, and `spec/features/{FEATURE}/clarifications.md` (resolved answers/decisions) as additional context. If any file is missing, continue working based on available materials and **CONTEXT**.
|
|
18
21
|
- Substitute specific values instead of placeholders (`{FEATURE}`, `{CONTEXT}`, etc.). The final document should not contain hints, examples, or `...` markers.
|
|
19
22
|
- Each task is a checkbox with result formulation and description of mandatory checks/tests.
|
|
20
23
|
- If a direction is not required, explicitly indicate under the corresponding subheading `Not required — reason: <explanation>`.
|
|
@@ -31,11 +34,12 @@ Template helps form a task list for feature implementation in the **spec-feature
|
|
|
31
34
|
**Steps**
|
|
32
35
|
|
|
33
36
|
1. Create the directory structure `spec/features/{FEATURE}/` if it doesn't exist.
|
|
34
|
-
2.
|
|
35
|
-
3.
|
|
36
|
-
4.
|
|
37
|
-
5.
|
|
38
|
-
6.
|
|
37
|
+
2. If any clarifying questions are needed, create/update `spec/features/{FEATURE}/clarifications.md` using `spec/core/clarifications.md` and stop if unanswered questions block correct task definition.
|
|
38
|
+
3. Form the task list according to the sections above, based on **CONTEXT** and available additional context.
|
|
39
|
+
4. Create/update the file `spec/features/{FEATURE}/tasks.md` with the complete task list content.
|
|
40
|
+
5. Ensure that tasks cover implementation, verification, and release of the feature. The final Markdown should not contain unfilled placeholders.
|
|
41
|
+
6. Record in the `## Definition of Done` section that `/spec/core/verify.md` execution is performed after completing all tasks, so executors do this automatically upon completion of the list.
|
|
42
|
+
7. Ensure the document is complete and ready for implementation.
|
|
39
43
|
|
|
40
44
|
**Result template**
|
|
41
45
|
|
package/spec/feature.md
CHANGED
|
@@ -12,11 +12,14 @@ Parameters are passed in one line in the format `#<feature># <context>` without
|
|
|
12
12
|
**General rules**
|
|
13
13
|
|
|
14
14
|
- Before doing anything, read and follow `spec/constitution/*`.
|
|
15
|
-
- If information is missing
|
|
15
|
+
- If information is missing:
|
|
16
|
+
- write clarifying questions to `spec/features/{FEATURE}/clarifications.md` (use `spec/core/clarifications.md` as a template),
|
|
17
|
+
- in other documents, write `No data — needs clarification (see clarifications.md: #<n>)`,
|
|
18
|
+
- do not guess.
|
|
16
19
|
- Work only with specification files in the `spec/features/{FEATURE}` directory: automatically create necessary directories and files within `/spec` folder only.
|
|
17
20
|
- Do not generate application code, configuration snippets, scripts, or patches while preparing specification artifacts.
|
|
18
21
|
- If the **FEATURE** value matches an already existing feature, update its current materials instead of creating a new folder and use the `spec/core/hotfix.md` template when making changes.
|
|
19
|
-
- Within one request, create/update
|
|
22
|
+
- Within one request, create/update feature documents in the appropriate directory structure. If clarifications are needed and answers are missing, create/update `clarifications.md` and stop before generating/updating `spec.md`, `plan.md`, and `tasks.md`.
|
|
20
23
|
- Automatically create the directory structure `spec/features/{FEATURE}/` if it doesn't exist.
|
|
21
24
|
- All sections from templates must be filled with content: do not leave empty headers, placeholders, or hint comments.
|
|
22
25
|
- Use sequence: first specification, then plan (based on specification), then task list (based on specification and plan).
|
|
@@ -26,18 +29,20 @@ Parameters are passed in one line in the format `#<feature># <context>` without
|
|
|
26
29
|
**Steps**
|
|
27
30
|
|
|
28
31
|
1. Check if `spec/features/{FEATURE}/` directory exists, create it if necessary.
|
|
29
|
-
2.
|
|
30
|
-
3.
|
|
31
|
-
4.
|
|
32
|
-
5.
|
|
32
|
+
2. If any clarifying questions are needed, create/update `spec/features/{FEATURE}/clarifications.md` using `spec/core/clarifications.md`. If answers are missing and this blocks correct generation, stop here.
|
|
33
|
+
3. Prepare and create/update specification `spec/features/{FEATURE}/spec.md` using the template from `spec/core/spec.md`, using **CONTEXT** as primary context (and clarified answers, if present).
|
|
34
|
+
4. Based on the completed specification and **CONTEXT**, form and create/update plan `spec/features/{FEATURE}/plan.md` using the structure from `spec/core/plan.md`.
|
|
35
|
+
5. Considering specification, plan, and **CONTEXT**, compile and create/update task list `spec/features/{FEATURE}/tasks.md` according to requirements from `spec/core/tasks.md`.
|
|
36
|
+
6. Check that each document is formatted in valid Markdown and contains no unfilled sections.
|
|
33
37
|
|
|
34
38
|
**Result structure**
|
|
35
39
|
|
|
36
40
|
The process should automatically create/update the following files:
|
|
37
41
|
|
|
38
|
-
1. `spec/features/{FEATURE}/
|
|
39
|
-
2. `spec/features/{FEATURE}/
|
|
40
|
-
3. `spec/features/{FEATURE}/
|
|
42
|
+
1. `spec/features/{FEATURE}/clarifications.md` - Clarifying questions and user answers (if needed)
|
|
43
|
+
2. `spec/features/{FEATURE}/spec.md` - Feature specification document
|
|
44
|
+
3. `spec/features/{FEATURE}/plan.md` - Implementation plan document
|
|
45
|
+
4. `spec/features/{FEATURE}/tasks.md` - Task list document
|
|
41
46
|
|
|
42
47
|
Each document should be created with complete content based on the templates from `spec/core/` and the provided **CONTEXT**.
|
|
43
48
|
|