@jabworks/condux 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jabworks/condux",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "OpenCode plugin for the condux workflow toolkit — bundles the condux skills and injects the specialist agents (coder, explorer, planner, researcher) plus an opt-in plan-review listener.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: discovery
3
- description: "Refine a rough idea into a signed-off design, presented in sections for sign-off before any planning or code begins. Feeds the tech spec, written via technical-spec at sign-off. Trigger for LARGE tasks, when scope is unclear, or when the user wants to brainstorm or explore a rough idea. Also when resuming an existing design or design doc — the existing-design check offers resume-or-fresh. A soft gate before /draft-plan: if discovery has not run, ask whether to skip it consciously."
3
+ description: "Refine a rough idea into a signed-off design, presented in sections for sign-off before any planning or code begins. Opens with the requirements — the feature PRD — and feeds the tech spec, written via technical-spec at sign-off. Trigger for LARGE tasks, when scope is unclear, or when the user wants to brainstorm or explore a rough idea — or to pin requirements first: \"write a PRD\", \"product requirements\", \"what are we building and why\". Also when resuming an existing design or design doc — the existing-design check offers resume-or-fresh. A soft gate before /draft-plan: if discovery has not run, ask whether to skip it consciously."
4
4
  argument-hint: "<rough idea or feature description>"
5
5
  effort: high
6
6
  ---
@@ -31,6 +31,13 @@ exists, read its frontmatter `status` and offer accordingly:
31
31
 
32
32
  Accept either answer, same as any other soft gate in this skill.
33
33
 
34
+ **Requirements on disk.** The same two-scope lookup finds
35
+ `specs/<slug>/prd.md`. When it exists, read it before Step 1 and say so —
36
+ "Requirements loaded from `<path>`" — then treat its sections as already
37
+ answered: the goal round asks only for the ones that are empty (The
38
+ Requirements Card, below). A spec with no `prd.md` is the normal case, not a
39
+ gap — say nothing.
40
+
34
41
  ```
35
42
  ┌──────────────────────────────────────────────────────────────────┐
36
43
  │ DISCOVERY │
@@ -42,6 +49,9 @@ Accept either answer, same as any other soft gate in this skill.
42
49
  │ - Is the request already well-defined (ticket, spec doc)? │
43
50
  │ → Ask: "This looks well-defined. Skip discovery and │
44
51
  │ go straight to planning?" │
52
+ │ → If discovery goes ahead: a PRD, ticket or product doc │
53
+ │ they brought is requirements, not a design — it feeds │
54
+ │ §0 (below); it never stands in for the design │
45
55
  │ - Is the scope genuinely unclear? │
46
56
  │ → Proceed to Step 2 │
47
57
  │ │
@@ -50,10 +60,15 @@ Accept either answer, same as any other soft gate in this skill.
50
60
  │ Focus on: goals, constraints, what "done" looks like, │
51
61
  │ known unknowns, and what should explicitly NOT be built. │
52
62
  │ No implementation detail yet — that's Step 4's job. │
63
+ │ The batch covers the six PRD sections — problem, users, │
64
+ │ goals and non-goals, success metrics, scope, open │
65
+ │ questions — skipping any a loaded PRD already answers. │
53
66
  │ │
54
67
  │ Step 3: PROPOSE │
55
68
  │ Announce the section list, then create the design file │
56
69
  │ (status: in-progress) and open the live preview. │
70
+ │ First card is §0 · requirements — the goal round in │
71
+ │ prd.md's six headings (The Requirements Card, below). │
57
72
  │ Present one section at a time in the card shape, get │
58
73
  │ acknowledgment, append the agreed section to the file. │
59
74
  │ §1 is approaches-and-tradeoffs; the rest follow the design. │
@@ -82,6 +97,8 @@ Accept either answer, same as any other soft gate in this skill.
82
97
  │ ✓ No subsystems that should be separate tasks │
83
98
  │ ✓ Every contract, mapping, or edge case named in the │
84
99
  │ design has a home in a spec concern file │
100
+ │ ✓ §0 invents nothing — an unanswered PRD section is an │
101
+ │ open question, never a filled-in guess │
85
102
  │ ✓ Unanswered detail questions surface as open questions, │
86
103
  │ never silently dropped │
87
104
  │ │
@@ -94,8 +111,9 @@ Accept either answer, same as any other soft gate in this skill.
94
111
  │ every agreed section is in it. Flip its frontmatter │
95
112
  │ status: in-progress → signed-off. That flip is what │
96
113
  │ /draft-plan's gate check reads. │
97
- │ Spec write-back is default-on: persist the concern files │
98
- │ too (Spec Integration below) unless the user opts out. │
114
+ │ Spec write-back is default-on: persist the concern files — │
115
+ │ prd.md from §0, then the rest (Spec Integration below) — │
116
+ │ unless the user opts out. │
99
117
  │ The preview is already running — reuse it (Design Review │
100
118
  │ Loop); never launch a second server or open a second tab. │
101
119
  └──────────────────────────────────────────────────────────────────┘
@@ -160,6 +178,8 @@ Accept either answer. Never block. Never lecture.
160
178
  ✗ Proceeding to planning without explicit sign-off
161
179
  ✗ Treating a well-defined ticket as needing full discovery
162
180
  ✗ Widening past the named target surface without saying so
181
+ ✗ Inventing users, metrics, or scope to complete §0
182
+ ✗ Writing prd.md before sign-off
163
183
  ✗ A section card that runs past one screen, or a paragraph past three lines
164
184
  ✗ Launching a second preview server, or opening a tab the user didn't ask for
165
185
  ```
@@ -211,6 +231,51 @@ the path as the label, and nothing degrades without a server. Never write a
211
231
  git-root-relative href (it cannot resolve against the served root), and
212
232
  never inline a copy of the diagram beside the artifact.
213
233
 
234
+ ## The Requirements Card (§0)
235
+
236
+ The goal round has always collected requirements — goals, what done looks
237
+ like, what not to build — and then compressed them into a three-line why-line,
238
+ where they were lost. §0 keeps them. It is the first card of Step 3, presented
239
+ once for acknowledgment before §1, and it is the feature's PRD in draft.
240
+
241
+ **Shape.** §0 uses `prd.md`'s six headings verbatim — *Problem · Users · Goals
242
+ and non-goals · Success metrics · Scope · Open questions* — each a table or a
243
+ short list (technical-spec's `references/templates.md` has the template). Same
244
+ one-screen rule as any card; overflow goes in the design file.
245
+
246
+ **§0 sits outside the count.** The section list announced before §1 names the
247
+ *design* sections — "4 sections: approach · …" — and cards stay `§n of N`
248
+ against that N. Announce §0 separately, first: *"Requirements first (§0), then
249
+ 4 sections: …"*.
250
+
251
+ **Three ways in, one card out:**
252
+
253
+ | Arriving with | What §0 is built from |
254
+ |---|---|
255
+ | nothing | the goal round — one batch, six slots |
256
+ | `specs/<slug>/prd.md` on disk | that file; ask only for empty sections |
257
+ | a ticket, product doc, or pasted PRD | that document, mapped onto the six headings, gaps marked |
258
+
259
+ **Rules underneath it:**
260
+
261
+ | Rule | Why |
262
+ |---|---|
263
+ | An unanswered section is asked once, then written under *Open questions* — never filled in | a six-slot shape creates pressure to complete it; invented users and metrics read as facts forever after |
264
+ | Content from the user's document that fits no heading goes under *Open questions*, in its original wording | losing what they wrote to fit the shape is worse than an untidy list |
265
+ | A later design section that changes scope, goals, or users updates §0 visibly, and names the change | `prd.md` and `decisions.md` describe one feature; preflight's drift check reads both |
266
+ | `prd.md` is written at Step 7, never at §0 | a PRD in `specs/` for a discovery nobody signed off is a durable file making unsigned claims |
267
+ | The design's why-line is derived from §0's *Problem* | one fact, one home — never a second copy that can disagree |
268
+
269
+ A request for *only* the requirements — "write a PRD for X", no design wanted
270
+ yet — still runs Steps 1–3 as far as §0, then asks: carry on into the design,
271
+ or sign off here and save the PRD alone? Saving it alone is the Step 7 spec
272
+ write-back with `prd.md` as the only concern file — and **the design file
273
+ keeps `status: in-progress`**. A PRD is not a design: no approach was agreed,
274
+ so `/draft-plan`'s gate must still ask, and flipping the status here would let
275
+ it plan against a file with requirements and no design in it. A later
276
+ discovery on the same feature finds the file and the `prd.md`, and resumes
277
+ from §0.
278
+
214
279
  ## The Design File and the Live Preview (Step 3 onward)
215
280
 
216
281
  **The file is created at §1, not at sign-off.** Write
@@ -275,8 +340,9 @@ A short design summary covering:
275
340
  - Key constraints and out-of-scope items
276
341
  - Open questions (if any remain after sign-off)
277
342
 
278
- Detail-round answers (Step 4) belong in the spec concern files, not the
279
- summary — the summary stays short; the spec carries the detail.
343
+ Requirements live in §0 and become `prd.md`; detail-round answers (Step 4)
344
+ belong in the other spec concern files, not the summary — the summary stays
345
+ short; the spec carries the detail.
280
346
 
281
347
  Lives at: `.condux/designs/YYYY-MM-DD-<feature>.md`, created at §1 and
282
348
  appended to per section, in the shape of `references/design-template.md`
@@ -334,8 +400,9 @@ the launch here.
334
400
  Integrates with `technical-spec` to persist the design and render it live while
335
401
  discovery runs. At sign-off (Step 7), unless the user opts out: run
336
402
  `technical-spec`'s scaffold script to create the spec directory, write the
337
- design's decisions/contracts/mappings/edge-cases into its concern files
338
- (`decisions.md`, `api.md`, `fields.md`, `quirks.md`, `implementation.md`), then
403
+ design's requirements/decisions/contracts/mappings/edge-cases into its concern
404
+ files (`prd.md` from §0, then `decisions.md`, `api.md`, `fields.md`,
405
+ `quirks.md`, `implementation.md`), then
339
406
  launch `plan-review`'s directory-mode preview against that spec path so it
340
407
  live-reloads as the conversation refines the design. Full commands, the
341
408
  existing-spec check, and how to action a submitted review decision:
@@ -19,6 +19,10 @@
19
19
  { "query": "review the plan in the browser", "should_trigger": true, "expected_skill": "plan-review" },
20
20
  { "query": "save what we decided as a spec", "should_trigger": true, "expected_skill": "technical-spec" },
21
21
  { "query": "why does checkout 500 on submit", "should_trigger": true, "expected_skill": "root-cause-analysis" },
22
+ { "query": "write a PRD for the notifications feature", "should_trigger": true, "expected_skill": "discovery", "accept": ["workflow"] },
23
+ { "query": "what are we building and why — pin the product requirements before any design", "should_trigger": true, "expected_skill": "discovery", "accept": ["workflow"] },
24
+ { "query": "write a PRD for fixing the footer typo", "should_trigger": true, "expected_skill": "workflow", "disallowed": ["discovery"], "note": "A PRD ask on a trivial change goes to the router, which picks SMALL; discovery must not claim it (specs/prd-authoring quirk Q5)." },
25
+ { "query": "save this PRD", "should_trigger": true, "expected_skill": "technical-spec" },
22
26
  { "query": "help me write my resume", "should_trigger": false, "expected_skill": null },
23
27
  { "query": "design a logo for the app", "should_trigger": false, "expected_skill": null }
24
28
  ]
@@ -23,6 +23,13 @@ feature: <slug>
23
23
 
24
24
  **Sections:** N — <names, in order> [at creation]
25
25
 
26
+ ## §0 · requirements — AGREED <date> [on acknowledgment; revised visibly]
27
+
28
+ <prd.md's six headings, verbatim — Problem · Users · Goals and non-goals ·
29
+ Success metrics · Scope · Open questions — each a table or short list.
30
+ technical-spec's references/templates.md has the template. Step 7 copies
31
+ this part into specs/<slug>/prd.md heading for heading.>
32
+
26
33
  ## §n · <name> — AGREED <date> [appended per agreement]
27
34
 
28
35
  **Decided:** <the choice>, because <one line>.
@@ -49,8 +56,11 @@ feature: <slug>
49
56
  | Rule | Why |
50
57
  |---|---|
51
58
  | Every agreed § carries the four facts a `decisions.md` entry carries — title+date, choice, alternatives with one-line why-nots, consequence | Step 7's spec write-back becomes transcription, not authorship; the design doc and `decisions.md` cannot disagree on shape because they share one |
59
+ | §0 carries `prd.md`'s six headings verbatim, outside the `§n of N` count; an unanswered section is an open question, never a guess | Step 7 copies §0 into `prd.md` — same shape, so nothing is re-authored; an invented metric reads as fact forever after |
60
+ | The why-line is derived from §0's *Problem*, never a second statement of it | one fact, one home |
52
61
  | Sections are appended as agreed, never drafted ahead | The file records the conversation's actual state; a pre-drafted section reads as agreed when it isn't |
53
62
  | Constraints discovered mid-flow go straight into their table | The section exists from creation precisely so mid-flow findings have a home other than an invented heading |
63
+ | A requirements-only discovery that stops at §0 writes `prd.md` and leaves `status: in-progress` | a PRD is not a design; `/draft-plan`'s gate must still ask |
54
64
  | `status` flips to `signed-off` only at Step 7, and nothing else edits the frontmatter | `/draft-plan` and the `planner` agent gate on this value |
55
65
 
56
66
  ## Lifecycle stamps, spelled out
@@ -58,6 +68,8 @@ feature: <slug>
58
68
  | Stamp | When written | Parts |
59
69
  |---|---|---|
60
70
  | `[at creation]` | Step 3 opens, before §1 is presented | frontmatter, title, why-line, section list |
71
+ | `[on acknowledgment]` | the §0 card is acknowledged, before §1 is presented | §0 requirements — written then, not before, so the file never shows requirements as agreed that nobody has seen |
72
+ | `[revised visibly]` | a later section changes scope, goals, or users | §0 — edited in place, the change named in that section's entry |
61
73
  | `[appended per agreement]` | each section, at the moment it is agreed | the § entries |
62
74
  | `[accumulates]` | any time | `Constraints & out of scope` rows |
63
75
  | `[finalized at sign-off]` | Step 7 | `Open questions`, the `status` flip |
@@ -21,8 +21,8 @@ If yes, go straight to **Launch preview** below (skip scaffold + write — spec
21
21
  The Markdown design doc (Step 7) is always written. The spec write-back is
22
22
  **default-on** — announce it rather than ask:
23
23
 
24
- > "Saving this as a tech spec too (decisions + the concern files from the
25
- > detail round) and opening the live preview — say no to skip."
24
+ > "Saving this as a tech spec too (the PRD from §0, decisions, and the concern
25
+ > files from the detail round) and opening the live preview — say no to skip."
26
26
 
27
27
  Unless the user opts out (the spec directory then becomes the target for the
28
28
  Design Review Loop above, in directory mode):
@@ -45,7 +45,12 @@ Design Review Loop above, in directory mode):
45
45
  repo structure, automatically.
46
46
 
47
47
  3. **Write initial spec files** from the design into `$SPEC_PATH/`.
48
- `decisions.md` always (chosen approach + rationale). Then every concern
48
+ `prd.md` first — the design file's `§0 · requirements` part, copied
49
+ heading for heading; if a `prd.md` was already on disk, update it in
50
+ place and add a changelog line to `index.md` rather than overwriting
51
+ silently. `decisions.md` always (chosen approach + rationale) — except on
52
+ the requirements-only exit (SKILL.md → The Requirements Card), where no
53
+ approach was agreed and `prd.md` is the only file written. Then every concern
49
54
  the detail round produced answers for gets its file: `api.md`,
50
55
  `fields.md`, `quirks.md`, `implementation.md`. A detail-round answer
51
56
  that never lands in a spec file is a bug in the flow, not a judgment call.
@@ -68,6 +68,7 @@ missing or scaffold-only file makes no claim, skip it:
68
68
 
69
69
  | Concern file | Check the implementation against |
70
70
  |---|---|
71
+ | `prd.md` | requirements — work that lands in the **Scope** table's *Out* column, or inside a row of the **Non-goal** table, is drift: both are explicit exclusions. Work the *In* column merely does not mention is not. Goals are compared only when the task claims to complete the feature; a task that serves a subset of them is not drift |
71
72
  | `api.md` | contracts touched — shapes, error forms, external calls |
72
73
  | `fields.md` | source-to-UI mappings and transformations |
73
74
  | `quirks.md` | edge cases and failure modes the spec says are handled |
@@ -21,11 +21,14 @@ mkdir -p "$SCRATCH_DIR"
21
21
  SLUG=$(basename "$PLAN_FILE" .md)
22
22
  BRIEF_FILE="$SCRATCH_DIR/${SLUG}-task-${TASK_N}-brief.md"
23
23
 
24
+ # A card is a `## Task N:` heading (draft-plan's plan-template.md) or the older
25
+ # `### Task N:`. The card ends at the next card of either shape, or at any
26
+ # other `## ` section — a trailing "## Verification" is not part of the brief.
24
27
  awk -v n="$TASK_N" '
25
28
  BEGIN { found = 0 }
26
- /^### Task [0-9]+:/ {
29
+ /^##+ Task [0-9]+:/ || /^## / {
27
30
  if (found) exit
28
- if ($0 ~ ("^### Task " n ":")) { found = 1 }
31
+ if ($0 ~ ("^##+ Task " n ":")) { found = 1 }
29
32
  }
30
33
  found { print }
31
34
  ' "$PLAN_FILE" > "$BRIEF_FILE"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: technical-spec
3
- description: "Persists feature decisions, API contracts, implementation details, and quirks into a structured, queryable spec tree — one folder per feature, one file per concern. Invoke-only — discovery runs it at design sign-off and preflight's drift check reads its output; the user runs it via /technical-spec when they say \"save spec\", \"document this\", \"write up what we decided\", \"record the decision rationale\", or \"spec this out\" — recording decisions for the future is spec work even when phrased as remembering. Not for turning a rough idea into a design first — that's discovery."
3
+ description: "Persists feature requirements, decisions, API contracts, implementation details, and quirks into a structured, queryable spec tree — one folder per feature, one file per concern. Invoke-only — discovery runs it at design sign-off and preflight's drift check reads its output; the user runs it via /technical-spec when they say \"save spec\", \"document this\", \"write up what we decided\", \"record the decision rationale\", \"spec this out\", \"save this PRD\", or \"write up the requirements\" — recording decisions for the future is spec work even when phrased as remembering. Not for turning a rough idea into a design first — that's discovery."
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
@@ -8,7 +8,7 @@ disable-model-invocation: true
8
8
 
9
9
  ## Overview
10
10
 
11
- Persists feature decisions, API contracts, implementation details, and quirks into a structured, queryable spec tree. One folder per feature, one file per concern — future sessions load only what they need. Specs are living contracts: `/preflight`'s Drift Check compares the implementation against them at end-of-task.
11
+ Persists feature requirements, decisions, API contracts, implementation details, and quirks into a structured, queryable spec tree. One folder per feature, one file per concern — future sessions load only what they need. Specs are living contracts: `/preflight`'s Drift Check compares the implementation against them at end-of-task.
12
12
 
13
13
  ## Spec Folder Layout
14
14
 
@@ -23,7 +23,8 @@ to place the spec.
23
23
  {feature-slug}/ # cross-cutting, or scaffolded from the repo root
24
24
  apps/web/
25
25
  {feature-slug}/ # scaffolded while working in apps/web
26
- index.md # purpose, TOC, last updated, commit hash, changelog ← scaffold creates this
26
+ index.md # purpose, TOC, last updated, PR stamp, changelog ← scaffold creates this
27
+ prd.md # Requirements: problem, users, goals/non-goals, metrics, scope
27
28
  decisions.md # Design decisions with context + rationale
28
29
  api.md # Endpoints, types, external APIs consumed
29
30
  fields.md # Field mappings: BE/3rd-party → UI, or forwarding chains
@@ -56,9 +57,11 @@ exists and has since the design's first section — discovery creates it at §1
56
57
  and appends to it as each section is agreed. So the input here is a finished
57
58
  file on disk, not a summary reconstructed from the conversation: read
58
59
  `.condux/designs/YYYY-MM-DD-<feature>.md` and map its sections into the
59
- concern files. Discovery's own preview server is already running against that
60
- file, so the live-preview offer below applies to the *spec directory* only —
61
- never start a second server for the design.
60
+ concern files. Its `§0 · requirements` part uses `prd.md`'s six headings
61
+ verbatim, so that mapping is a copy, heading for heading. Discovery's own
62
+ preview server is already running against that file, so the live-preview
63
+ offer below applies to the *spec directory* only — never start a second
64
+ server for the design.
62
65
 
63
66
  ## Required Notifications
64
67
 
@@ -86,10 +89,16 @@ bash path/to/skill/references/scaffold.sh "WanConfig"
86
89
  ```
87
90
 
88
91
  The script outputs one line:
89
- - `created:/abs/path/to/specs/wan-config commit:abc1234 date:2026-06-24` — new spec, `index.md` written
90
- - `exists:/abs/path/to/specs/wan-config commit:abc1234 date:2026-06-24` — spec already exists
92
+ - `created:/abs/path/to/specs/wan-config date:2026-06-24 commit:PR #pending` — new spec, `index.md` written
93
+ - `exists:/abs/path/to/specs/wan-config date:2026-06-24 commit:PR #pending` — spec already exists
91
94
 
92
- Parse `commit`, `date`, and the **absolute spec path** from the output — use the absolute path when writing content files and launching the preview server.
95
+ Parse `date` and the **absolute spec path** from the output — use the absolute path when writing content files and launching the preview server.
96
+
97
+ The `**Commit:**` stamp names the PR that carries the change (`PR #153`), never
98
+ a commit hash: a hash written on a feature branch is orphaned by the
99
+ squash-merge that lands it, so it resolves only in clones that had the branch.
100
+ The scaffold writes `PR #pending`; replace it with the number once the PR is
101
+ open, and use the same form in changelog lines.
93
102
 
94
103
  ## After Scaffold: Writing Content Files
95
104
 
@@ -105,6 +114,16 @@ the spec all read, so write each row as a claim someone could check.
105
114
  trailing `//` per field, JSDoc only when a line won't do. `fields.md` says
106
115
  what *happens to it* — mapping and transformation only. One fact never lives
107
116
  in both places: a fact with two homes goes missing from the one being read.
117
+ The same split holds one level up: `prd.md` says *why the feature exists and
118
+ for whom*; `decisions.md` says *how it was chosen*. A decision never restates
119
+ the problem, and the PRD never records an alternative.
120
+
121
+ **`prd.md` is the requirements file, and the one file written before the
122
+ design.** `discovery` authors it from its requirements card and writes it
123
+ here at sign-off; run standalone ("save this PRD", "write up the
124
+ requirements") you write it directly from what the user gives you. Six fixed
125
+ sections — see the template. A section nobody has answered becomes an open
126
+ question; never invent users or metrics to complete the table.
108
127
 
109
128
  **Quirk headings are `## Q<n> — Title`.** The `Q<n>` anchors are a citation
110
129
  contract (`durable-citations.test.mjs` resolves them), so numbers are unique,
@@ -131,7 +150,7 @@ path that resolves nowhere.
131
150
  When scaffold output is `exists:`:
132
151
  1. Read `index.md` to see current state and which files exist
133
152
  2. Update only files with new or changed content
134
- 3. Bump `Last updated` and `Commit` in `index.md` using values from scaffold output
153
+ 3. Bump `Last updated` in `index.md` from scaffold output; set `Commit` to the PR carrying this change (`PR #pending` until it is open)
135
154
  4. Append to the `## Changelog` in `index.md`
136
155
 
137
156
  ## Live HTML Preview & Review (Optional)
@@ -188,7 +207,8 @@ feedback file, if a decision is submitted).
188
207
  | Mistake | Fix |
189
208
  |---------|-----|
190
209
  | Skipping the notification/confirmation | Always announce before writing, wait for approval |
191
- | Not using scaffold output for date/commit | Parse them from the script — don't run git separately |
210
+ | Not using scaffold output for the date | Parse it from the script — don't run git separately |
211
+ | Stamping a commit hash | The stamp is `PR #N` — a branch hash is orphaned by squash-merge; `PR #pending` until the PR is open |
192
212
  | Rewriting all files on update | Read `index.md` first, only touch files with new content |
193
213
  | Vague decisions | Each decision needs context + rationale + consequences |
194
214
  | Creating empty placeholder files | Only create a file when it has real content |
@@ -17,6 +17,9 @@
17
17
  { "query": "browse the specs tree", "should_trigger": true, "expected_skill": "spec-browser" },
18
18
  { "query": "where is the spec for the auth feature", "should_trigger": true, "expected_skill": "spec-browser" },
19
19
  { "query": "design the feature first before documenting", "should_trigger": true, "expected_skill": "discovery" },
20
+ { "query": "save this PRD", "should_trigger": true, "expected_skill": "technical-spec" },
21
+ { "query": "write up the requirements from this ticket into the spec", "should_trigger": true, "expected_skill": "technical-spec", "disallowed": ["draft-plan"] },
22
+ { "query": "write a PRD for the notifications feature", "should_trigger": true, "expected_skill": "discovery", "accept": ["workflow"] },
20
23
  { "query": "generate openapi yaml from the routes", "should_trigger": false, "expected_skill": null },
21
24
  { "query": "write jsdoc comments for this module", "should_trigger": false, "expected_skill": null, "accept": ["workflow"], "note": "Writing comments is a code change — an implementation request workflow claims. null stays primary: it is also fine to just do it." },
22
25
  { "query": "host our swagger docs somewhere", "should_trigger": false, "expected_skill": null }
@@ -38,7 +38,12 @@ if [[ -z "$SLUG" || ! "$SLUG" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
38
38
  fi
39
39
 
40
40
  DATE=$(date +%Y-%m-%d)
41
- COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "no-git")
41
+ # The stamp names the PR that carries the spec, not a commit. A hash taken
42
+ # here is HEAD on a feature branch, and a squash-merge orphans it the moment
43
+ # the PR lands — it resolves only in clones that had the branch. The PR number
44
+ # is not known until the PR is open, so the scaffold writes a placeholder for
45
+ # the author to replace; a spec still stamped `PR #pending` is unfinished.
46
+ COMMIT="PR #pending"
42
47
  REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
43
48
  [[ -z "$REPO_ROOT" ]] && REPO_ROOT="${PWD}"
44
49
 
@@ -76,7 +81,7 @@ case "$SPEC_DIR" in
76
81
  esac
77
82
 
78
83
  if [[ -d "$SPEC_DIR" ]]; then
79
- echo "exists:$SPEC_DIR commit:$COMMIT date:$DATE"
84
+ echo "exists:$SPEC_DIR date:$DATE commit:$COMMIT"
80
85
  exit 0
81
86
  fi
82
87
 
@@ -110,4 +115,4 @@ cat > "$SPEC_DIR/index.md" <<EOF
110
115
  - $DATE ($COMMIT): Initial spec
111
116
  EOF
112
117
 
113
- echo "created:$SPEC_DIR commit:$COMMIT date:$DATE"
118
+ echo "created:$SPEC_DIR date:$DATE commit:$COMMIT"
@@ -20,7 +20,7 @@ follow. Write each table row as a claim someone could check, not a label.
20
20
  > shows for the spec — without it the spec is listed with no description.
21
21
 
22
22
  **Last updated:** {YYYY-MM-DD}
23
- **Commit:** {short-hash}
23
+ **Commit:** PR #{N}
24
24
  **Status:** draft | review | stable
25
25
 
26
26
  ## Contents
@@ -31,9 +31,14 @@ follow. Write each table row as a claim someone could check, not a label.
31
31
  | [Quirks](quirks.md) | what will bite you, and whether it is mitigated |
32
32
 
33
33
  ## Changelog
34
- - {YYYY-MM-DD} ({short-hash}): Initial spec
34
+ - {YYYY-MM-DD} (PR #{N}): Initial spec
35
35
  ```
36
36
 
37
+ The stamp names the PR that carries the change, never a commit hash: a hash
38
+ written on a feature branch is orphaned by the squash-merge that lands it.
39
+ The scaffold writes `PR #pending`; replace it once the PR is open, and use the
40
+ same form in changelog lines.
41
+
37
42
  The Contents table answers *which file do I open* — one row per concern file
38
43
  that actually exists, each `Answers` cell saying what a reader comes to it
39
44
  for. Files that don't exist get no row.
@@ -47,6 +52,74 @@ rule existed and two were already dead when they were found.
47
52
 
48
53
  ---
49
54
 
55
+ ## prd.md
56
+
57
+ ```markdown
58
+ # PRD — {Feature Name}
59
+
60
+ | Section | In one line |
61
+ |---|---|
62
+ | Problem | {the problem, stated as a claim} |
63
+ | Users | {who it is for} |
64
+ | Goals | {what changes when this succeeds} |
65
+ | Scope | {where the boundary sits} |
66
+
67
+ ## Problem
68
+
69
+ {one paragraph, three lines at most — what is wrong today, for whom, and why
70
+ it is worth fixing now}
71
+
72
+ ## Users
73
+
74
+ | Who | Today | What changes |
75
+ |---|---|---|
76
+ | {role or persona} | {what they do now} | {what they can do after} |
77
+
78
+ ## Goals and non-goals
79
+
80
+ | Goal | Measured by |
81
+ |---|---|
82
+ | {outcome, not a feature} | {the metric row that proves it} |
83
+
84
+ | Non-goal | Why excluded |
85
+ |---|---|
86
+ | {what this deliberately does not do} | {one line} |
87
+
88
+ ## Success metrics
89
+
90
+ | Metric | Target | How measured |
91
+ |---|---|---|
92
+ | {what is counted} | {the number or state} | {where the reading comes from} |
93
+
94
+ ## Scope
95
+
96
+ | In | Out |
97
+ |---|---|
98
+ | {a surface, flow, or platform this covers} | {the adjacent thing it does not} |
99
+
100
+ ## Open questions
101
+
102
+ - {a question nobody has answered yet — or "none"}
103
+ ```
104
+
105
+ The PRD is the one concern file written *before* the design: it says why the
106
+ feature exists and for whom, and `decisions.md` says how it was chosen. The
107
+ section set is fixed — these six headings, in this order — because
108
+ `discovery` writes them from its requirements card and `preflight`'s drift
109
+ check reads **Scope** and the **Non-goal** table as claims: work that lands
110
+ in the Out column, or inside a non-goal, is drift. Write the Out column as
111
+ things someone might plausibly build — an exclusion nobody would attempt
112
+ checks nothing.
113
+
114
+ **An empty section is an open question, not a blank to fill.** When nobody
115
+ has stated the users or a metric, the section says so under *Open questions*
116
+ in plain words. A PRD whose metrics were invented to complete the table is
117
+ worse than one that admits it has none. Content from a document the user
118
+ brought that fits none of the six sections also lands under *Open questions*,
119
+ in its original wording.
120
+
121
+ ---
122
+
50
123
  ## decisions.md
51
124
 
52
125
  ```markdown
@@ -78,7 +78,8 @@ Every tier ends with `preflight` then `finalize` — no exceptions.
78
78
  Match the task subject to a spec dir (fuzzy kebab-case: "checkout flow" →
79
79
  `specs/checkout-flow`). If found, read `index.md`, then load by task type —
80
80
  bug/debug → `quirks.md`, `api.md`, `fields.md`; refactor → `implementation.md`,
81
- `decisions.md`; new feature → `decisions.md`, `api.md`, `fields.md`. Carry this
81
+ `decisions.md`; new feature → `prd.md`, `decisions.md`, `api.md`, `fields.md`
82
+ (any of these the spec does not have is skipped silently). Carry this
82
83
  context through; don't re-read mid-task. No spec → proceed without comment.
83
84
  3. **Confirm with the user.** State the inferred tier + a one-sentence reason. If a
84
85
  spec was loaded, mention it and offer the companion: "Found spec for