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.
Files changed (161) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/README.md +308 -0
  3. package/README.zh-CN.md +306 -0
  4. package/bin/specdo.js +3 -0
  5. package/dist/cli/index.d.ts +15 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +297 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/commands/_shared.d.ts +45 -0
  10. package/dist/commands/_shared.d.ts.map +1 -0
  11. package/dist/commands/_shared.js +124 -0
  12. package/dist/commands/_shared.js.map +1 -0
  13. package/dist/commands/apply.d.ts +30 -0
  14. package/dist/commands/apply.d.ts.map +1 -0
  15. package/dist/commands/apply.js +393 -0
  16. package/dist/commands/apply.js.map +1 -0
  17. package/dist/commands/archive.d.ts +25 -0
  18. package/dist/commands/archive.d.ts.map +1 -0
  19. package/dist/commands/archive.js +362 -0
  20. package/dist/commands/archive.js.map +1 -0
  21. package/dist/commands/doctor.d.ts +21 -0
  22. package/dist/commands/doctor.d.ts.map +1 -0
  23. package/dist/commands/doctor.js +180 -0
  24. package/dist/commands/doctor.js.map +1 -0
  25. package/dist/commands/domains.d.ts +14 -0
  26. package/dist/commands/domains.d.ts.map +1 -0
  27. package/dist/commands/domains.js +107 -0
  28. package/dist/commands/domains.js.map +1 -0
  29. package/dist/commands/explore.d.ts +48 -0
  30. package/dist/commands/explore.d.ts.map +1 -0
  31. package/dist/commands/explore.js +378 -0
  32. package/dist/commands/explore.js.map +1 -0
  33. package/dist/commands/init.d.ts +45 -0
  34. package/dist/commands/init.d.ts.map +1 -0
  35. package/dist/commands/init.js +243 -0
  36. package/dist/commands/init.js.map +1 -0
  37. package/dist/commands/list.d.ts +23 -0
  38. package/dist/commands/list.d.ts.map +1 -0
  39. package/dist/commands/list.js +135 -0
  40. package/dist/commands/list.js.map +1 -0
  41. package/dist/commands/propose.d.ts +22 -0
  42. package/dist/commands/propose.d.ts.map +1 -0
  43. package/dist/commands/propose.js +316 -0
  44. package/dist/commands/propose.js.map +1 -0
  45. package/dist/commands/show.d.ts +15 -0
  46. package/dist/commands/show.d.ts.map +1 -0
  47. package/dist/commands/show.js +214 -0
  48. package/dist/commands/show.js.map +1 -0
  49. package/dist/commands/status.d.ts +17 -0
  50. package/dist/commands/status.d.ts.map +1 -0
  51. package/dist/commands/status.js +146 -0
  52. package/dist/commands/status.js.map +1 -0
  53. package/dist/commands/sync.d.ts +21 -0
  54. package/dist/commands/sync.d.ts.map +1 -0
  55. package/dist/commands/sync.js +113 -0
  56. package/dist/commands/sync.js.map +1 -0
  57. package/dist/commands/validate.d.ts +117 -0
  58. package/dist/commands/validate.d.ts.map +1 -0
  59. package/dist/commands/validate.js +446 -0
  60. package/dist/commands/validate.js.map +1 -0
  61. package/dist/core/apply-brief-renderer.d.ts +35 -0
  62. package/dist/core/apply-brief-renderer.d.ts.map +1 -0
  63. package/dist/core/apply-brief-renderer.js +242 -0
  64. package/dist/core/apply-brief-renderer.js.map +1 -0
  65. package/dist/core/config-store.d.ts +190 -0
  66. package/dist/core/config-store.d.ts.map +1 -0
  67. package/dist/core/config-store.js +280 -0
  68. package/dist/core/config-store.js.map +1 -0
  69. package/dist/core/context-store.d.ts +96 -0
  70. package/dist/core/context-store.d.ts.map +1 -0
  71. package/dist/core/context-store.js +426 -0
  72. package/dist/core/context-store.js.map +1 -0
  73. package/dist/core/json-schemas.d.ts +349 -0
  74. package/dist/core/json-schemas.d.ts.map +1 -0
  75. package/dist/core/json-schemas.js +125 -0
  76. package/dist/core/json-schemas.js.map +1 -0
  77. package/dist/core/skill-content/cross-domain.d.ts +12 -0
  78. package/dist/core/skill-content/cross-domain.d.ts.map +1 -0
  79. package/dist/core/skill-content/cross-domain.js +291 -0
  80. package/dist/core/skill-content/cross-domain.js.map +1 -0
  81. package/dist/core/skill-content/protocol-examples.d.ts +13 -0
  82. package/dist/core/skill-content/protocol-examples.d.ts.map +1 -0
  83. package/dist/core/skill-content/protocol-examples.js +190 -0
  84. package/dist/core/skill-content/protocol-examples.js.map +1 -0
  85. package/dist/core/skill-content/workflow-content.d.ts +25 -0
  86. package/dist/core/skill-content/workflow-content.d.ts.map +1 -0
  87. package/dist/core/skill-content/workflow-content.js +1572 -0
  88. package/dist/core/skill-content/workflow-content.js.map +1 -0
  89. package/dist/core/skill-exporter.d.ts +186 -0
  90. package/dist/core/skill-exporter.d.ts.map +1 -0
  91. package/dist/core/skill-exporter.js +922 -0
  92. package/dist/core/skill-exporter.js.map +1 -0
  93. package/dist/core/spec-sync.d.ts +65 -0
  94. package/dist/core/spec-sync.d.ts.map +1 -0
  95. package/dist/core/spec-sync.js +226 -0
  96. package/dist/core/spec-sync.js.map +1 -0
  97. package/dist/core/task-parser.d.ts +58 -0
  98. package/dist/core/task-parser.d.ts.map +1 -0
  99. package/dist/core/task-parser.js +244 -0
  100. package/dist/core/task-parser.js.map +1 -0
  101. package/dist/core/template-renderer.d.ts +51 -0
  102. package/dist/core/template-renderer.d.ts.map +1 -0
  103. package/dist/core/template-renderer.js +362 -0
  104. package/dist/core/template-renderer.js.map +1 -0
  105. package/dist/domains/architecture.d.ts +34 -0
  106. package/dist/domains/architecture.d.ts.map +1 -0
  107. package/dist/domains/architecture.js +341 -0
  108. package/dist/domains/architecture.js.map +1 -0
  109. package/dist/domains/backend.d.ts +35 -0
  110. package/dist/domains/backend.d.ts.map +1 -0
  111. package/dist/domains/backend.js +367 -0
  112. package/dist/domains/backend.js.map +1 -0
  113. package/dist/domains/frontend.d.ts +36 -0
  114. package/dist/domains/frontend.d.ts.map +1 -0
  115. package/dist/domains/frontend.js +373 -0
  116. package/dist/domains/frontend.js.map +1 -0
  117. package/dist/domains/index.d.ts +49 -0
  118. package/dist/domains/index.d.ts.map +1 -0
  119. package/dist/domains/index.js +255 -0
  120. package/dist/domains/index.js.map +1 -0
  121. package/dist/domains/operations.d.ts +37 -0
  122. package/dist/domains/operations.d.ts.map +1 -0
  123. package/dist/domains/operations.js +344 -0
  124. package/dist/domains/operations.js.map +1 -0
  125. package/dist/domains/pool-ranking.d.ts +43 -0
  126. package/dist/domains/pool-ranking.d.ts.map +1 -0
  127. package/dist/domains/pool-ranking.js +153 -0
  128. package/dist/domains/pool-ranking.js.map +1 -0
  129. package/dist/domains/quality.d.ts +45 -0
  130. package/dist/domains/quality.d.ts.map +1 -0
  131. package/dist/domains/quality.js +368 -0
  132. package/dist/domains/quality.js.map +1 -0
  133. package/dist/domains/security.d.ts +19 -0
  134. package/dist/domains/security.d.ts.map +1 -0
  135. package/dist/domains/security.js +364 -0
  136. package/dist/domains/security.js.map +1 -0
  137. package/dist/domains/signal-match.d.ts +25 -0
  138. package/dist/domains/signal-match.d.ts.map +1 -0
  139. package/dist/domains/signal-match.js +67 -0
  140. package/dist/domains/signal-match.js.map +1 -0
  141. package/dist/domains/types.d.ts +354 -0
  142. package/dist/domains/types.d.ts.map +1 -0
  143. package/dist/domains/types.js +12 -0
  144. package/dist/domains/types.js.map +1 -0
  145. package/dist/index.d.ts +9 -0
  146. package/dist/index.d.ts.map +1 -0
  147. package/dist/index.js +9 -0
  148. package/dist/index.js.map +1 -0
  149. package/dist/protocols/index.d.ts +36 -0
  150. package/dist/protocols/index.d.ts.map +1 -0
  151. package/dist/protocols/index.js +85 -0
  152. package/dist/protocols/index.js.map +1 -0
  153. package/dist/protocols/review-to-solid.d.ts +32 -0
  154. package/dist/protocols/review-to-solid.d.ts.map +1 -0
  155. package/dist/protocols/review-to-solid.js +309 -0
  156. package/dist/protocols/review-to-solid.js.map +1 -0
  157. package/dist/utils/prompt.d.ts +37 -0
  158. package/dist/utils/prompt.d.ts.map +1 -0
  159. package/dist/utils/prompt.js +81 -0
  160. package/dist/utils/prompt.js.map +1 -0
  161. 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