specdo 1.0.2
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/CHANGELOG.md +139 -0
- package/README.md +308 -0
- package/README.zh-CN.md +306 -0
- package/bin/specdo.js +3 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +297 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/_shared.d.ts +45 -0
- package/dist/commands/_shared.d.ts.map +1 -0
- package/dist/commands/_shared.js +124 -0
- package/dist/commands/_shared.js.map +1 -0
- package/dist/commands/apply.d.ts +30 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +393 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/archive.d.ts +25 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +362 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/doctor.d.ts +21 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +180 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/domains.d.ts +14 -0
- package/dist/commands/domains.d.ts.map +1 -0
- package/dist/commands/domains.js +107 -0
- package/dist/commands/domains.js.map +1 -0
- package/dist/commands/explore.d.ts +48 -0
- package/dist/commands/explore.d.ts.map +1 -0
- package/dist/commands/explore.js +378 -0
- package/dist/commands/explore.js.map +1 -0
- package/dist/commands/init.d.ts +45 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +243 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +23 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +135 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/propose.d.ts +22 -0
- package/dist/commands/propose.d.ts.map +1 -0
- package/dist/commands/propose.js +316 -0
- package/dist/commands/propose.js.map +1 -0
- package/dist/commands/show.d.ts +15 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +214 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/status.d.ts +17 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +146 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +21 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +113 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/validate.d.ts +117 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +446 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/core/apply-brief-renderer.d.ts +35 -0
- package/dist/core/apply-brief-renderer.d.ts.map +1 -0
- package/dist/core/apply-brief-renderer.js +242 -0
- package/dist/core/apply-brief-renderer.js.map +1 -0
- package/dist/core/config-store.d.ts +190 -0
- package/dist/core/config-store.d.ts.map +1 -0
- package/dist/core/config-store.js +280 -0
- package/dist/core/config-store.js.map +1 -0
- package/dist/core/context-store.d.ts +96 -0
- package/dist/core/context-store.d.ts.map +1 -0
- package/dist/core/context-store.js +426 -0
- package/dist/core/context-store.js.map +1 -0
- package/dist/core/json-schemas.d.ts +349 -0
- package/dist/core/json-schemas.d.ts.map +1 -0
- package/dist/core/json-schemas.js +125 -0
- package/dist/core/json-schemas.js.map +1 -0
- package/dist/core/skill-content/cross-domain.d.ts +12 -0
- package/dist/core/skill-content/cross-domain.d.ts.map +1 -0
- package/dist/core/skill-content/cross-domain.js +291 -0
- package/dist/core/skill-content/cross-domain.js.map +1 -0
- package/dist/core/skill-content/protocol-examples.d.ts +13 -0
- package/dist/core/skill-content/protocol-examples.d.ts.map +1 -0
- package/dist/core/skill-content/protocol-examples.js +190 -0
- package/dist/core/skill-content/protocol-examples.js.map +1 -0
- package/dist/core/skill-content/workflow-content.d.ts +25 -0
- package/dist/core/skill-content/workflow-content.d.ts.map +1 -0
- package/dist/core/skill-content/workflow-content.js +1572 -0
- package/dist/core/skill-content/workflow-content.js.map +1 -0
- package/dist/core/skill-exporter.d.ts +186 -0
- package/dist/core/skill-exporter.d.ts.map +1 -0
- package/dist/core/skill-exporter.js +922 -0
- package/dist/core/skill-exporter.js.map +1 -0
- package/dist/core/spec-sync.d.ts +65 -0
- package/dist/core/spec-sync.d.ts.map +1 -0
- package/dist/core/spec-sync.js +226 -0
- package/dist/core/spec-sync.js.map +1 -0
- package/dist/core/task-parser.d.ts +58 -0
- package/dist/core/task-parser.d.ts.map +1 -0
- package/dist/core/task-parser.js +244 -0
- package/dist/core/task-parser.js.map +1 -0
- package/dist/core/template-renderer.d.ts +51 -0
- package/dist/core/template-renderer.d.ts.map +1 -0
- package/dist/core/template-renderer.js +362 -0
- package/dist/core/template-renderer.js.map +1 -0
- package/dist/domains/architecture.d.ts +34 -0
- package/dist/domains/architecture.d.ts.map +1 -0
- package/dist/domains/architecture.js +341 -0
- package/dist/domains/architecture.js.map +1 -0
- package/dist/domains/backend.d.ts +35 -0
- package/dist/domains/backend.d.ts.map +1 -0
- package/dist/domains/backend.js +367 -0
- package/dist/domains/backend.js.map +1 -0
- package/dist/domains/frontend.d.ts +36 -0
- package/dist/domains/frontend.d.ts.map +1 -0
- package/dist/domains/frontend.js +373 -0
- package/dist/domains/frontend.js.map +1 -0
- package/dist/domains/index.d.ts +49 -0
- package/dist/domains/index.d.ts.map +1 -0
- package/dist/domains/index.js +255 -0
- package/dist/domains/index.js.map +1 -0
- package/dist/domains/operations.d.ts +37 -0
- package/dist/domains/operations.d.ts.map +1 -0
- package/dist/domains/operations.js +344 -0
- package/dist/domains/operations.js.map +1 -0
- package/dist/domains/pool-ranking.d.ts +43 -0
- package/dist/domains/pool-ranking.d.ts.map +1 -0
- package/dist/domains/pool-ranking.js +153 -0
- package/dist/domains/pool-ranking.js.map +1 -0
- package/dist/domains/quality.d.ts +45 -0
- package/dist/domains/quality.d.ts.map +1 -0
- package/dist/domains/quality.js +368 -0
- package/dist/domains/quality.js.map +1 -0
- package/dist/domains/security.d.ts +19 -0
- package/dist/domains/security.d.ts.map +1 -0
- package/dist/domains/security.js +364 -0
- package/dist/domains/security.js.map +1 -0
- package/dist/domains/signal-match.d.ts +25 -0
- package/dist/domains/signal-match.d.ts.map +1 -0
- package/dist/domains/signal-match.js +67 -0
- package/dist/domains/signal-match.js.map +1 -0
- package/dist/domains/types.d.ts +354 -0
- package/dist/domains/types.d.ts.map +1 -0
- package/dist/domains/types.js +12 -0
- package/dist/domains/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/protocols/index.d.ts +36 -0
- package/dist/protocols/index.d.ts.map +1 -0
- package/dist/protocols/index.js +85 -0
- package/dist/protocols/index.js.map +1 -0
- package/dist/protocols/review-to-solid.d.ts +32 -0
- package/dist/protocols/review-to-solid.d.ts.map +1 -0
- package/dist/protocols/review-to-solid.js +309 -0
- package/dist/protocols/review-to-solid.js.map +1 -0
- package/dist/utils/prompt.d.ts +37 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +81 -0
- package/dist/utils/prompt.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,1572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Skill Content
|
|
3
|
+
*
|
|
4
|
+
* 5 个工作流 skill 的完整 progressive-disclosure 内容:
|
|
5
|
+
* 每个 skill 由 1 个精炼 SKILL.md(≤ 50 行)+ 1-2 个 references/*.md 组成。
|
|
6
|
+
*
|
|
7
|
+
* - SKILL.md: When to use / Quick command / 链接 references / Next step
|
|
8
|
+
* - references/REFERENCE.md: 完整命令矩阵、所有标志、exit code、错误恢复
|
|
9
|
+
* - references/EXAMPLES.md: 1-2 段真实对话样本
|
|
10
|
+
*
|
|
11
|
+
* 当前内容约束:
|
|
12
|
+
* - 不导出 `specdo-init` skill(input 由 agent 直接引导)
|
|
13
|
+
* - exit code 列表对齐当前 CLI 行为
|
|
14
|
+
* - description 包含真实 trigger 短语("let's plan", "scaffold the change" 等)
|
|
15
|
+
*
|
|
16
|
+
* Source of truth 为代码本身(运行时渲染,无模板文件)。
|
|
17
|
+
*/
|
|
18
|
+
// ─── specdo-explore ────────────────────────────────────────────
|
|
19
|
+
const EXPLORE_BODY = `# specdo explore
|
|
20
|
+
|
|
21
|
+
## How to use this skill (do exactly this)
|
|
22
|
+
|
|
23
|
+
**CRITICAL: Do NOT run \`specdo explore\` immediately.**
|
|
24
|
+
|
|
25
|
+
When this skill loads, your first instinct may be to run \`specdo explore '<idea>'\`.
|
|
26
|
+
**Resist this.** Running explore without preparation produces a zero-domain,
|
|
27
|
+
shallow-context change with a random slug that will fail downstream.
|
|
28
|
+
|
|
29
|
+
You MUST first complete the Grill-Me interview below — ask at least 8
|
|
30
|
+
domain questions (typically 10-30), one at a time, in \`[domain:index]\`
|
|
31
|
+
format. Only run
|
|
32
|
+
\`specdo explore\` **after** the user has answered enough questions and you
|
|
33
|
+
can summarize all decisions into a \`--context\` string.
|
|
34
|
+
|
|
35
|
+
## Overview
|
|
36
|
+
|
|
37
|
+
Seed a new change directory with domain-scored context. The explore stage
|
|
38
|
+
captures the user's intent, selects relevant domains (1-4 of 6), runs the
|
|
39
|
+
Grill-Me interview methodology, and records discovery context before any
|
|
40
|
+
artifacts are generated. Output: \`specdo/changes/<name>/context.json\`.
|
|
41
|
+
|
|
42
|
+
## The correct flow (follow this exactly)
|
|
43
|
+
|
|
44
|
+
### Phase 1 — DISCOVERY (do this FIRST)
|
|
45
|
+
|
|
46
|
+
1. Read \`references/DOMAIN_DISCOVERY.md\` — review all 6 domains'
|
|
47
|
+
signals and questions.
|
|
48
|
+
2. **Select 1-4 domains** that match the user's intent. Do NOT rely on
|
|
49
|
+
\`scoreDomains()\` — non-English input (pure Chinese, Japanese, etc.)
|
|
50
|
+
may produce zero matches; prefer explicit \`--domains\` selection.
|
|
51
|
+
3. **Grill the user** using the Grill-Me Methodology below — ask at least 8
|
|
52
|
+
domain questions (typically 10-30), one at a time, with \`[domain:index]\`
|
|
53
|
+
format. Continue until the decision tree is exhausted. Do NOT offer to
|
|
54
|
+
proceed to propose after only 3-5 questions **unless every branch of
|
|
55
|
+
the decision tree has been genuinely resolved in fewer** (see stop
|
|
56
|
+
conditions below).
|
|
57
|
+
4. **Summarize** all collected decisions into a \`--context\` string
|
|
58
|
+
(comma-separated key decisions, e.g. "Next.js + Tailwind, Markdown in
|
|
59
|
+
repo, no DB").
|
|
60
|
+
|
|
61
|
+
### Phase 2 — RECORD (only after Phase 1 is complete)
|
|
62
|
+
|
|
63
|
+
\`\`\`bash
|
|
64
|
+
specdo explore '<idea>' \\
|
|
65
|
+
--change <your-english-slug> \\
|
|
66
|
+
--domains <list> \\
|
|
67
|
+
--context '<summary>' \\
|
|
68
|
+
--depth standard
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
\`--change\` must be lowercase ASCII letters, digits, and hyphens only, max 50 chars.
|
|
72
|
+
|
|
73
|
+
**For non-English ideas (Chinese, Japanese, etc.):** always pass
|
|
74
|
+
\`--change <your-english-slug>\`. The auto-generated slug from non-ASCII
|
|
75
|
+
input will be a random string like \`change-mq1r8sxt-l6be\`.
|
|
76
|
+
|
|
77
|
+
That's it. The CLI creates the directory, writes context.json with correct
|
|
78
|
+
schema, enforces atomic writes, and stamps \`completedAt\`.
|
|
79
|
+
|
|
80
|
+
## What happens if you skip Phase 1 (anti-pattern)
|
|
81
|
+
|
|
82
|
+
\`\`\`bash
|
|
83
|
+
# WRONG — bare explore, no --change, no --domains, no --context
|
|
84
|
+
$ specdo explore '我要开发一个博客系统'
|
|
85
|
+
# → Change captured: change-mq1r8sxt-l6be (random slug!)
|
|
86
|
+
# → No domains matched (Chinese input, auto-score returned zero)
|
|
87
|
+
# → depth: shallow (no --context provided)
|
|
88
|
+
# → propose will warn: "Explore depth is shallow"
|
|
89
|
+
# → Result: garbage change that must be deleted and restarted
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
If you already ran bare explore, fix it:
|
|
93
|
+
\`\`\`bash
|
|
94
|
+
rm -rf specdo/changes/<bad-slug>
|
|
95
|
+
# Then start over: grill first, then run with --change, --domains, --context
|
|
96
|
+
\`\`\`
|
|
97
|
+
|
|
98
|
+
## CRITICAL: Only the CLI creates valid context.json
|
|
99
|
+
|
|
100
|
+
Do **not** use \`Write\`, \`mkdir\`, or \`Update\` to create or modify
|
|
101
|
+
\`specdo/changes/*/context.json\`. Hand-written files break schema validation
|
|
102
|
+
and will fail at \`propose\`, \`apply\`, \`sync\`, and \`archive\`.
|
|
103
|
+
|
|
104
|
+
## The "Grill-Me" Methodology
|
|
105
|
+
|
|
106
|
+
Interview the user relentlessly about every aspect of the plan before running
|
|
107
|
+
\`specdo explore\`. Walk down each branch of the decision tree, resolving
|
|
108
|
+
dependencies between decisions one-by-one. **For each question, provide your
|
|
109
|
+
recommended answer** based on best practices.
|
|
110
|
+
|
|
111
|
+
### How to grill
|
|
112
|
+
|
|
113
|
+
1. **ONE question at a time — this is the most important rule**: Never put
|
|
114
|
+
two \`[domain:index]\` questions in one message. After asking, STOP and
|
|
115
|
+
WAIT for the user's response. If you batch questions and the user replies
|
|
116
|
+
"B", you won't know which question they answered — the answer is lost.
|
|
117
|
+
|
|
118
|
+
2. **Start with domain questions**: From \`references/DOMAIN_DISCOVERY.md\`,
|
|
119
|
+
ask questions from each selected domain. You decide how many — **minimum
|
|
120
|
+
1 per domain**, **total ≥8 across all domains**, **maximum 10 per domain**. Go deeper (6-10 questions) on
|
|
121
|
+
domains central to the user's intent; ask only the 1-2 most critical
|
|
122
|
+
questions for peripheral domains.
|
|
123
|
+
|
|
124
|
+
3. **Go deeper within each domain**: Don't jump to another domain after one
|
|
125
|
+
question. Follow the decision tree — pick the NEXT indexed question from
|
|
126
|
+
\`DOMAIN_DISCOVERY.md\` within the same domain that becomes relevant based
|
|
127
|
+
on the user's last answer. Example: choosing Next.js opens questions about
|
|
128
|
+
deployment strategy (Vercel vs Docker), styling approach (Tailwind vs CSS
|
|
129
|
+
Modules), and data fetching (Server Components vs SWR). Chase each branch
|
|
130
|
+
until resolved before moving to the next domain. For peripheral domains,
|
|
131
|
+
the 1-2 critical questions from rule 2 are sufficient — move on when
|
|
132
|
+
those are answered.
|
|
133
|
+
|
|
134
|
+
4. **Walk the decision tree**: Identify dependencies between decisions and
|
|
135
|
+
resolve them in order. E.g., choosing Next.js affects deployment (Vercel
|
|
136
|
+
vs Docker), styling (Tailwind vs CSS Modules), data fetching (Server
|
|
137
|
+
Components vs client SWR). Chase each branch until it's resolved.
|
|
138
|
+
|
|
139
|
+
5. **Explore the codebase when relevant**: If a question can be answered by
|
|
140
|
+
reading existing code, config, or specs, explore the codebase instead of
|
|
141
|
+
asking the user.
|
|
142
|
+
|
|
143
|
+
6. **Address concerns NOW, don't defer**: Do NOT create a "flagged concerns"
|
|
144
|
+
list and push items to later stages. If you identify a gap (payment model,
|
|
145
|
+
auth strategy, scalability plan), address it immediately with the user.
|
|
146
|
+
|
|
147
|
+
### Question format protocol
|
|
148
|
+
|
|
149
|
+
Every question MUST use this format — one \`[domain:index]\` per message:
|
|
150
|
+
|
|
151
|
+
\`\`\`
|
|
152
|
+
[domain:index] Single clear question? Options if applicable.
|
|
153
|
+
|
|
154
|
+
Recommended: <your recommendation with brief reason>
|
|
155
|
+
\`\`\`
|
|
156
|
+
|
|
157
|
+
Rules:
|
|
158
|
+
- \`domain\` = the domain name (frontend, backend, security, etc.)
|
|
159
|
+
- \`index\` = the question index from DOMAIN_DISCOVERY.md
|
|
160
|
+
- Always provide your recommended answer with a brief reason
|
|
161
|
+
- After asking, STOP. Do not ask another question until the user responds.
|
|
162
|
+
|
|
163
|
+
CORRECT — one question:
|
|
164
|
+
\`\`\`
|
|
165
|
+
[frontend:0] Which framework? I recommend Next.js App Router — it gives you
|
|
166
|
+
SSG for blog posts, API routes, and excellent SEO out of the box.
|
|
167
|
+
\`\`\`
|
|
168
|
+
|
|
169
|
+
WRONG — two questions batched (causes unrecoverable ambiguity):
|
|
170
|
+
\`\`\`
|
|
171
|
+
[backend:1] User system? A/B/C
|
|
172
|
+
[backend:2] Database? A/B/C/D
|
|
173
|
+
\`\`\`
|
|
174
|
+
If the user replies "B", you CANNOT know which question they answered. The
|
|
175
|
+
answer is lost and you must re-ask both questions — wasting a full round-trip.
|
|
176
|
+
|
|
177
|
+
### When to stop grilling
|
|
178
|
+
|
|
179
|
+
You are done exploring when:
|
|
180
|
+
- Each selected domain has at least 1 question answered, **AND the total
|
|
181
|
+
across all domains reaches at least 8 questions (never stop at 3-5) —
|
|
182
|
+
unless every branch of the decision tree has been genuinely resolved
|
|
183
|
+
in fewer, in which case document the resolved decisions and proceed
|
|
184
|
+
- Every branch of the decision tree has been resolved (no open dependencies)
|
|
185
|
+
- You can describe the solution to a colleague and they'd know exactly what
|
|
186
|
+
to build without asking more questions
|
|
187
|
+
- There are zero unaddressed concerns left for later stages
|
|
188
|
+
|
|
189
|
+
A healthy explore phase typically covers **10-30 questions** across all
|
|
190
|
+
selected domains, with deeper coverage on the core 1-2 domains.
|
|
191
|
+
|
|
192
|
+
### When the user refuses grilling
|
|
193
|
+
|
|
194
|
+
If the user explicitly declines ("just do it", "don't ask, just build"),
|
|
195
|
+
acknowledge the risk and fall back to a minimal capture:
|
|
196
|
+
|
|
197
|
+
1. **Explain the trade-off**: "Without context, the proposal will be generic.
|
|
198
|
+
OK for sketching ideas, but production features need exploration."
|
|
199
|
+
2. **Run explore with what you have**:
|
|
200
|
+
\`\`\`bash
|
|
201
|
+
specdo explore '<idea>' \\
|
|
202
|
+
--change <your-english-slug> \\
|
|
203
|
+
--domains <agent-inferred-list> \\
|
|
204
|
+
--depth shallow
|
|
205
|
+
\`\`\`
|
|
206
|
+
\`--change\` must be lowercase ASCII letters, digits, and hyphens only, max 50 chars.
|
|
207
|
+
Even in degraded mode, infer at least 1-2 domains from the idea and
|
|
208
|
+
pass them via \`--domains\` — this prevents zero-domain changes when
|
|
209
|
+
auto-scoring fails on non-English input.
|
|
210
|
+
⚠️ Do **not** add \`--context\` in degraded mode — even a minimal
|
|
211
|
+
\`--context\` without explicit \`--depth shallow\` causes the CLI to
|
|
212
|
+
auto-derive \`--depth standard\`, suppressing the shallow warning at
|
|
213
|
+
propose time.
|
|
214
|
+
3. **Accept the degraded result** — \`propose\` will warn that depth is shallow.
|
|
215
|
+
|
|
216
|
+
This is a degraded path — prefer grilling whenever the user is willing.
|
|
217
|
+
|
|
218
|
+
**Note:** \`context.json\` does not record whether the user declined
|
|
219
|
+
grilling. If resuming a conversation where explore was completed in a
|
|
220
|
+
previous session, check \`explore.depth\` — a \`shallow\` depth with
|
|
221
|
+
empty \`collectedContext\` may indicate a degraded path that should be
|
|
222
|
+
accepted without re-asking.
|
|
223
|
+
|
|
224
|
+
### Anti-patterns
|
|
225
|
+
|
|
226
|
+
- **Premature propose**: Do NOT ask "Want me to proceed to propose?" after
|
|
227
|
+
only 3-5 questions. If you catch yourself about to offer propose, ask:
|
|
228
|
+
"Have I exhausted the decision tree?" If no, keep grilling.
|
|
229
|
+
- **Deferred concerns**: Do NOT create a "⚠️ Flagged concerns" list and push
|
|
230
|
+
items to propose/apply. Resolve them now.
|
|
231
|
+
- **Batched questions**: Do NOT put multiple \`[domain:index]\` questions in
|
|
232
|
+
one message. If the user replies "B", which question did they answer —
|
|
233
|
+
backend:1 or backend:2? This creates unrecoverable ambiguity and forces
|
|
234
|
+
you to re-ask, wasting a full round-trip.
|
|
235
|
+
- **Hand-writing context.json**: Do NOT use \`Write\`/\`mkdir\` to create
|
|
236
|
+
context.json manually. Only \`specdo explore\` writes a valid, atomic
|
|
237
|
+
context.json with correct schema. Hand-written files will fail downstream
|
|
238
|
+
validation and propose.
|
|
239
|
+
|
|
240
|
+
### Why focus questions but inject all domains?
|
|
241
|
+
|
|
242
|
+
During explore, you ask questions only about selected domains — this keeps
|
|
243
|
+
the user focused and avoids overwhelming them with 48 questions across all
|
|
244
|
+
6 domains. But when artifacts are generated downstream, **ALL 6 domains'
|
|
245
|
+
checklists are injected** — into design.md and tasks.md at propose time.
|
|
246
|
+
At apply time, domains are matched dynamically per task via signal scoring
|
|
247
|
+
against the current task title, falling back to the domains used during
|
|
248
|
+
propose. (See \`specdo-apply\` for the full \`implement\` clause injection logic.)
|
|
249
|
+
|
|
250
|
+
This ensures every production-grade concern (security, architecture,
|
|
251
|
+
operations, backend, quality, frontend) gets reviewed in the generated
|
|
252
|
+
artifacts — even domains the user didn't discuss explicitly during explore.
|
|
253
|
+
The \`--domains\` flag controls only **which domains to ask questions about**,
|
|
254
|
+
not which domain checklists are injected at propose/apply time.
|
|
255
|
+
|
|
256
|
+
## When to use
|
|
257
|
+
|
|
258
|
+
- The user describes a new feature, refactor, bug fix, or migration and has
|
|
259
|
+
described a concrete change — at least 2 proactive-detection signals or
|
|
260
|
+
≥10 words describing the target behaviour/outcome. (See Proactive
|
|
261
|
+
Detection below for the full signal table.)
|
|
262
|
+
- Before any \`specdo propose\` or \`specdo apply\` invocation.
|
|
263
|
+
- Trigger phrases: "let's plan X", "new feature Y", "capture this idea",
|
|
264
|
+
"set up a change", "scaffold a proposal".
|
|
265
|
+
|
|
266
|
+
## When NOT to use
|
|
267
|
+
|
|
268
|
+
- Do NOT run explore with just a one-line vague idea and immediately
|
|
269
|
+
proceed to propose. This produces low-quality generic templates.
|
|
270
|
+
- If the user's input is too short or vague (< 2 proactive detection
|
|
271
|
+
signals AND < 10 words describing target outcome) — ask one clarifying
|
|
272
|
+
question to understand what they want to build, then proceed to Grill-Me
|
|
273
|
+
when the intent is concrete enough for domain selection.
|
|
274
|
+
|
|
275
|
+
## Proactive explore detection
|
|
276
|
+
|
|
277
|
+
**Even without an explicit trigger phrase, recognize when the user is
|
|
278
|
+
describing a new requirement and light-weight suggest explore.**
|
|
279
|
+
|
|
280
|
+
### Signals to watch for
|
|
281
|
+
|
|
282
|
+
Watch for these natural-language patterns during any conversation:
|
|
283
|
+
|
|
284
|
+
| Pattern | Example |
|
|
285
|
+
|---------|---------|
|
|
286
|
+
| Feature wish | "I wish it could...", "It should be able to...", "Can we add..." |
|
|
287
|
+
| Pain point | "Every time I have to manually...", "This is broken when..." |
|
|
288
|
+
| Gap description | "We're missing...", "There's no way to...", "We don't handle..." |
|
|
289
|
+
| Future intent | "Eventually we'll need...", "Down the road...", "Phase 2 should..." |
|
|
290
|
+
| Edge case concern | "What happens if the user...", "What about when..." |
|
|
291
|
+
|
|
292
|
+
### Decision flow
|
|
293
|
+
|
|
294
|
+
When you detect ≥2 signals in a single exchange (the user's most recent
|
|
295
|
+
message, or up to 3 consecutive messages without agent interruption)
|
|
296
|
+
AND the idea is concrete
|
|
297
|
+
(≥10 words describing a behaviour or outcome):
|
|
298
|
+
|
|
299
|
+
1. **Acknowledge the idea** — "That sounds like a meaningful change."
|
|
300
|
+
2. **Offer, don't force** — "Want me to capture this with \`specdo explore\`
|
|
301
|
+
so we don't lose track of it?"
|
|
302
|
+
3. **If yes** — switch into the full Grill-Me workflow.
|
|
303
|
+
4. **If no** — continue the current task without interruption.
|
|
304
|
+
|
|
305
|
+
### When NOT to suggest
|
|
306
|
+
|
|
307
|
+
- The user is asking a question, not describing a requirement
|
|
308
|
+
- It's a trivial one-line fix (typo, rename, config tweak)
|
|
309
|
+
- You're mid-debugging and the user hasn't finished diagnosing
|
|
310
|
+
- The user is clearly brainstorming without intent to act
|
|
311
|
+
|
|
312
|
+
### Example
|
|
313
|
+
|
|
314
|
+
> User: "Hmm, every time I add a new API route I forget to wire up the
|
|
315
|
+
> rate limiter. It would be nice if the scaffold did that automatically."
|
|
316
|
+
>
|
|
317
|
+
> Agent: "That sounds like a worthwhile improvement. Want me to capture
|
|
318
|
+
> this as a change with \`specdo explore\` so we can spec out the scaffold
|
|
319
|
+
> enhancement properly?"
|
|
320
|
+
>
|
|
321
|
+
> User: "Sure, let's do that."
|
|
322
|
+
>
|
|
323
|
+
> Agent: [enters Grill-Me workflow...]
|
|
324
|
+
|
|
325
|
+
## What it produces
|
|
326
|
+
|
|
327
|
+
- A new \`specdo/changes/<name>/\` directory
|
|
328
|
+
- \`context.json\` (schema v2) with \`explore.matchedDomains\`, \`answers\`,
|
|
329
|
+
\`collectedContext\`, \`depth\`, \`flaggedConcerns\`, and \`completedAt\`
|
|
330
|
+
|
|
331
|
+
## Depth levels
|
|
332
|
+
|
|
333
|
+
| Level | Meaning |
|
|
334
|
+
|-------|---------|
|
|
335
|
+
| \`shallow\` | Idea captured but minimal domain context. \`propose\` will warn. |
|
|
336
|
+
| \`standard\` | Domains selected, clarifying questions answered, reasonable context. |
|
|
337
|
+
| \`deep\` | All domain questions answered, thorough context, code/spec reviewed. |
|
|
338
|
+
|
|
339
|
+
Self-assess honestly. If you only have a one-line idea and no domain answers,
|
|
340
|
+
your depth is \`shallow\`. Set \`--depth standard\` only when you have done
|
|
341
|
+
real discovery work.
|
|
342
|
+
|
|
343
|
+
If you omit \`--depth\`, the CLI auto-derives it: \`standard\` when both
|
|
344
|
+
\`--domains\` and \`--context\` are provided, otherwise \`shallow\`.
|
|
345
|
+
|
|
346
|
+
## LLM mode (dynamic question generation)
|
|
347
|
+
|
|
348
|
+
For complex or deeply customized changes, use \`--llm\` to generate tailored
|
|
349
|
+
questions instead of the offline pool ranking:
|
|
350
|
+
|
|
351
|
+
\`\`\`bash
|
|
352
|
+
# Step 1: emit LLM prompt
|
|
353
|
+
specdo explore '<idea>' --domains backend,security --llm
|
|
354
|
+
|
|
355
|
+
# Step 2: feed the ---SPECDO_LLM_PROMPT--- JSON to an LLM.
|
|
356
|
+
# The payload includes domain signals, descriptions, and the user's idea.
|
|
357
|
+
# Instruct the LLM: "Generate 5-10 clarifying questions per domain,
|
|
358
|
+
# specific to this idea and the domain signal taxonomy."
|
|
359
|
+
|
|
360
|
+
# Step 3: inject LLM-generated questions
|
|
361
|
+
specdo explore '<idea>' \\
|
|
362
|
+
--domains backend,security \\
|
|
363
|
+
--llm-questions '{"security":["Q1?","Q2?"],"backend":["Q3?","Q4?"]}'
|
|
364
|
+
\`\`\`
|
|
365
|
+
|
|
366
|
+
Full protocol in \`references/REFERENCE.md\`.
|
|
367
|
+
|
|
368
|
+
## See also
|
|
369
|
+
|
|
370
|
+
- [\`references/REFERENCE.md\`](references/REFERENCE.md) — full flag matrix,
|
|
371
|
+
exit codes, recovery, LLM mode protocol
|
|
372
|
+
- [\`references/EXAMPLES.md\`](references/EXAMPLES.md) — annotated sample
|
|
373
|
+
sessions
|
|
374
|
+
- [\`references/DOMAIN_DISCOVERY.md\`](references/DOMAIN_DISCOVERY.md) —
|
|
375
|
+
all 6 domains with signals, pool metadata, and clarifying questions
|
|
376
|
+
|
|
377
|
+
## Recovery
|
|
378
|
+
|
|
379
|
+
| Situation | Action |
|
|
380
|
+
|-----------|--------|
|
|
381
|
+
| Bare explore produced garbage change | \`rm -rf specdo/changes/<bad-slug>\` and restart with proper grilling |
|
|
382
|
+
| Wrong slug / wrong domains | Re-run \`specdo explore '<idea>' --change <correct-slug> --domains <list>\` |
|
|
383
|
+
| Explore depth stuck at shallow | Re-run with \`--context '<richer-summary>' --depth standard\` |
|
|
384
|
+
| User refused grilling, proposal is generic | Accept degraded result; proceed to propose with shallow depth accepted |
|
|
385
|
+
|
|
386
|
+
## Next step
|
|
387
|
+
|
|
388
|
+
Once \`explore.completedAt\` is set and \`depth\` is at least \`standard\`,
|
|
389
|
+
run \`specdo propose --change <name>\`. If \`depth\` is \`shallow\`, collect
|
|
390
|
+
more context and re-run explore before proposing — unless the user
|
|
391
|
+
explicitly declined grilling, in which case the degraded shallow path
|
|
392
|
+
is accepted and you may proceed to propose.
|
|
393
|
+
`;
|
|
394
|
+
const EXPLORE_REFERENCE = `# specdo explore — Reference
|
|
395
|
+
|
|
396
|
+
## Full command matrix
|
|
397
|
+
|
|
398
|
+
| Form | Use case |
|
|
399
|
+
|------|----------|
|
|
400
|
+
| \`specdo explore '<idea>'\` | Auto-scored domains via signal matching (may be inaccurate for non-English) |
|
|
401
|
+
| \`specdo explore '<idea>' --domains <list>\` | **Recommended**: agent selects domains, bypasses auto-scoring |
|
|
402
|
+
| \`specdo explore '<idea>' --change <slug> --domains <list> --context '<text>'\` | Full agent-driven discovery with collected context |
|
|
403
|
+
| \`specdo explore '<idea>' --domains <list> --depth standard\` | Explicitly mark explore as well-prepared |
|
|
404
|
+
| \`specdo explore '<idea>' --domains <list> --depth deep\` | Mark the change as thoroughly explored — all questions answered, highest confidence |
|
|
405
|
+
| \`specdo explore '<idea>' --domains <list> --llm\` | Emit LLM prompt for tailored question generation |
|
|
406
|
+
| \`specdo explore '<idea>' --domains <list> --llm-questions '<json>'\` | Inject LLM-generated questions, bypassing pool ranking |
|
|
407
|
+
| \`specdo explore '<idea>' --non-interactive --answers '{...}'\` | CI mode: preset answers as JSON \`{"<domain>:<index>":"<text>"}\` |
|
|
408
|
+
|
|
409
|
+
## New flags (agent-driven explore)
|
|
410
|
+
|
|
411
|
+
- \`--domains <list>\` — Comma-separated domain names to **focus questions on**
|
|
412
|
+
during explore (e.g. \`frontend,backend\`). When provided, \`scoreDomains()\`
|
|
413
|
+
is bypassed. Each named domain gets score 1.0 and reason "Agent-selected
|
|
414
|
+
via --domains". Unknown domain names cause exit code 2.
|
|
415
|
+
**Note**: \`--domains\` controls only which domains you ask questions about.
|
|
416
|
+
All 6 domains' checklists are still injected at propose/apply time for
|
|
417
|
+
production-grade completeness.
|
|
418
|
+
- \`--context <text>\` — Free-text summary of discovery context collected
|
|
419
|
+
by the agent. Written to \`explore.collectedContext\`.
|
|
420
|
+
- \`--depth <level>\` — Self-assessed depth: \`shallow\`, \`standard\`,
|
|
421
|
+
or \`deep\`. Default is auto-derived: \`standard\` when both \`--domains\`
|
|
422
|
+
and \`--context\` are provided, otherwise \`shallow\`.
|
|
423
|
+
- \`--llm\` — Enable LLM-driven question generation. Emits a structured
|
|
424
|
+
JSON prompt to stdout that you feed to an LLM to generate context-specific
|
|
425
|
+
questions. The LLM response is ingested via \`--llm-questions\`.
|
|
426
|
+
- \`--llm-questions <json>\` — Inject LLM-generated questions as a JSON
|
|
427
|
+
object \`{"<domain>":["Q1","Q2"]}\`. These questions replace the default
|
|
428
|
+
pool ranking for the named domains. Cached in \`context.json\` under
|
|
429
|
+
\`explore.llmQuestions\` to avoid regeneration on re-explore.
|
|
430
|
+
|
|
431
|
+
## LLM mode workflow
|
|
432
|
+
|
|
433
|
+
When the user's idea is complex or domain coverage needs deep customization,
|
|
434
|
+
use the LLM mode to generate tailored questions instead of the default offline
|
|
435
|
+
pool ranking:
|
|
436
|
+
|
|
437
|
+
1. Run \`specdo explore '<idea>' --domains <list> --llm\`
|
|
438
|
+
2. Parse the \`---SPECDO_LLM_PROMPT---\` block from stdout. It contains:
|
|
439
|
+
- \`idea\` — the user's original input
|
|
440
|
+
- \`domains\` — selected domains with full signal taxonomies and descriptions
|
|
441
|
+
- \`existingAnswers\` — empty (first call) or pre-collected answers
|
|
442
|
+
3. Call an LLM with this payload. The system prompt should instruct the LLM to
|
|
443
|
+
generate 5-10 clarifying questions per domain, tailored to the user's idea
|
|
444
|
+
and the domain's signal taxonomy. Questions should be specific, not generic.
|
|
445
|
+
4. Re-run: \`specdo explore '<idea>' --domains <list> --llm-questions '<json>'\`
|
|
446
|
+
with the LLM's response. The CLI stores the questions in \`context.json\` and
|
|
447
|
+
uses them in the interactive loop instead of pool ranking.
|
|
448
|
+
5. If \`--llm\` is used without \`--llm-questions\`, the CLI falls back to the
|
|
449
|
+
offline question pool for all domains and logs a warning.
|
|
450
|
+
|
|
451
|
+
## Slug rules
|
|
452
|
+
|
|
453
|
+
- Derived from idea text: lowercase, alphanumerics + hyphens, max 50 chars
|
|
454
|
+
- Non-ASCII input (Chinese, Japanese, etc.) produces a random fallback slug
|
|
455
|
+
(e.g. \`change-<timestamp>-<random>\`). Always pass \`--change <slug>\`
|
|
456
|
+
for non-English ideas to get a meaningful name.
|
|
457
|
+
- Collisions resolved by appending \`-2\`, \`-3\`, ... (never overwrite)
|
|
458
|
+
- Pass \`--change <slug>\` to force a specific name
|
|
459
|
+
|
|
460
|
+
## Exit codes
|
|
461
|
+
|
|
462
|
+
- \`0\` — explore stage stored; \`completedAt\` set (also emitted for \`--llm\` prompt mode)
|
|
463
|
+
- \`1\` — workspace not initialized (\`specdo/config.yaml\` missing), idea string empty, invalid --change name, invalid \`--answers\` JSON, or change directory already exists without explicit \`--change\`
|
|
464
|
+
- \`2\` — unknown domain name in \`--domains\`, invalid \`--llm-questions\` JSON, or payload exceeds size limit
|
|
465
|
+
- \`3\` — filesystem write failure (e.g. \`specdo/changes/\` not writable)
|
|
466
|
+
|
|
467
|
+
## Domain injection modes
|
|
468
|
+
|
|
469
|
+
\`--domains\` controls which domains to **ask questions about** during
|
|
470
|
+
explore. At propose time, **all 6 domains' checklists are always
|
|
471
|
+
injected** into design.md and tasks.md for production-grade completeness.
|
|
472
|
+
At apply time, domain focus is selected dynamically per task via signal
|
|
473
|
+
matching against the task title.
|
|
474
|
+
|
|
475
|
+
1. **Agent-driven** (\`--domains <list>\`): You select which domains to focus
|
|
476
|
+
questions on. The explore phase is shorter and more focused.
|
|
477
|
+
2. **Auto-scored** (no \`--domains\`): \`scoreDomains()\` runs signal matching
|
|
478
|
+
to suggest focus domains. May produce zero matches for non-English input.
|
|
479
|
+
When zero matches occur, the CLI suggests using \`--domains\`.
|
|
480
|
+
|
|
481
|
+
## Recovery
|
|
482
|
+
|
|
483
|
+
| Situation | Action |
|
|
484
|
+
|-----------|--------|
|
|
485
|
+
| Wrong slug | \`rm -rf specdo/changes/<wrong>\` and re-run with \`--change <right>\` |
|
|
486
|
+
| Wrong domains | Re-run \`specdo explore '<idea>' --change <name> --domains <correct-list>\` |
|
|
487
|
+
| Shallow explore | Re-run with \`--context '<richer-summary>' --depth standard\` |
|
|
488
|
+
| Stuck mid-prompt | Ctrl-C; \`context.json\` will not exist; re-run from scratch |
|
|
489
|
+
|
|
490
|
+
## Schema reference
|
|
491
|
+
|
|
492
|
+
See [\`src/core/json-schemas.ts\`](../../../../src/core/json-schemas.ts) for
|
|
493
|
+
the Zod schema validating \`context.json\` at every stage.
|
|
494
|
+
`;
|
|
495
|
+
const EXPLORE_EXAMPLES = `# specdo explore — Examples
|
|
496
|
+
|
|
497
|
+
## Session 1: the "Grill-Me" workflow (recommended)
|
|
498
|
+
|
|
499
|
+
> User: "I want to build a blog website."
|
|
500
|
+
|
|
501
|
+
The agent reads \`references/DOMAIN_DISCOVERY.md\`, selects domains, then
|
|
502
|
+
grills the user relentlessly — **one question at a time** — before calling
|
|
503
|
+
explore:
|
|
504
|
+
|
|
505
|
+
\`\`\`
|
|
506
|
+
Agent: I've read the domain catalogue. Based on "blog website", I recommend
|
|
507
|
+
selecting frontend (UI, rendering, styling) and architecture (system
|
|
508
|
+
design, data flow). Does that cover your scope, or should I add
|
|
509
|
+
backend (CMS/API) or operations (deployment)?
|
|
510
|
+
|
|
511
|
+
User: Add backend too — I want a custom API.
|
|
512
|
+
|
|
513
|
+
Agent: Got it: frontend, architecture, backend.
|
|
514
|
+
[frontend:0] Which framework do you prefer? I recommend Next.js App
|
|
515
|
+
Router — it gives you SSG for blog posts and easy API routes.
|
|
516
|
+
|
|
517
|
+
User: Next.js is fine.
|
|
518
|
+
|
|
519
|
+
Agent: [frontend:1] What styling approach? Tailwind CSS is the default for
|
|
520
|
+
rapid UI with design tokens. Or do you have a design system in mind?
|
|
521
|
+
|
|
522
|
+
User: Tailwind.
|
|
523
|
+
|
|
524
|
+
Agent: [architecture:0] Where will blog content live? I recommend Markdown
|
|
525
|
+
files in the repo (no CMS needed for a personal blog). This keeps
|
|
526
|
+
everything version-controlled and deployable as static pages.
|
|
527
|
+
|
|
528
|
+
User: Yes, Markdown files.
|
|
529
|
+
|
|
530
|
+
Agent: [architecture:1] How will you handle images in posts? Options:
|
|
531
|
+
(a) same repo under public/, (b) external CDN, (c) Vercel Blob.
|
|
532
|
+
I recommend (a) for simplicity.
|
|
533
|
+
|
|
534
|
+
User: Option a.
|
|
535
|
+
|
|
536
|
+
Agent: [backend:0] Do you need a database, or is filesystem + Markdown
|
|
537
|
+
enough? For a personal blog, no DB is simpler and faster.
|
|
538
|
+
|
|
539
|
+
User: No database needed.
|
|
540
|
+
|
|
541
|
+
Agent: [backend:1] Comments system? None (static), third-party (Giscus/Disqus),
|
|
542
|
+
or custom? I recommend Giscus — free, GitHub-backed, no DB.
|
|
543
|
+
|
|
544
|
+
User: Giscus sounds good.
|
|
545
|
+
|
|
546
|
+
// ... continues for ~20 more questions across all domains ...
|
|
547
|
+
|
|
548
|
+
Agent: I've exhausted the decision tree. Summary:
|
|
549
|
+
- Next.js App Router + Tailwind, Markdown in repo, Giscus comments
|
|
550
|
+
- No DB, no CMS, images in public/, Vercel deployment
|
|
551
|
+
- RSS feed, code highlighting, tag-based navigation
|
|
552
|
+
- No auth needed (static site), no real-time features
|
|
553
|
+
Ready to record. Running specdo explore...
|
|
554
|
+
\`\`\`
|
|
555
|
+
|
|
556
|
+
\`\`\`bash
|
|
557
|
+
$ specdo explore 'Build a Markdown-driven blog website' \\
|
|
558
|
+
--change build-blog-website \\
|
|
559
|
+
--domains frontend,architecture,backend \\
|
|
560
|
+
--context 'Next.js App Router + Tailwind, Markdown in repo, Giscus comments, no DB/CMS, Vercel deploy, RSS + code highlighting + tag nav, no auth, no real-time' \\
|
|
561
|
+
--depth deep
|
|
562
|
+
|
|
563
|
+
✓ Change captured: build-blog-website
|
|
564
|
+
|
|
565
|
+
Matched domains (agent-selected):
|
|
566
|
+
- frontend score=1.000 Agent-selected via --domains
|
|
567
|
+
- architecture score=1.000 Agent-selected via --domains
|
|
568
|
+
- backend score=1.000 Agent-selected via --domains
|
|
569
|
+
|
|
570
|
+
Answers: skipped (non-interactive mode without --answers) (0 entries).
|
|
571
|
+
|
|
572
|
+
Next: specdo propose --change build-blog-website
|
|
573
|
+
\`\`\`
|
|
574
|
+
|
|
575
|
+
Notice: the agent grilled the user for ~20 questions BEFORE running explore.
|
|
576
|
+
The \`--context\` flag captures the complete decision tree summary.
|
|
577
|
+
|
|
578
|
+
## Session 2: CI / non-interactive with structured answers
|
|
579
|
+
|
|
580
|
+
> Test pipeline pre-fills answers; no human typing.
|
|
581
|
+
|
|
582
|
+
\`\`\`bash
|
|
583
|
+
$ specdo explore 'Migrate session store from memory to Redis' \\
|
|
584
|
+
--change session-redis-migration \\
|
|
585
|
+
--domains backend,operations \\
|
|
586
|
+
--non-interactive \\
|
|
587
|
+
--answers '{"backend:0":"Redis 7 with persistence","operations:0":"blue/green"}' \\
|
|
588
|
+
--depth standard
|
|
589
|
+
|
|
590
|
+
✓ Change captured: session-redis-migration
|
|
591
|
+
|
|
592
|
+
Matched domains (agent-selected):
|
|
593
|
+
- backend score=1.000 Agent-selected via --domains
|
|
594
|
+
- operations score=1.000 Agent-selected via --domains
|
|
595
|
+
|
|
596
|
+
Answers: preset (from --answers JSON) (2 entries).
|
|
597
|
+
|
|
598
|
+
Next: specdo propose --change session-redis-migration
|
|
599
|
+
\`\`\`
|
|
600
|
+
|
|
601
|
+
## Session 3: auto-scored fallback (not recommended for non-English)
|
|
602
|
+
|
|
603
|
+
\`\`\`bash
|
|
604
|
+
$ specdo explore 'Add rate limiting to the public API'
|
|
605
|
+
✓ Change captured: add-rate-limiting-to-the-public-api
|
|
606
|
+
|
|
607
|
+
Matched domains (by score):
|
|
608
|
+
- backend score=0.235 Matched 3 signals: api, rate limiting, ...
|
|
609
|
+
|
|
610
|
+
[backend] What data store backs the change?
|
|
611
|
+
> Redis for counters
|
|
612
|
+
|
|
613
|
+
Answers: collected interactively (pool ranked) (1 entries).
|
|
614
|
+
|
|
615
|
+
Next: specdo propose --change add-rate-limiting-to-the-public-api
|
|
616
|
+
\`\`\`
|
|
617
|
+
|
|
618
|
+
Notice: auto-scored mode works for English input but may miss domains or
|
|
619
|
+
return zero matches for non-English. Prefer \`--domains\` for reliability.
|
|
620
|
+
|
|
621
|
+
## Anti-pattern: one-line idea directly to propose
|
|
622
|
+
|
|
623
|
+
\`\`\`bash
|
|
624
|
+
$ # WRONG — too shallow, no domain context
|
|
625
|
+
$ specdo explore 'build a blog'
|
|
626
|
+
$ specdo propose --change build-a-blog
|
|
627
|
+
# → Warning: Explore depth is "shallow" — context may be insufficient.
|
|
628
|
+
\`\`\`
|
|
629
|
+
|
|
630
|
+
The fix: re-run explore with \`--domains\`, \`--context\`, and \`--depth standard\`.
|
|
631
|
+
|
|
632
|
+
## Anti-pattern: hand-writing context.json breaks the pipeline
|
|
633
|
+
|
|
634
|
+
\`\`\`bash
|
|
635
|
+
# WRONG — agent bypasses CLI, hand-writes everything
|
|
636
|
+
$ mkdir -p specdo/changes/my-change
|
|
637
|
+
$ Write context.json with hand-crafted matchedDomains as object {frontend: 9}
|
|
638
|
+
$ Write proposal.md, design.md, tasks.md, specs/*.md by hand
|
|
639
|
+
$ specdo validate --change my-change
|
|
640
|
+
# → Error: schema validation failed. matchedDomains must be array, not object.
|
|
641
|
+
# → Missing required fields: domainsUsed, capabilities, collectedContext, depth.
|
|
642
|
+
# → context.json is irrecoverable. Must rm -rf the change directory and restart.
|
|
643
|
+
|
|
644
|
+
# CORRECT — always run the CLI
|
|
645
|
+
$ specdo explore 'my idea' --change my-change --domains backend --depth standard
|
|
646
|
+
$ specdo propose --change my-change
|
|
647
|
+
\`\`\`
|
|
648
|
+
`;
|
|
649
|
+
// ─── specdo-propose ────────────────────────────────────────────
|
|
650
|
+
const PROPOSE_BODY = `# specdo propose
|
|
651
|
+
|
|
652
|
+
## How to use this skill (do exactly this)
|
|
653
|
+
|
|
654
|
+
\`\`\`bash
|
|
655
|
+
specdo propose --change <name> # safe; skips existing handwritten artifacts
|
|
656
|
+
specdo propose --change <name> --force # overwrite user-modified artifacts
|
|
657
|
+
\`\`\`
|
|
658
|
+
|
|
659
|
+
The CLI reads context.json, renders all 4 artifacts with domain checklists
|
|
660
|
+
injected, and validates the schema automatically. Do **not** hand-write
|
|
661
|
+
\`proposal.md\`, \`design.md\`, \`tasks.md\`, or \`specs/*.md\` — the
|
|
662
|
+
renderer injects domain knowledge you cannot replicate manually.
|
|
663
|
+
|
|
664
|
+
**Note:** \`propose\` does **not** accept \`--domains\`. The \`--domains\`
|
|
665
|
+
flag is only for \`specdo explore\`. \`propose\` always injects all 6
|
|
666
|
+
domains' checklists regardless of which domains were explored.
|
|
667
|
+
|
|
668
|
+
**CRITICAL: Never silently use \`--force\`.** Always ask the user whether
|
|
669
|
+
to keep their edits or overwrite with generated artifacts. Only add
|
|
670
|
+
\`--force\` when the user explicitly requests overwrite.
|
|
671
|
+
|
|
672
|
+
## Overview
|
|
673
|
+
|
|
674
|
+
Render OpenSpec-aligned artifacts from the explore context: proposal.md,
|
|
675
|
+
design.md, tasks.md, and specs/<capability>/spec.md. All 6 domain checklists
|
|
676
|
+
are injected regardless of which domains were explored. Existing handwritten
|
|
677
|
+
artifacts are preserved unless \`--force\` is explicitly requested.
|
|
678
|
+
|
|
679
|
+
### Before you run — verify explore depth
|
|
680
|
+
|
|
681
|
+
Read \`specdo/changes/<name>/context.json\` and check \`explore.depth\`:
|
|
682
|
+
- \`standard\` or \`deep\` → proceed.
|
|
683
|
+
- \`shallow\` → if the user already explicitly declined grilling during
|
|
684
|
+
explore (the degraded shallow path was accepted), proceed without re-asking.
|
|
685
|
+
Otherwise, warn the user that the proposal will be generic, then
|
|
686
|
+
ask whether to (a) re-run explore with richer context or (b) accept
|
|
687
|
+
the degraded shallow path.
|
|
688
|
+
|
|
689
|
+
## When to use
|
|
690
|
+
|
|
691
|
+
- \`specdo explore --change <name>\` has set \`explore.completedAt\` and
|
|
692
|
+
\`explore.depth\` is at least \`standard\` (not \`shallow\`), unless
|
|
693
|
+
the user explicitly accepted the degraded shallow path.
|
|
694
|
+
- You have collected sufficient context during explore — at minimum, you
|
|
695
|
+
have selected domains and answered clarifying questions.
|
|
696
|
+
- Before any implementation work or \`specdo apply\` invocation.
|
|
697
|
+
- Trigger phrases: "generate the proposal", "scaffold tasks", "draft the
|
|
698
|
+
design doc", "kick off the change", "what's next for <change>".
|
|
699
|
+
|
|
700
|
+
## When NOT to use
|
|
701
|
+
|
|
702
|
+
- Do NOT run propose immediately after a shallow explore (\`depth: shallow\`),
|
|
703
|
+
*unless* the user explicitly accepted the degraded shallow path during
|
|
704
|
+
explore. The resulting templates will be generic and low-quality. Instead,
|
|
705
|
+
re-run explore with richer \`--context\` and proper \`--domains\`.
|
|
706
|
+
|
|
707
|
+
## After propose runs
|
|
708
|
+
|
|
709
|
+
Read each generated artifact and supplement with the context you
|
|
710
|
+
collected during discovery:
|
|
711
|
+
- \`proposal.md\`: add specific details to scope and risks sections.
|
|
712
|
+
- \`design.md\`: inject architecture decisions discussed in explore.
|
|
713
|
+
- \`tasks.md\`: refine task descriptions based on domain choices.
|
|
714
|
+
Use the file editing tool to insert content inline — never regenerate
|
|
715
|
+
artifacts manually. Do **not** skip directly to apply without
|
|
716
|
+
reviewing \`proposal.md\`, \`design.md\`, and \`tasks.md\`.
|
|
717
|
+
|
|
718
|
+
## What it produces
|
|
719
|
+
|
|
720
|
+
\`\`\`
|
|
721
|
+
specdo/changes/<name>/
|
|
722
|
+
├── proposal.md # why + scope + risks
|
|
723
|
+
├── specs/
|
|
724
|
+
│ └── <capability>/spec.md # behaviour contracts (the source of truth post-sync)
|
|
725
|
+
├── design.md # how (domain design.checklist injected)
|
|
726
|
+
└── tasks.md # ordered, numbered task list (drives apply)
|
|
727
|
+
\`\`\`
|
|
728
|
+
|
|
729
|
+
## Quality warning
|
|
730
|
+
|
|
731
|
+
If propose outputs "Explore depth is shallow", the generated artifacts
|
|
732
|
+
will be generic templates with minimal domain-specific guidance. Return
|
|
733
|
+
to explore and collect more context before proceeding — unless the user
|
|
734
|
+
explicitly declined grilling during explore (degraded shallow path
|
|
735
|
+
accepted), in which case you may proceed with the caveat that artifacts
|
|
736
|
+
will be generic.
|
|
737
|
+
|
|
738
|
+
## See also
|
|
739
|
+
|
|
740
|
+
- [\`references/REFERENCE.md\`](references/REFERENCE.md) — flag matrix, exit
|
|
741
|
+
codes, conflict handling
|
|
742
|
+
- [\`references/EXAMPLES.md\`](references/EXAMPLES.md) — sample artifact
|
|
743
|
+
layout and the \`--force\` recovery dance
|
|
744
|
+
|
|
745
|
+
## Recovery
|
|
746
|
+
|
|
747
|
+
| Situation | Action |
|
|
748
|
+
|-----------|--------|
|
|
749
|
+
| Explore depth is shallow | Warn user; either re-run explore with richer context or accept degraded path |
|
|
750
|
+
| Hand-edited artifact was skipped | Review stderr warnings; keep file as source of truth or re-run with \`--force\` |
|
|
751
|
+
| Wrong domain matches in generated artifacts | Re-run \`specdo explore '<idea>' --change <name>\` to re-score, then \`propose --change <name> --force\` |
|
|
752
|
+
| Mixed spec layout detected | Resolve by normalizing to capability folders, then re-run with \`--force\` |
|
|
753
|
+
|
|
754
|
+
## Next step
|
|
755
|
+
|
|
756
|
+
Run \`specdo apply --change <name>\` to render the execution brief and start
|
|
757
|
+
TDD-disciplined task work.
|
|
758
|
+
`;
|
|
759
|
+
const PROPOSE_REFERENCE = `# specdo propose — Reference
|
|
760
|
+
|
|
761
|
+
## Full command matrix
|
|
762
|
+
|
|
763
|
+
| Form | Use case |
|
|
764
|
+
|------|----------|
|
|
765
|
+
| \`specdo propose --change <name>\` | Safe default; writes missing/generated artifacts and skips existing handwritten ones with stderr warnings |
|
|
766
|
+
| \`specdo propose --change <name> --force\` | Overwrite user-modified artifacts and normalize legacy / mixed spec layouts before task progress exists |
|
|
767
|
+
|
|
768
|
+
## Required preconditions
|
|
769
|
+
|
|
770
|
+
- \`specdo/changes/<name>/context.json\` exists with \`explore.completedAt\` non-null
|
|
771
|
+
- Workspace passes \`specdo validate\` (config.yaml parses, no schema drift)
|
|
772
|
+
|
|
773
|
+
## Exit codes
|
|
774
|
+
|
|
775
|
+
- \`0\` — all artifacts rendered; \`propose.completedAt\` set
|
|
776
|
+
- \`1\` — change not found, workspace invalid, no explore stage, explore
|
|
777
|
+
in-progress (\`--llm\` mode), mixed spec layout detected, or legacy-layout
|
|
778
|
+
upgrade blocked by existing execution progress
|
|
779
|
+
- \`3\` — filesystem write failure
|
|
780
|
+
|
|
781
|
+
## What gets injected per domain
|
|
782
|
+
|
|
783
|
+
| Artifact | Injected content |
|
|
784
|
+
|----------|------------------|
|
|
785
|
+
| \`design.md\` | \`domain.design.checklist\` + \`patterns\` + \`antiPatterns\` for every domain (all 6 are always injected) |
|
|
786
|
+
| \`specs/<capability>/spec.md\` | OpenSpec-style requirement/scenario scaffold; behaviour to be authored by user |
|
|
787
|
+
| \`tasks.md\` | numbered list with empty evidence slots, ordered for TDD |
|
|
788
|
+
| \`proposal.md\` | summary + risks + matched-domain rationale |
|
|
789
|
+
|
|
790
|
+
## Conflict semantics
|
|
791
|
+
|
|
792
|
+
When the user has already edited a file:
|
|
793
|
+
|
|
794
|
+
- Without \`--force\`: each existing non-empty handwritten artifact is skipped
|
|
795
|
+
individually with a warning on stderr; generated-looking placeholders can
|
|
796
|
+
still be refreshed in the same run.
|
|
797
|
+
- With \`--force\`: rendered artifacts are overwritten in place.
|
|
798
|
+
- Legacy flat specs (\`specs/foo.md\`) are preserved as-is on a normal re-run
|
|
799
|
+
to avoid creating a mixed layout. Upgrading them to
|
|
800
|
+
\`specs/<capability>/spec.md\` requires \`--force\`, and is rejected once
|
|
801
|
+
any task progress or evidence exists.
|
|
802
|
+
- If the change already contains both legacy flat specs and capability folders,
|
|
803
|
+
\`propose\` stops with "mixed spec layout detected" until the user resolves
|
|
804
|
+
it or explicitly normalizes with \`--force\`.
|
|
805
|
+
|
|
806
|
+
## Recovery
|
|
807
|
+
|
|
808
|
+
| Situation | Action |
|
|
809
|
+
|-----------|--------|
|
|
810
|
+
| Existing handwritten artifact was skipped | Review the stderr warnings, keep the file as source of truth, or re-run with \`--force\` if you want the renderer to replace it |
|
|
811
|
+
| Legacy change needs OpenSpec capability layout | Re-run \`specdo propose --change <name> --force\` before any task is completed or evidence is recorded. Once execution progress exists, the command fails with \`Cannot upgrade legacy artifacts with existing task progress\`. |
|
|
812
|
+
| Wrong domain matches | Re-run \`specdo explore '<idea>' --change <name>\` to re-score, then \`propose --change <name> --force\` |
|
|
813
|
+
`;
|
|
814
|
+
const PROPOSE_EXAMPLES = `# specdo propose — Examples
|
|
815
|
+
|
|
816
|
+
## Session 1: clean propose after explore
|
|
817
|
+
|
|
818
|
+
\`\`\`bash
|
|
819
|
+
$ specdo propose --change rate-limiting-public-api
|
|
820
|
+
# specdo propose --change rate-limiting-public-api
|
|
821
|
+
|
|
822
|
+
Domain selection: all 6 domains (full coverage, overrides applied)
|
|
823
|
+
✓ wrote proposal.md
|
|
824
|
+
✓ wrote specs/rate-limiting-public-api/spec.md
|
|
825
|
+
✓ wrote design.md
|
|
826
|
+
✓ wrote tasks.md
|
|
827
|
+
|
|
828
|
+
Next: specdo apply --change rate-limiting-public-api
|
|
829
|
+
\`\`\`
|
|
830
|
+
|
|
831
|
+
The 6 tasks in tasks.md will look roughly like:
|
|
832
|
+
|
|
833
|
+
\`\`\`markdown
|
|
834
|
+
## 1. Spec Updates
|
|
835
|
+
|
|
836
|
+
- [ ] 1.1 Finalize 429 requirement scenarios
|
|
837
|
+
|
|
838
|
+
## 2. Backend Implementation
|
|
839
|
+
|
|
840
|
+
- [ ] 2.1 Add Redis-backed token bucket middleware
|
|
841
|
+
- [ ] 2.2 Wire middleware into the public router
|
|
842
|
+
|
|
843
|
+
## 3. Verification
|
|
844
|
+
|
|
845
|
+
- [ ] 3.1 Add metrics and rollback coverage
|
|
846
|
+
\`\`\`
|
|
847
|
+
|
|
848
|
+
## Session 2: user edited design.md, propose rejects without --force
|
|
849
|
+
|
|
850
|
+
\`\`\`bash
|
|
851
|
+
$ specdo propose --change rate-limiting-public-api
|
|
852
|
+
# (stderr) ! design.md already exists and has content. Skipping. Use --force to overwrite.
|
|
853
|
+
\`\`\`
|
|
854
|
+
|
|
855
|
+
Recommended dialog:
|
|
856
|
+
|
|
857
|
+
> Agent should ask: "design.md was edited. Should I keep that file as the
|
|
858
|
+
> source of truth, or re-generate it with \`--force\`?" — do NOT silently
|
|
859
|
+
> force an overwrite.
|
|
860
|
+
|
|
861
|
+
This run still exits \`0\`; the warning is advisory and the untouched file
|
|
862
|
+
remains the source of truth.
|
|
863
|
+
|
|
864
|
+
## Session 3: after propose, review and supplement artifacts
|
|
865
|
+
|
|
866
|
+
After \`specdo propose\` completes, read each generated artifact and
|
|
867
|
+
supplement with your discovery context before moving to apply:
|
|
868
|
+
|
|
869
|
+
\`\`\`
|
|
870
|
+
Agent: Propose complete. Let me review the generated artifacts and
|
|
871
|
+
cross-check with the context we collected during explore.
|
|
872
|
+
|
|
873
|
+
Reading proposal.md — the scope and risks look right.
|
|
874
|
+
I'll add a note about the rate-limit threshold we discussed
|
|
875
|
+
(100 req/min per IP).
|
|
876
|
+
|
|
877
|
+
Reading design.md — the middleware pattern is solid.
|
|
878
|
+
I'll note that we chose token bucket over sliding window
|
|
879
|
+
for memory efficiency.
|
|
880
|
+
|
|
881
|
+
Reading tasks.md — 6 tasks, ordered for TDD.
|
|
882
|
+
I confirm task 1.1 (spec updates) should come first since
|
|
883
|
+
we need the spec to drive the red-green cycle.
|
|
884
|
+
|
|
885
|
+
Ready for apply. Running specdo apply --change rate-limiting-public-api...
|
|
886
|
+
\`\`\`
|
|
887
|
+
|
|
888
|
+
## Anti-pattern: don't hand-edit context.json to skip propose
|
|
889
|
+
|
|
890
|
+
If \`propose.completedAt\` is missing from \`context.json\`, the right
|
|
891
|
+
recovery is to run \`specdo propose --change <name>\`, not to write
|
|
892
|
+
\`completedAt\` by hand. The renderer is the only thing that knows which
|
|
893
|
+
domains are actually injected.
|
|
894
|
+
`;
|
|
895
|
+
// ─── specdo-apply ──────────────────────────────────────────────
|
|
896
|
+
const APPLY_BODY = `# specdo apply
|
|
897
|
+
|
|
898
|
+
## How to use this skill (do exactly this)
|
|
899
|
+
|
|
900
|
+
Run the CLI for ALL task state changes:
|
|
901
|
+
|
|
902
|
+
\`\`\`bash
|
|
903
|
+
specdo apply --change <name> # (re)render brief
|
|
904
|
+
specdo apply --change <name> --done <ref> --evidence "..." # mark task ref done
|
|
905
|
+
specdo apply --change <name> --undo <ref> # revert task ref
|
|
906
|
+
\`\`\`
|
|
907
|
+
|
|
908
|
+
Do **not** hand-edit \`tasks.md\` checkboxes or \`context.json\` →
|
|
909
|
+
\`apply.tasksEvidence\`. The CLI's evidence ledger lives in \`context.json\`,
|
|
910
|
+
not \`tasks.md\`. Hand-flipping \`- [ ]\` to \`- [x]\` will be **overwritten**
|
|
911
|
+
the next time \`apply\` regenerates the brief. Always go through \`--done\` /
|
|
912
|
+
\`--undo\`.
|
|
913
|
+
|
|
914
|
+
### Typical apply loop
|
|
915
|
+
|
|
916
|
+
1. \`specdo apply --change <name>\` — render the brief, note the task refs
|
|
917
|
+
(e.g. \`1.1\`, \`2.1\`, \`3.1\`) from the generated \`apply-brief.md\`
|
|
918
|
+
2. Read \`apply-brief.md\` to find the current task ref
|
|
919
|
+
3. Implement the task, write tests, verify
|
|
920
|
+
4. \`specdo apply --change <name> --done <ref> --evidence "..."\` — mark done
|
|
921
|
+
5. Repeat steps 2-4 until all tasks complete
|
|
922
|
+
6. \`specdo sync --change <name>\` — promote specs
|
|
923
|
+
|
|
924
|
+
When all tasks are marked done, the CLI automatically sets
|
|
925
|
+
\`apply.completedAt\` in \`context.json\`. This is the gate that
|
|
926
|
+
\`specdo sync\` checks before allowing spec promotion.
|
|
927
|
+
|
|
928
|
+
## Overview
|
|
929
|
+
|
|
930
|
+
Render the execution brief for a change (with each matched domain's
|
|
931
|
+
\`implement\` clauses injected) and record per-task evidence as the user
|
|
932
|
+
completes them. This is the main loop during implementation.
|
|
933
|
+
|
|
934
|
+
## When to use
|
|
935
|
+
|
|
936
|
+
- \`specdo propose --change <name>\` has produced \`tasks.md\`.
|
|
937
|
+
- During iterative TDD work — each completed task is recorded with
|
|
938
|
+
one-line evidence.
|
|
939
|
+
- Trigger phrases: "start implementing", "I'm done with task 3", "mark
|
|
940
|
+
task 2 complete", "show me the brief", "what's next on <change>".
|
|
941
|
+
|
|
942
|
+
## When NOT to use
|
|
943
|
+
|
|
944
|
+
- Do NOT run apply when \`propose.completedAt\` is null — proposal artifacts
|
|
945
|
+
(especially \`tasks.md\`) must exist first.
|
|
946
|
+
- Do NOT hand-edit \`tasks.md\` checkboxes to simulate progress; always use
|
|
947
|
+
\`--done\` / \`--undo\` to keep the evidence ledger in \`context.json\` in sync.
|
|
948
|
+
|
|
949
|
+
## What it produces
|
|
950
|
+
|
|
951
|
+
- Goal + change metadata
|
|
952
|
+
- For each matched domain: \`implement.focusAreas\`, \`patterns\`, \`antiPatterns\`
|
|
953
|
+
- Optional protocol injection when the resolved domains plus the current task
|
|
954
|
+
activate it (for example \`review-to-solid\` on quality-heavy work) — see
|
|
955
|
+
the \`references/PROTOCOL_REVIEW_TO_SOLID.md\` guidance
|
|
956
|
+
- Task list with current completion state, hierarchical task refs (such as
|
|
957
|
+
\`1.1\` / \`2.1\`), and evidence summaries
|
|
958
|
+
|
|
959
|
+
## See also
|
|
960
|
+
|
|
961
|
+
- [\`references/REFERENCE.md\`](references/REFERENCE.md) — flag matrix, exit
|
|
962
|
+
codes, evidence formatting rules, undo semantics
|
|
963
|
+
- [\`references/EXAMPLES.md\`](references/EXAMPLES.md) — full apply loop from
|
|
964
|
+
task 1 to task N, plus the \`--undo\` correction pattern
|
|
965
|
+
|
|
966
|
+
## Recovery
|
|
967
|
+
|
|
968
|
+
| Situation | Action |
|
|
969
|
+
|-----------|--------|
|
|
970
|
+
| Task marked done with wrong evidence | \`specdo apply --change <name> --undo <ref>\`, then re-mark with correct \`--evidence\` |
|
|
971
|
+
| Hand-edited tasks.md checkbox overwritten | Always go through \`--done\` / \`--undo\`; the CLI regenerates \`apply-brief.md\` from \`context.json\` |
|
|
972
|
+
| Propose not complete (\`tasks.md\` missing) | Run \`specdo propose --change <name>\` first |
|
|
973
|
+
| Attempted undo on incomplete task | Verify the task ref; the task may already be unchecked or the wrong ref was used |
|
|
974
|
+
| Evidence too vague ("done", "ok") | Push back: "What test / commit / file demonstrates this task is complete?" |
|
|
975
|
+
|
|
976
|
+
## Next step
|
|
977
|
+
|
|
978
|
+
After every task in \`tasks.md\` is marked done, run \`specdo sync --change <name>\` to promote the per-change specs into \`specdo/specs/\`.
|
|
979
|
+
`;
|
|
980
|
+
const APPLY_REFERENCE = `# specdo apply — Reference
|
|
981
|
+
|
|
982
|
+
## Full command matrix
|
|
983
|
+
|
|
984
|
+
| Form | Use case |
|
|
985
|
+
|------|----------|
|
|
986
|
+
| \`specdo apply --change <name>\` | Render / re-render \`apply-brief.md\`; safe to run any time |
|
|
987
|
+
| \`specdo apply --change <name> --done <ref> --evidence "<text>"\` | Mark task ref (for example \`1\` or \`1.1\`) complete with a one-line evidence note |
|
|
988
|
+
| \`specdo apply --change <name> --undo <ref>\` | Revert that task ref to unchecked; deletes its evidence entry |
|
|
989
|
+
|
|
990
|
+
## Evidence formatting rules
|
|
991
|
+
|
|
992
|
+
- One line, ≤ 200 chars after trim
|
|
993
|
+
- Should name the artifact proving the task is done (test name, commit SHA,
|
|
994
|
+
file path, log excerpt). Examples:
|
|
995
|
+
- \`"middleware added in src/api/rate-limit.ts; test rate-limit.test.ts:42 passes"\`
|
|
996
|
+
- \`"docs/runbook.md §rollback updated; reviewed in PR #482"\`
|
|
997
|
+
- Avoid filler ("done", "ok", "✓") — these add no audit value
|
|
998
|
+
|
|
999
|
+
## Required preconditions
|
|
1000
|
+
|
|
1001
|
+
- \`propose.completedAt\` non-null (i.e. \`tasks.md\` exists)
|
|
1002
|
+
- Task ref in \`--done\` / \`--undo\` must match an existing task entry such
|
|
1003
|
+
as \`1\`, \`1.1\`, or \`2.3\`
|
|
1004
|
+
|
|
1005
|
+
## Exit codes
|
|
1006
|
+
|
|
1007
|
+
- \`0\` — brief rendered, or task state updated
|
|
1008
|
+
- \`1\` — change not found, propose not complete, task ref not found in
|
|
1009
|
+
tasks.md, missing / empty evidence, \`--done\`/\`--undo\` mutually exclusive,
|
|
1010
|
+
\`--evidence\` cannot be used with \`--undo\`, task already completed (use
|
|
1011
|
+
\`--undo\` first), task not completed (nothing to undo), or workspace invalid
|
|
1012
|
+
- \`2\` — invalid task ref format (non-canonical like \"01\" or \"abc\";
|
|
1013
|
+
rejected at CLI parse before \`handleApply\`)
|
|
1014
|
+
- \`3\` — filesystem write failure
|
|
1015
|
+
|
|
1016
|
+
## Protocol activation semantics
|
|
1017
|
+
|
|
1018
|
+
- Explicitly mentioning a protocol name does **not** inject it by itself
|
|
1019
|
+
- \`apply\` decides protocol injection from the resolved domain set plus the
|
|
1020
|
+
current task wording
|
|
1021
|
+
- When the quality domain is disabled from explore, quality-driven protocol
|
|
1022
|
+
injection is disabled too
|
|
1023
|
+
|
|
1024
|
+
## Brief regeneration
|
|
1025
|
+
|
|
1026
|
+
\`apply-brief.md\` is **always overwritten** on \`specdo apply --change <name>\`
|
|
1027
|
+
(no \`--force\` needed). It is a derived artifact — user edits should go into
|
|
1028
|
+
\`tasks.md\` / \`design.md\` instead.
|
|
1029
|
+
|
|
1030
|
+
## Undo semantics
|
|
1031
|
+
|
|
1032
|
+
\`--undo\` cannot be used with \`--evidence\`. To change evidence, run
|
|
1033
|
+
\`--undo <ref>\` first, then re-mark with \`--done <ref> --evidence "..."\`.
|
|
1034
|
+
|
|
1035
|
+
\`--undo <ref>\`:
|
|
1036
|
+
- Unchecks that task ref in \`tasks.md\`
|
|
1037
|
+
- Deletes \`context.json\` → \`apply.tasksEvidence["<ref>"]\` (the key is *removed*,
|
|
1038
|
+
not set to empty string — JSON shape stability matters for replay)
|
|
1039
|
+
- Does NOT touch source code (the user is responsible for reverting the work)
|
|
1040
|
+
`;
|
|
1041
|
+
const APPLY_EXAMPLES = `# specdo apply — Examples
|
|
1042
|
+
|
|
1043
|
+
## Session 1: complete loop from task 1.1 to task 3.1
|
|
1044
|
+
|
|
1045
|
+
\`\`\`bash
|
|
1046
|
+
# Render the brief once, read it, then start coding
|
|
1047
|
+
$ specdo apply --change rate-limiting-public-api
|
|
1048
|
+
# specdo apply --change rate-limiting-public-api
|
|
1049
|
+
|
|
1050
|
+
Tasks: 0/6 complete
|
|
1051
|
+
|
|
1052
|
+
Current focus: task 1.1. Finalize 429 requirement scenarios
|
|
1053
|
+
Brief written to specdo/changes/rate-limiting-public-api/apply-brief.md.
|
|
1054
|
+
|
|
1055
|
+
Mark complete with: specdo apply --change rate-limiting-public-api --done 1.1 --evidence "<...>"
|
|
1056
|
+
|
|
1057
|
+
# After writing & passing the red-then-green test for task 1
|
|
1058
|
+
$ specdo apply --change rate-limiting-public-api \\
|
|
1059
|
+
--done 1.1 \\
|
|
1060
|
+
--evidence "test rate-limit.test.ts:18 covers 429 path; passes locally"
|
|
1061
|
+
✓ Marked task 1.1 done.
|
|
1062
|
+
|
|
1063
|
+
# ...iterate for tasks 1.2 through 3.1...
|
|
1064
|
+
|
|
1065
|
+
$ specdo apply --change rate-limiting-public-api \\
|
|
1066
|
+
--done 3.1 \\
|
|
1067
|
+
--evidence "docs/runbook.md §rollback updated; reviewed in PR #482"
|
|
1068
|
+
✓ Marked task 3.1 done.
|
|
1069
|
+
|
|
1070
|
+
All tasks complete (6/6).
|
|
1071
|
+
Run 'specdo sync --change rate-limiting-public-api' then 'specdo archive --change rate-limiting-public-api' to finalize.
|
|
1072
|
+
\`\`\`
|
|
1073
|
+
|
|
1074
|
+
## Session 2: realized task 2.1 was wrong, undo + redo
|
|
1075
|
+
|
|
1076
|
+
\`\`\`bash
|
|
1077
|
+
$ specdo apply --change rate-limiting-public-api --undo 2.1
|
|
1078
|
+
✓ Reverted task 2.1 to incomplete (evidence cleared).
|
|
1079
|
+
|
|
1080
|
+
# Fix the work, then re-mark
|
|
1081
|
+
$ specdo apply --change rate-limiting-public-api \\
|
|
1082
|
+
--done 2.1 \\
|
|
1083
|
+
--evidence "router wiring fixed in src/api/router.ts; integration test:55 passes"
|
|
1084
|
+
✓ Marked task 2.1 done.
|
|
1085
|
+
\`\`\`
|
|
1086
|
+
|
|
1087
|
+
## Anti-pattern: marking done without evidence
|
|
1088
|
+
|
|
1089
|
+
\`\`\`bash
|
|
1090
|
+
$ specdo apply --change rate-limiting-public-api --done 2.1
|
|
1091
|
+
# (stderr) --evidence is required when marking done. Provide a non-empty string.
|
|
1092
|
+
\`\`\`
|
|
1093
|
+
|
|
1094
|
+
Filler evidence ("done", "ok") is allowed by the CLI but defeats the audit
|
|
1095
|
+
trail. Agent should push back: "What test / commit / file demonstrates this
|
|
1096
|
+
task is complete?"
|
|
1097
|
+
|
|
1098
|
+
## Anti-pattern: hand-editing tasks.md to flip the checkbox
|
|
1099
|
+
|
|
1100
|
+
The CLI's evidence ledger lives in \`context.json\`, not \`tasks.md\`. Hand
|
|
1101
|
+
flipping \`- [ ]\` to \`- [x]\` will be **overwritten** the next time
|
|
1102
|
+
\`apply\` regenerates the brief. Always go through \`--done\` / \`--undo\`.
|
|
1103
|
+
`;
|
|
1104
|
+
// ─── specdo-sync ───────────────────────────────────────────────
|
|
1105
|
+
const SYNC_BODY = `# specdo sync
|
|
1106
|
+
|
|
1107
|
+
## How to use this skill (do exactly this)
|
|
1108
|
+
|
|
1109
|
+
Run the CLI — never hand-copy spec files into \`specdo/specs/\`:
|
|
1110
|
+
|
|
1111
|
+
\`\`\`bash
|
|
1112
|
+
specdo sync --change <name> # safe; aborts on any conflict
|
|
1113
|
+
specdo sync --change <name> --force # clobber conflicts (stages backups in specdo/.sync-backup/)
|
|
1114
|
+
\`\`\`
|
|
1115
|
+
|
|
1116
|
+
Do **not** manually \`cp\` or \`mv\` per-change spec files into
|
|
1117
|
+
\`specdo/specs/\`. Only the CLI knows the conflict detection rules,
|
|
1118
|
+
backup staging semantics (\`specdo/.sync-backup/\`), forced-conflict
|
|
1119
|
+
hash audit, and \`sync.completedAt\` timestamping. Hand-copied files
|
|
1120
|
+
will look like "synced" but lack audit metadata, breaking archive.
|
|
1121
|
+
|
|
1122
|
+
## Overview
|
|
1123
|
+
|
|
1124
|
+
Promote a change's per-change specs (\`specdo/changes/<name>/specs/<capability>/spec.md\`) to
|
|
1125
|
+
the canonical \`specdo/specs/\` directory, detecting and reporting conflicts
|
|
1126
|
+
against any existing same-name spec.
|
|
1127
|
+
|
|
1128
|
+
## What it produces
|
|
1129
|
+
|
|
1130
|
+
- Updates \`specdo/specs/<capability>/spec.md\` for each per-change spec
|
|
1131
|
+
- Writes \`context.json\` → \`sync.completedAt\` and \`sync.syncedSpecs\`
|
|
1132
|
+
- On conflict without \`--force\`: writes \`sync.conflicts\` (array of paths)
|
|
1133
|
+
- On \`--force\`: writes \`sync.forcedConflicts\` + SHA256 hashes for audit
|
|
1134
|
+
|
|
1135
|
+
## When to use
|
|
1136
|
+
|
|
1137
|
+
- Every task in \`tasks.md\` is marked done via \`specdo apply --done\`.
|
|
1138
|
+
- Before \`specdo archive\`.
|
|
1139
|
+
- Trigger phrases: "sync specs", "promote the specs", "merge change specs",
|
|
1140
|
+
"publish the spec", "spec is ready to be canonical".
|
|
1141
|
+
|
|
1142
|
+
## When NOT to use
|
|
1143
|
+
|
|
1144
|
+
- Do NOT run sync before every task in \`tasks.md\` is marked done —
|
|
1145
|
+
\`apply.completedAt\` must be non-null.
|
|
1146
|
+
- Do NOT manually \`cp\` per-change specs into \`specdo/specs/\` — only the CLI
|
|
1147
|
+
writes \`sync.completedAt\` and the audit metadata required by archive.
|
|
1148
|
+
|
|
1149
|
+
## Conflict policy
|
|
1150
|
+
|
|
1151
|
+
- Unresolved conflicts → \`sync\` exits 1 and \`archive\` will refuse to proceed.
|
|
1152
|
+
- \`--force\` records the path list as \`forcedConflicts\` plus before/after
|
|
1153
|
+
hashes. Existing canonical specs are copied into \`specdo/.sync-backup/\`
|
|
1154
|
+
before overwrite; that staging area is removed on success and preserved on
|
|
1155
|
+
partial failure for manual recovery.
|
|
1156
|
+
- **Never silently re-run with \`--force\`.** Always ask the user first:
|
|
1157
|
+
show which specs conflict, offer to diff, and let the user choose between
|
|
1158
|
+
hand-merge and deliberate overwrite. The \`--force\` audit trail is permanent
|
|
1159
|
+
and visible in \`archive-summary.md\`.
|
|
1160
|
+
|
|
1161
|
+
## Skipping sync
|
|
1162
|
+
|
|
1163
|
+
If the user needs to bypass sync (e.g. template migration, specs already
|
|
1164
|
+
promoted by hand), use \`specdo archive --change <name> --skip-sync-check\`.
|
|
1165
|
+
This records a mandatory risk note in \`archive-summary.md\`. Do NOT use
|
|
1166
|
+
\`--skip-sync-check\` silently — confirm with the user and note the reason
|
|
1167
|
+
in conversation. The CLI auto-generates the risk note; you do not need to
|
|
1168
|
+
write it yourself.
|
|
1169
|
+
|
|
1170
|
+
## See also
|
|
1171
|
+
|
|
1172
|
+
- [\`references/REFERENCE.md\`](references/REFERENCE.md) — exit codes, conflict
|
|
1173
|
+
detection internals, hash audit format
|
|
1174
|
+
- [\`references/EXAMPLES.md\`](references/EXAMPLES.md) — clean sync, dirty
|
|
1175
|
+
sync with conflicts, and the recommended \`--force\` review dialog
|
|
1176
|
+
|
|
1177
|
+
## Recovery
|
|
1178
|
+
|
|
1179
|
+
| Situation | Action |
|
|
1180
|
+
|-----------|--------|
|
|
1181
|
+
| Sync rejected (unresolved conflicts) | Show user the diff; let them choose hand-merge or \`--force\` |
|
|
1182
|
+
| Stale \`specdo/.sync-backup/\` from previous failed run | Inspect staged files, complete manual recovery, then remove the directory |
|
|
1183
|
+
| Accidental \`--force\` completed successfully | Recover prior contents from VCS or archive history; the before/after hashes are in \`archive-summary.md\` |
|
|
1184
|
+
| Apply not complete (\`completedAt\` null) | Run \`specdo apply --change <name>\` and complete all tasks first |
|
|
1185
|
+
|
|
1186
|
+
## Next step
|
|
1187
|
+
|
|
1188
|
+
When \`sync\` completes (no unresolved conflicts), run \`specdo archive
|
|
1189
|
+
--change <name>\` to finalize.
|
|
1190
|
+
`;
|
|
1191
|
+
const SYNC_REFERENCE = `# specdo sync — Reference
|
|
1192
|
+
|
|
1193
|
+
## Full command matrix
|
|
1194
|
+
|
|
1195
|
+
| Form | Use case |
|
|
1196
|
+
|------|----------|
|
|
1197
|
+
| \`specdo sync --change <name>\` | Detect conflicts; promote only when conflict-free |
|
|
1198
|
+
| \`specdo sync --change <name> --force\` | Overwrite same-name specs in \`specdo/specs/\`; existing targets are staged under \`specdo/.sync-backup/\` first |
|
|
1199
|
+
|
|
1200
|
+
## Conflict detection
|
|
1201
|
+
|
|
1202
|
+
A conflict exists when:
|
|
1203
|
+
1. \`specdo/changes/<name>/specs/<capability>/spec.md\` exists AND
|
|
1204
|
+
2. \`specdo/specs/<capability>/spec.md\` exists AND
|
|
1205
|
+
3. The two files differ (byte-equal short-circuits as "no conflict; skipped")
|
|
1206
|
+
|
|
1207
|
+
Unresolved conflicts are stored in \`context.json\` → \`sync.conflicts\`
|
|
1208
|
+
as an array of relative spec paths. \`archive\` reads this field to
|
|
1209
|
+
enforce the sync gate. When \`--force\` is used, conflicts are moved to
|
|
1210
|
+
\`sync.forcedConflicts\` and \`sync.conflicts\` is cleared.
|
|
1211
|
+
|
|
1212
|
+
## Exit codes
|
|
1213
|
+
|
|
1214
|
+
- \`0\` — all per-change specs promoted; \`sync.completedAt\` set
|
|
1215
|
+
- \`1\` — change not found, apply not complete, or unresolved conflicts present
|
|
1216
|
+
- \`3\` — filesystem write failure, write+restore failure, or a leftover
|
|
1217
|
+
\`specdo/.sync-backup/\` directory from a previous failed run
|
|
1218
|
+
|
|
1219
|
+
## \`--force\` audit fields
|
|
1220
|
+
|
|
1221
|
+
When \`--force\` is used, \`context.json\` → \`sync\` is augmented with:
|
|
1222
|
+
|
|
1223
|
+
\`\`\`json
|
|
1224
|
+
{
|
|
1225
|
+
"forced": true,
|
|
1226
|
+
"forcedConflicts": ["rate-limiting-public-api/spec.md"],
|
|
1227
|
+
"forcedConflictHashes": {
|
|
1228
|
+
"rate-limiting-public-api/spec.md": {
|
|
1229
|
+
"before": "sha256:...",
|
|
1230
|
+
"after": "sha256:..."
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
\`\`\`
|
|
1235
|
+
|
|
1236
|
+
These hashes are echoed in \`archive-summary.md\` for downstream review.
|
|
1237
|
+
|
|
1238
|
+
## Backup staging semantics
|
|
1239
|
+
|
|
1240
|
+
- Forced overwrites copy the current canonical file to
|
|
1241
|
+
\`specdo/.sync-backup/<relative-path>\`
|
|
1242
|
+
- The staging directory is removed after a successful sync
|
|
1243
|
+
- If overwrite succeeds but later writes fail, restore is attempted from
|
|
1244
|
+
\`specdo/.sync-backup/\`
|
|
1245
|
+
- If restore also fails, the backup directory is intentionally left behind and
|
|
1246
|
+
the command exits \`3\`
|
|
1247
|
+
|
|
1248
|
+
## Recovery
|
|
1249
|
+
|
|
1250
|
+
| Situation | Action |
|
|
1251
|
+
|-----------|--------|
|
|
1252
|
+
| Conflict on a file you don't want to overwrite | Hand-merge \`specdo/specs/<file>\` to incorporate both, then re-run \`sync\` (it will see the files are equal and skip) |
|
|
1253
|
+
| Previous run left \`specdo/.sync-backup/\` behind | Inspect the staged files, complete manual recovery if needed, then remove the directory before retrying |
|
|
1254
|
+
| Accidental \`--force\` that still completed successfully | Recover the prior contents from the staged copy you preserved before removing \`specdo/.sync-backup/\`, or from VCS / archive history |
|
|
1255
|
+
`;
|
|
1256
|
+
const SYNC_EXAMPLES = `# specdo sync — Examples
|
|
1257
|
+
|
|
1258
|
+
## Session 1: clean first-time sync
|
|
1259
|
+
|
|
1260
|
+
\`\`\`bash
|
|
1261
|
+
$ specdo sync --change rate-limiting-public-api
|
|
1262
|
+
# specdo sync --change rate-limiting-public-api
|
|
1263
|
+
|
|
1264
|
+
Synced 1 spec file(s) into specdo/specs/.
|
|
1265
|
+
✓ rate-limiting-public-api/spec.md
|
|
1266
|
+
|
|
1267
|
+
Next: specdo archive --change rate-limiting-public-api
|
|
1268
|
+
\`\`\`
|
|
1269
|
+
|
|
1270
|
+
## Session 2: conflict against an existing spec
|
|
1271
|
+
|
|
1272
|
+
\`\`\`bash
|
|
1273
|
+
$ specdo sync --change auth-flow-revamp
|
|
1274
|
+
# (stderr) Sync blocked: 2 conflict(s) detected.
|
|
1275
|
+
# (stderr) ✗ auth-flow/spec.md
|
|
1276
|
+
# (stderr) ✗ session-policy/spec.md
|
|
1277
|
+
# (stderr) Run with --force to overwrite (a backup will be written to specdo/.sync-backup/).
|
|
1278
|
+
\`\`\`
|
|
1279
|
+
|
|
1280
|
+
Agent should *never* silently re-run with \`--force\`. The correct dialog:
|
|
1281
|
+
|
|
1282
|
+
> "Two specs in specdo/specs/ already exist and differ from your change's
|
|
1283
|
+
> versions. Should I (a) show you a diff so you can merge by hand, or (b)
|
|
1284
|
+
> overwrite both with your change's versions? — option (b) stages the current
|
|
1285
|
+
> canonical copies under specdo/.sync-backup/ before overwrite."
|
|
1286
|
+
|
|
1287
|
+
## Session 3: deliberate --force with audit trail
|
|
1288
|
+
|
|
1289
|
+
\`\`\`bash
|
|
1290
|
+
$ specdo sync --change auth-flow-revamp --force
|
|
1291
|
+
# specdo sync --change auth-flow-revamp
|
|
1292
|
+
|
|
1293
|
+
Synced 2 spec file(s) into specdo/specs/.
|
|
1294
|
+
✓ auth-flow/spec.md [forced]
|
|
1295
|
+
✓ session-policy/spec.md [forced]
|
|
1296
|
+
|
|
1297
|
+
Forced overwrites recorded in context.json.sync.forcedConflictHashes (2 entries).
|
|
1298
|
+
|
|
1299
|
+
Next: specdo archive --change auth-flow-revamp
|
|
1300
|
+
\`\`\`
|
|
1301
|
+
|
|
1302
|
+
The before/after hashes flow into \`archive-summary.md\` so any reviewer can
|
|
1303
|
+
spot a forced spec rewrite later.
|
|
1304
|
+
|
|
1305
|
+
## Anti-pattern: archive before sync
|
|
1306
|
+
|
|
1307
|
+
\`\`\`bash
|
|
1308
|
+
$ specdo archive --change auth-flow-revamp
|
|
1309
|
+
# (stderr) Cannot archive: sync has not been executed. Run 'specdo sync --change auth-flow-revamp' first, or pass --skip-sync-check (record-only).
|
|
1310
|
+
\`\`\`
|
|
1311
|
+
|
|
1312
|
+
Always run \`sync\` (or explicitly skip with \`archive --skip-sync-check\` plus
|
|
1313
|
+
a written risk note) before archiving.
|
|
1314
|
+
`;
|
|
1315
|
+
// ─── specdo-archive ────────────────────────────────────────────
|
|
1316
|
+
const ARCHIVE_BODY = `# specdo archive
|
|
1317
|
+
|
|
1318
|
+
## How to use this skill (do exactly this)
|
|
1319
|
+
|
|
1320
|
+
Run the CLI — never hand-move the change directory:
|
|
1321
|
+
|
|
1322
|
+
\`\`\`bash
|
|
1323
|
+
specdo archive --change <name>
|
|
1324
|
+
\`\`\`
|
|
1325
|
+
|
|
1326
|
+
Do **not** manually \`mv specdo/changes/<name> specdo/archive/<name>\`.
|
|
1327
|
+
Hand-moving skips \`archive-summary.md\` generation and \`archivedAt\`
|
|
1328
|
+
stamping, leaving the change in a broken state ("in flight" to \`list active\`
|
|
1329
|
+
AND "archived" to \`list archived\`). Always go through \`specdo archive\`.
|
|
1330
|
+
|
|
1331
|
+
Use \`--skip-sync-check\` ONLY when the user explicitly accepts that sync was
|
|
1332
|
+
incomplete or skipped; a risk note will be automatically recorded in
|
|
1333
|
+
\`archive-summary.md\`.
|
|
1334
|
+
|
|
1335
|
+
### Before you run — verify completion and sync status
|
|
1336
|
+
|
|
1337
|
+
Read \`specdo/changes/<name>/context.json\` and \`tasks.md\`:
|
|
1338
|
+
|
|
1339
|
+
**Task completion:**
|
|
1340
|
+
- Every task in \`tasks.md\` must be \`[x]\` with non-empty \`Evidence:\` line
|
|
1341
|
+
- \`context.apply\` must exist and \`tasksCompleted === tasksTotal\`
|
|
1342
|
+
- If tasks are incomplete, run \`specdo apply --change <name>\` first
|
|
1343
|
+
|
|
1344
|
+
**Sync status:**
|
|
1345
|
+
- \`sync.completedAt\` must be non-null. If null, confirm with the user
|
|
1346
|
+
before using \`--skip-sync-check\` — note the reason in conversation.
|
|
1347
|
+
- \`sync.conflicts\` must be empty or resolved (\`forcedConflicts\` is OK)
|
|
1348
|
+
- The CLI also performs a live filesystem comparison between
|
|
1349
|
+
\`changes/<name>/specs/\` and \`specdo/specs/\` — any unsynced files
|
|
1350
|
+
will cause archive to exit 1
|
|
1351
|
+
- If sync conditions are not met, run \`specdo sync --change <name>\` first
|
|
1352
|
+
|
|
1353
|
+
## Overview
|
|
1354
|
+
|
|
1355
|
+
Finalize a change: move \`specdo/changes/<name>/\` into \`specdo/archive/\`
|
|
1356
|
+
with a generated \`archive-summary.md\` snapshotting evidence, sync state,
|
|
1357
|
+
and any forced conflicts.
|
|
1358
|
+
|
|
1359
|
+
## When to use
|
|
1360
|
+
|
|
1361
|
+
- \`specdo sync --change <name>\` succeeded with no unresolved conflicts.
|
|
1362
|
+
- The change is done and should leave the active set.
|
|
1363
|
+
- Trigger phrases: "archive the change", "finalize <change>", "close out
|
|
1364
|
+
this change", "we're done with X".
|
|
1365
|
+
|
|
1366
|
+
## When NOT to use
|
|
1367
|
+
|
|
1368
|
+
- Do NOT archive a change with unresolved sync conflicts — \`sync.conflicts\`
|
|
1369
|
+
must be empty.
|
|
1370
|
+
- Do NOT manually \`mv\` the change directory to \`specdo/archive/\` — this
|
|
1371
|
+
skips \`archive-summary.md\` generation and \`archivedAt\` stamping, breaking
|
|
1372
|
+
both \`list active\` and \`list archived\` views.
|
|
1373
|
+
|
|
1374
|
+
## What it produces
|
|
1375
|
+
|
|
1376
|
+
- Moves \`specdo/changes/<name>/\` → \`specdo/archive/<name>/\`
|
|
1377
|
+
- Writes \`archive-summary.md\` with:
|
|
1378
|
+
- explore matched domains + final answers
|
|
1379
|
+
- apply tasks total / completed + per-task evidence
|
|
1380
|
+
- sync state snapshot (forced conflicts + hashes, if any)
|
|
1381
|
+
- risk notes (mandatory when \`--skip-sync-check\` is used)
|
|
1382
|
+
- Sets \`context.json\` → \`archive.archivedAt\` (ISO timestamp)
|
|
1383
|
+
|
|
1384
|
+
## See also
|
|
1385
|
+
|
|
1386
|
+
- [\`references/REFERENCE.md\`](references/REFERENCE.md) — flag matrix, exit
|
|
1387
|
+
codes, archive directory layout, audit fields
|
|
1388
|
+
- [\`references/EXAMPLES.md\`](references/EXAMPLES.md) — clean archive, the
|
|
1389
|
+
\`--skip-sync-check\` risk-note dialog, and post-archive lookups
|
|
1390
|
+
|
|
1391
|
+
## Recovery
|
|
1392
|
+
|
|
1393
|
+
| Situation | Action |
|
|
1394
|
+
|-----------|--------|
|
|
1395
|
+
| Sync incomplete (\`completedAt\` null) | Run \`specdo sync --change <name>\` first, or use \`--skip-sync-check\` with documented reason |
|
|
1396
|
+
| Unresolved sync conflicts | Run \`specdo sync --change <name>\` to resolve; \`archive\` refuses with conflicts present |
|
|
1397
|
+
| Archive path collision | Confirm with user whether the existing archive is stale. If confirmed, \`rm -rf specdo/archive/<name>\` and retry |
|
|
1398
|
+
| Hand-moved directory (broken state) | Move it back: \`mv specdo/archive/<name> specdo/changes/<name>\`, then run \`specdo archive --change <name>\` |
|
|
1399
|
+
|
|
1400
|
+
## Next step
|
|
1401
|
+
|
|
1402
|
+
This change is now archived. Use \`specdo list --archived\` or
|
|
1403
|
+
\`specdo show <name>\` to review the finalized record.
|
|
1404
|
+
`;
|
|
1405
|
+
const ARCHIVE_REFERENCE = `# specdo archive — Reference
|
|
1406
|
+
|
|
1407
|
+
## Full command matrix
|
|
1408
|
+
|
|
1409
|
+
| Form | Use case |
|
|
1410
|
+
|------|----------|
|
|
1411
|
+
| \`specdo archive --change <name>\` | Standard; requires sync-complete + no unresolved conflicts |
|
|
1412
|
+
| \`specdo archive --change <name> --skip-sync-check\` | Bypass sync gate; risk note automatically recorded |
|
|
1413
|
+
|
|
1414
|
+
## Required preconditions (without \`--skip-sync-check\`)
|
|
1415
|
+
|
|
1416
|
+
- \`tasks.md\` exists, parses, and every task is \`[x]\` with non-empty evidence
|
|
1417
|
+
- \`context.apply\` exists with \`tasksCompleted === tasksTotal\`
|
|
1418
|
+
- \`sync.completedAt\` non-null
|
|
1419
|
+
- \`sync.conflicts\` empty (forcedConflicts is OK; they were a deliberate choice)
|
|
1420
|
+
- Change directory still exists at \`specdo/changes/<name>/\`
|
|
1421
|
+
|
|
1422
|
+
## Exit codes
|
|
1423
|
+
|
|
1424
|
+
- \`0\` — archive succeeded; \`context.json\` → \`archive.archivedAt\` set
|
|
1425
|
+
- \`1\` — change not found / sync incomplete / unresolved conflicts present / invalid \`--change\`
|
|
1426
|
+
- \`3\` — filesystem move failure (target archive path collision, permission)
|
|
1427
|
+
|
|
1428
|
+
## Archive directory layout
|
|
1429
|
+
|
|
1430
|
+
\`\`\`
|
|
1431
|
+
specdo/archive/<name>/
|
|
1432
|
+
├── context.json # final, with archive stage stamped
|
|
1433
|
+
├── proposal.md
|
|
1434
|
+
├── specs/ # copy of the per-change specs at archive time
|
|
1435
|
+
├── design.md
|
|
1436
|
+
├── tasks.md
|
|
1437
|
+
├── apply-brief.md # last-rendered brief
|
|
1438
|
+
└── archive-summary.md # generated by archive command
|
|
1439
|
+
\`\`\`
|
|
1440
|
+
|
|
1441
|
+
## archive-summary.md sections
|
|
1442
|
+
|
|
1443
|
+
1. **Header**: change name, archivedAt, schema version
|
|
1444
|
+
2. **Domains**: matched + scores + clarifying answers
|
|
1445
|
+
3. **Tasks**: total / completed / evidence (one per task)
|
|
1446
|
+
4. **Sync snapshot**: completedAt, forcedConflicts, hashes
|
|
1447
|
+
5. **Risk notes**: only present when \`--skip-sync-check\` was used
|
|
1448
|
+
|
|
1449
|
+
## Why move (not copy)?
|
|
1450
|
+
|
|
1451
|
+
The directory move ensures a single source of truth — no risk of two
|
|
1452
|
+
diverging copies of the same change. To recover a change from archive,
|
|
1453
|
+
\`mv specdo/archive/<name> specdo/changes/<name>\` (then re-run \`sync\` if
|
|
1454
|
+
specs changed in the meantime).
|
|
1455
|
+
`;
|
|
1456
|
+
const ARCHIVE_EXAMPLES = `# specdo archive — Examples
|
|
1457
|
+
|
|
1458
|
+
## Session 1: clean finalization
|
|
1459
|
+
|
|
1460
|
+
\`\`\`bash
|
|
1461
|
+
$ specdo archive --change rate-limiting-public-api
|
|
1462
|
+
✓ Archived 'rate-limiting-public-api' → specdo/archive/rate-limiting-public-api/.
|
|
1463
|
+
Summary: specdo/archive/rate-limiting-public-api/archive-summary.md
|
|
1464
|
+
|
|
1465
|
+
Pre-archive verify checklist (cross-check before announcing the change):
|
|
1466
|
+
- [ ] (backend) Contract test passes for every endpoint
|
|
1467
|
+
- [ ] (security) All auth endpoints have rate limiting
|
|
1468
|
+
- [ ] (operations) Release notes include headline changes and migration actions
|
|
1469
|
+
\`\`\`
|
|
1470
|
+
|
|
1471
|
+
## Session 2: trying to archive with unresolved conflicts
|
|
1472
|
+
|
|
1473
|
+
\`\`\`bash
|
|
1474
|
+
$ specdo archive --change auth-flow-revamp
|
|
1475
|
+
# (stderr) Cannot archive: change specs are not fully synced into specdo/specs.
|
|
1476
|
+
# (stderr) ! pending conflict: auth-flow/spec.md
|
|
1477
|
+
# (stderr) ! pending conflict: session-policy/spec.md
|
|
1478
|
+
# (stderr) Re-run 'specdo sync --change auth-flow-revamp' before archiving.
|
|
1479
|
+
\`\`\`
|
|
1480
|
+
|
|
1481
|
+
## Session 3: deliberate skip-sync with risk note
|
|
1482
|
+
|
|
1483
|
+
This path is rare. Agent should confirm with the user *why* sync is being
|
|
1484
|
+
skipped before invoking it.
|
|
1485
|
+
|
|
1486
|
+
> User: "Sync is broken because the spec template changed; just archive it,
|
|
1487
|
+
> we'll re-sync later."
|
|
1488
|
+
|
|
1489
|
+
\`\`\`bash
|
|
1490
|
+
$ specdo archive --change auth-flow-revamp --skip-sync-check
|
|
1491
|
+
✓ Archived 'auth-flow-revamp' → specdo/archive/auth-flow-revamp/.
|
|
1492
|
+
Summary: specdo/archive/auth-flow-revamp/archive-summary.md
|
|
1493
|
+
|
|
1494
|
+
Risk notes:
|
|
1495
|
+
! Sync started but never completed
|
|
1496
|
+
|
|
1497
|
+
Pre-archive verify checklist (cross-check before announcing the change):
|
|
1498
|
+
- [ ] (backend) Contract test passes for every endpoint
|
|
1499
|
+
- [ ] (security) All auth endpoints have rate limiting
|
|
1500
|
+
- [ ] (operations) Release notes include headline changes and migration actions
|
|
1501
|
+
\`\`\`
|
|
1502
|
+
|
|
1503
|
+
## After archive: read-only lookups still work
|
|
1504
|
+
|
|
1505
|
+
\`\`\`bash
|
|
1506
|
+
$ specdo list --archived
|
|
1507
|
+
Archived changes (2):
|
|
1508
|
+
|
|
1509
|
+
NAME STAGE TASKS UPDATED
|
|
1510
|
+
rate-limiting-public-api archive 6/6 ...
|
|
1511
|
+
auth-flow-revamp archive ... ...
|
|
1512
|
+
|
|
1513
|
+
$ specdo show rate-limiting-public-api --type spec
|
|
1514
|
+
# (renders the archived spec)
|
|
1515
|
+
\`\`\`
|
|
1516
|
+
|
|
1517
|
+
## Anti-pattern: hand-moving the directory
|
|
1518
|
+
|
|
1519
|
+
\`mv specdo/changes/<name> specdo/archive/<name>\` will succeed but skip the
|
|
1520
|
+
summary generation and the \`archivedAt\` stamping. The change will then look
|
|
1521
|
+
"in flight" to \`list active\` *and* "archived" to \`list archived\` — break-
|
|
1522
|
+
ing both views. Always go through \`specdo archive --change <name>\`.
|
|
1523
|
+
`;
|
|
1524
|
+
// ─── Exported aggregate ────────────────────────────────────────
|
|
1525
|
+
export const WORKFLOW_SKILLS = [
|
|
1526
|
+
{
|
|
1527
|
+
name: 'specdo-explore',
|
|
1528
|
+
description: "Use when the user is starting a new feature, refactor, bug fix, or any spec-driven change. Runs `specdo explore '<idea>'` to seed context.json, score domains, and create `specdo/changes/<name>/`. Trigger phrases: 'let's plan X', 'new feature', 'capture this idea', 'scaffold a proposal', 'set up a change'.",
|
|
1529
|
+
body: EXPLORE_BODY,
|
|
1530
|
+
references: {
|
|
1531
|
+
'REFERENCE.md': EXPLORE_REFERENCE,
|
|
1532
|
+
'EXAMPLES.md': EXPLORE_EXAMPLES,
|
|
1533
|
+
},
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
name: 'specdo-propose',
|
|
1537
|
+
description: 'Use after specdo explore completes. Runs `specdo propose --change <name>` to render OpenSpec-aligned proposal.md / specs/<capability>/spec.md / design.md / tasks.md, with SpecDo domain guidance injected into the standard skeleton. Existing handwritten artifacts are skipped unless `--force` is explicitly chosen. Trigger phrases: "generate the proposal", "scaffold tasks", "draft design doc", "kick off the change", "what is next for <change>".',
|
|
1538
|
+
body: PROPOSE_BODY,
|
|
1539
|
+
references: {
|
|
1540
|
+
'REFERENCE.md': PROPOSE_REFERENCE,
|
|
1541
|
+
'EXAMPLES.md': PROPOSE_EXAMPLES,
|
|
1542
|
+
},
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
name: 'specdo-apply',
|
|
1546
|
+
description: 'Use during change implementation. Runs `specdo apply --change <name>` to render apply-brief.md (with domain implement clauses) and `--done <ref> --evidence "..."` to record per-task evidence under TDD discipline. Trigger phrases: "start implementing", "I\'m done with task 1.1", "mark task 2.1", "show me the brief", "what\'s next on <change>".',
|
|
1547
|
+
body: APPLY_BODY,
|
|
1548
|
+
references: {
|
|
1549
|
+
'REFERENCE.md': APPLY_REFERENCE,
|
|
1550
|
+
'EXAMPLES.md': APPLY_EXAMPLES,
|
|
1551
|
+
},
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
name: 'specdo-sync',
|
|
1555
|
+
description: 'Use when every task in tasks.md is complete. Runs `specdo sync --change <name>` to promote per-change specs into `specdo/specs/`, detecting and reporting conflicts. Trigger phrases: "sync specs", "promote the spec", "merge change specs", "publish the spec", "spec is ready to be canonical".',
|
|
1556
|
+
body: SYNC_BODY,
|
|
1557
|
+
references: {
|
|
1558
|
+
'REFERENCE.md': SYNC_REFERENCE,
|
|
1559
|
+
'EXAMPLES.md': SYNC_EXAMPLES,
|
|
1560
|
+
},
|
|
1561
|
+
},
|
|
1562
|
+
{
|
|
1563
|
+
name: 'specdo-archive',
|
|
1564
|
+
description: 'Use after specdo sync succeeds with no unresolved conflicts. Runs `specdo archive --change <name>` to move changes/<name>/ → archive/<name>/ with archive-summary.md. Trigger phrases: "archive the change", "finalize <change>", "close out", "we\'re done with <change>".',
|
|
1565
|
+
body: ARCHIVE_BODY,
|
|
1566
|
+
references: {
|
|
1567
|
+
'REFERENCE.md': ARCHIVE_REFERENCE,
|
|
1568
|
+
'EXAMPLES.md': ARCHIVE_EXAMPLES,
|
|
1569
|
+
},
|
|
1570
|
+
},
|
|
1571
|
+
];
|
|
1572
|
+
//# sourceMappingURL=workflow-content.js.map
|