@jabworks/condux 0.15.1 → 0.17.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/agents/planner.md CHANGED
@@ -19,6 +19,8 @@ Both can run in parallel if they don't depend on each other's output.
19
19
 
20
20
  For LARGE tasks (cross-cutting, unclear scope, multiple subsystems), `/discovery` should have already run before you are invoked — it produces the signed-off design you turn into an executable plan. That design is a saved artifact: glob `.condux/designs/*<slug>*.md` (and `specs/<slug>/` for a tech-spec) and **read it first** — it is your source of truth for scope, chosen approach, and out-of-scope items. Do not re-derive or second-guess design decisions already settled there; if the file is missing for a large task, ask whether discovery has run rather than filling in the design yourself.
21
21
 
22
+ **Check its `status` before trusting it.** Discovery creates the design file at its first section, not at sign-off, so finding the file does not mean the design was approved. Read the frontmatter: `signed-off` (or no `status` field at all, which means the file predates the field and was therefore saved at sign-off) means the design is settled and the paragraph above applies in full. `in-progress` means discovery started and did not finish — stop and ask whether to resume discovery, and do not plan from it. An unfinished design is the one case where the file is present and still must not be treated as source of truth.
23
+
22
24
  ## Task Size Classification
23
25
 
24
26
  - **Large (3+ files OR any architectural change)**: ask up to 3 impact-prioritized clarifying questions in one message, then delegate to `explorer`/`researcher`, then produce the full plan with ADR.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jabworks/condux",
3
- "version": "0.15.1",
3
+ "version": "0.17.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: blueprint
3
- description: "Produce dependency-free visual clarity artifacts at design time — HTML wireframes and full renders for UI screens and flows in the house design language (surface-kit tokens), and inline-SVG system diagrams (data models, flows, architecture, state machines) for backend work. During /discovery when the feature has a UI surface or a data model, from /draft-plan task cards, or standalone on \"mock this up\", \"wireframe this screen\", \"visualize the data model\", \"sketch the architecture\", \"diagram the flow\". Not for aesthetic or brand direction, editable design canvases or Figma, charts from real data, or generating code from a mockup."
3
+ description: "Produce dependency-free visual clarity artifacts at design time — HTML wireframes and full renders for UI screens and flows in the house design language (surface-kit tokens), and inline-SVG system diagrams (data models, flows, architecture, state machines) for backend work. During /discovery when a section turns on what entities exist, what happens in what order, what talks to what, what states are legal, or what goes where on a screen; from /draft-plan task cards; or standalone on \"mock this up\", \"wireframe this screen\", \"visualize the data model\", \"sketch the architecture\", \"diagram the flow\". Not for aesthetic or brand direction, editable design canvases or Figma, charts from real data, or generating code from a mockup."
4
4
  argument-hint: "[surface or model to visualize — optional; defaults to the current design context]"
5
5
  ---
6
6
 
@@ -26,12 +26,13 @@ product family.
26
26
  ┌──────────────────────────────────────────────────────────────────┐
27
27
  │ BLUEPRINT │
28
28
  ├──────────────────────────────────────────────────────────────────┤
29
- │ Step 1: ASSESS SURFACES │
30
- │ What does the feature touch? │
31
- │ - UI screens or flows → wireframe family │
32
- │ - Data models, services, → diagram family │
33
- │ flows, state machines │
34
- │ - Both → both families │
29
+ │ Step 1: ASSESS THE QUESTION │
30
+ │ What is the reader trying to answer? │
31
+ │ - What goes where on a screen → wireframe family │
32
+ │ - What exists / what happens → diagram family │
33
+ │ / what talks to what / │
34
+ │ what states are legal │
35
+ │ - Two of these → one artifact each │
35
36
  │ │
36
37
  │ Step 2: PRODUCE │
37
38
  │ One self-contained HTML file per screen / flow state / diagram. │
@@ -42,9 +43,13 @@ product family.
42
43
  │ No external assets, no CDN, no font files. │
43
44
  │ │
44
45
  │ Step 3: DELIVER │
45
- │ Open in the browser (xdg-open / open). If neither works │
46
- │ (headless, SSH), print the absolute paths and continue — │
47
- │ never fail on delivery. Always state which mode was produced │
46
+ │ Standalone: open in the browser (xdg-open / open). If neither │
47
+ │ works (headless, SSH), print the absolute paths and continue — │
48
+ │ never fail on delivery. │
49
+ │ Inside /discovery: open NOTHING. Link the file from the design │
50
+ │ doc and let the running preview reload — see Inside the │
51
+ │ Workflow. │
52
+ │ Either way, always state which mode was produced │
48
53
  │ and offer the flip: "wireframe mode — say 'promote to render' │
49
54
  │ for the full house look" (or the reverse). The mode is never │
50
55
  │ chosen silently. │
@@ -93,9 +98,26 @@ mockup into the spec directory first and cite the committed copy.
93
98
 
94
99
  ## Inside the Workflow
95
100
 
96
- - **/discovery** loads this skill at the propose step when the feature has a
97
- UI surface or a data model — the mockups render the proposal, and the
98
- signed-off design doc links the chosen ones. Side-by-side option *picking*
101
+ - **/discovery** loads this skill at the propose step when a section's decision
102
+ turns on one of the five questions below — not when the feature "has" a UI
103
+ surface or a data model. That noun test has a blind spot: a design whose
104
+ subjects are, say, a terminal output shape and a markdown file contains
105
+ neither, and still needs a flow diagram. A question test has no such gap,
106
+ because the reader asks the question regardless of what the feature is made of.
107
+
108
+ | The question the section turns on | Shape |
109
+ |---|---|
110
+ | What entities exist and how do they relate? | entity / data-model |
111
+ | What happens, in what order, when X occurs? | request / data flow |
112
+ | What services exist and what talks to what? | architecture |
113
+ | What states are legal and what moves between them? | state machine |
114
+ | What goes where on a screen, and in what order does it read? | wireframe |
115
+
116
+ **Inside discovery, deliver by linking — never by opening.** The reader
117
+ already has the design preview open (discovery launches it at §1 and it
118
+ live-reloads on every write). Add the mockup's path to the design doc and the
119
+ link appears there. A tab per section is the interruption this avoids;
120
+ standalone invocations keep opening on deliver. Side-by-side option *picking*
99
121
  stays with discovery's own mockup-picker.
100
122
  - **/draft-plan** task cards may cite mockup paths so an implementer sees the
101
123
  visual target for their task.
@@ -111,5 +133,8 @@ mockup into the spec directory first and cite the committed copy.
111
133
  ✗ External dependencies — no Mermaid CDN, no image generation, no Figma
112
134
  ✗ Code generation from the mockup (that's implementation's job, later)
113
135
  ✗ Charts of real data (that's a dataviz concern, not a design mockup)
136
+ ✗ Labels generic enough to fit another feature — see the specificity rule in
137
+ both kits; a box the reader can't disagree with isn't evidence
138
+ ✗ Opening a browser tab while running inside /discovery
114
139
  ✗ Editing the mockups after design sign-off without saying so
115
140
  ```
@@ -48,13 +48,18 @@
48
48
  "query": "show me a wireframe of both options for the onboarding screen",
49
49
  "should_trigger": true,
50
50
  "expected_skill": "blueprint",
51
- "accept": ["discovery"]
51
+ "accept": [
52
+ "discovery"
53
+ ]
52
54
  },
53
55
  {
54
56
  "query": "before planning, can we visualize what this feature will look like",
55
57
  "should_trigger": true,
56
58
  "expected_skill": "blueprint",
57
- "accept": ["discovery", "workflow"]
59
+ "accept": [
60
+ "discovery",
61
+ "workflow"
62
+ ]
58
63
  },
59
64
  {
60
65
  "query": "mock up the ER diagram for the new billing tables",
@@ -82,19 +87,29 @@
82
87
  "query": "build the settings page from the approved design",
83
88
  "should_trigger": false,
84
89
  "expected_skill": null,
85
- "accept": ["workflow"],
90
+ "accept": [
91
+ "workflow"
92
+ ],
86
93
  "note": "Building from an approved design is an implementation request; workflow's any-implementation-request claim covers it. The case still guards blueprint against the \"design\" bait."
87
94
  },
88
95
  {
89
96
  "query": "implement this Figma design as a React component",
90
97
  "should_trigger": false,
91
98
  "expected_skill": null,
92
- "accept": ["workflow"],
99
+ "accept": [
100
+ "workflow"
101
+ ],
93
102
  "note": "Implementing a design in code is an implementation request; workflow covers it. The case still guards blueprint against the \"Figma design\" bait."
94
103
  },
95
104
  {
96
105
  "query": "pick a color palette and typography for the marketing site",
97
106
  "should_trigger": false,
98
107
  "expected_skill": null
108
+ },
109
+ {
110
+ "query": "sketch how the CLI, the cache file and the background daemon hand off to each other",
111
+ "should_trigger": true,
112
+ "expected_skill": "blueprint",
113
+ "note": "No UI surface and no data model — the old noun-shaped trigger could not see this. The section turns on \"what talks to what\", which is a blueprint question."
99
114
  }
100
115
  ]
@@ -34,6 +34,29 @@ of the `<style>` block, verbatim.
34
34
  - Every relationship line gets a label. An unlabeled arrow is a guess the
35
35
  reader has to make.
36
36
 
37
+ ## The Specificity Rule
38
+
39
+ Every label must name something real from *this* design — a path, a command, a
40
+ field, a state, a status value, an endpoint. **If a label would be equally true
41
+ of a different feature, it is too vague.**
42
+
43
+ A diagram is evidence for a decision. A box the reader cannot disagree with
44
+ carries no information, so it cannot be evidence — and "generic enough to fit
45
+ any feature" is the single most common reason a produced artifact turns out not
46
+ to help anyone.
47
+
48
+ | Too vague | Specific |
49
+ |---|---|
50
+ | `Design Doc` | `.condux/designs/<date>-<slug>.md` |
51
+ | `Preview` | `plan-review --steer` |
52
+ | `Gate` | `signed-off → plan proceeds` |
53
+ | `Status` | `status: in-progress` |
54
+ | `saves` | `5. append agreed §` |
55
+
56
+ The rule bites hardest early, when the specifics are not settled yet — which is
57
+ the correct time for it to bite. A diagram drawn before there is anything
58
+ concrete to put in it is decoration, and should not be drawn.
59
+
37
60
  ## 1. Entity / Data-Model
38
61
 
39
62
  One `<g>` per entity: title bar + field rows. Keys marked `PK` / `FK`; edge
@@ -58,6 +58,16 @@ mixes both signals.
58
58
  8. **Self-contained.** All CSS inline in a `<style>` block. No external
59
59
  requests of any kind. The file must render identically from `file://`.
60
60
  The token core carries dark and light themes; the page follows the OS.
61
+ 9. **Specific enough to disagree with.** Every label names something real from
62
+ *this* design — a route, a field, a state, a real CTA. If a label would be
63
+ equally true of a different feature, it is too vague: `Submit` on a form
64
+ whose button says "Save and invite", a nav reading `Item · Item · Item`, a
65
+ panel titled `Details`. This is rule 5 pushed one step further — rule 5 asks
66
+ for the intended text, this asks whether the intended text distinguishes
67
+ anything. A wireframe is evidence for a layout decision, and an element the
68
+ reader cannot disagree with is not evidence. It bites hardest before the
69
+ specifics are settled, which is exactly when a wireframe should not be
70
+ drawn yet. Same rule, same reasoning as `diagram-kit.md`.
61
71
 
62
72
  ## Page Skeleton
63
73
 
@@ -21,9 +21,15 @@ Before Step 1, check for an existing design: glob `.condux/designs/*<slug>*.md`
21
21
  and both spec scopes — `<package-root>/specs/<slug>/` and
22
22
  `<git-root>/specs/<slug>/`, the workflow router's two-scope lookup (slug =
23
23
  kebab-case of the feature name). If any
24
- exists, offer: "Found an existing design for this feature at `<path>` —
25
- resume from there, or start a fresh discovery?" Accept either answer, same
26
- as any other soft gate in this skill.
24
+ exists, read its frontmatter `status` and offer accordingly:
25
+
26
+ - `signed-off`, or no `status` field at all (the file predates the field, so
27
+ it was saved at sign-off): "Found a signed-off design for this feature at
28
+ `<path>` — resume from there, or start a fresh discovery?"
29
+ - `in-progress`: "Found a discovery that stopped partway at `<path>`
30
+ (`<n>` sections agreed) — pick up where it left off, or start fresh?"
31
+
32
+ Accept either answer, same as any other soft gate in this skill.
27
33
 
28
34
  ```
29
35
  ┌──────────────────────────────────────────────────────────────────┐
@@ -46,12 +52,15 @@ as any other soft gate in this skill.
46
52
  │ No implementation detail yet — that's Step 4's job. │
47
53
  │ │
48
54
  │ Step 3: PROPOSE │
49
- │ Present 2-3 approaches with tradeoffs. │
50
- │ Show design in sections — get acknowledgment per section │
51
- │ before moving on. │
52
- │ UI surface or data model involved? Load `blueprint` to │
53
- │ render the proposal visually — wireframes and diagrams │
54
- │ become part of what gets signed off. │
55
+ │ Announce the section list, then create the design file │
56
+ │ (status: in-progress) and open the live preview. │
57
+ │ Present one section at a time in the card shape, get │
58
+ │ acknowledgment, append the agreed section to the file. │
59
+ │ §1 is approaches-and-tradeoffs; the rest follow the design. │
60
+ │ Full contract: The Section Card, below. │
61
+ │ Does a section's decision turn on one of blueprint's five │
62
+ │ questions? Load `blueprint` — the artifact is linked from │
63
+ │ the design doc, not opened in a new tab. │
55
64
  │ │
56
65
  │ Step 4: DETAIL ROUND — feed the spec │
57
66
  │ With the approach chosen, ask ONE more batch, grouped by │
@@ -79,13 +88,15 @@ as any other soft gate in this skill.
79
88
  │ Get explicit approval: "Looks good, proceed to planning" │
80
89
  │ Do not proceed to /draft-plan without this. │
81
90
  │ │
82
- │ Step 7: SAVE DESIGN + SPEC (mandatory) │
83
- │ Write the design summary to │
84
- │ .condux/designs/YYYY-MM-DD-<feature>.md — this is the │
85
- │ artifact /draft-plan's gate check globs for. │
91
+ │ Step 7: SIGN OFF THE FILE + SPEC (mandatory) │
92
+ │ The design file already exists — Step 3 created it and │
93
+ │ every agreed section is in it. Flip its frontmatter │
94
+ │ status: in-progress → signed-off. That flip is what │
95
+ │ /draft-plan's gate check reads. │
86
96
  │ Spec write-back is default-on: persist the concern files │
87
97
  │ too (Spec Integration below) unless the user opts out. │
88
- │ Then offer the browser review loop (Design Review Loop). │
98
+ │ The preview is already running — reuse it (Design Review │
99
+ │ Loop); never launch a second server or open a second tab. │
89
100
  └──────────────────────────────────────────────────────────────────┘
90
101
  ```
91
102
 
@@ -148,8 +159,105 @@ Accept either answer. Never block. Never lecture.
148
159
  ✗ Proceeding to planning without explicit sign-off
149
160
  ✗ Treating a well-defined ticket as needing full discovery
150
161
  ✗ Widening past the named target surface without saying so
162
+ ✗ A section card that runs past one screen, or a paragraph past three lines
163
+ ✗ Launching a second preview server, or opening a tab the user didn't ask for
164
+ ```
165
+
166
+ ## The Section Card (Step 3)
167
+
168
+ Step 3 used to say "show design in sections" and stop, which left the shape to
169
+ be reinvented every time — and what came out was prose. The shape is now fixed.
170
+
171
+ **Before §1, announce the section list.** Name every section you intend to
172
+ present, in order: *"4 sections: approach · section shape · blueprint trigger ·
173
+ rollout."* Three lines, and the reader knows the shape of the conversation
174
+ before they are inside it. Then create the design file and open the preview
175
+ (next section), and begin.
176
+
177
+ **Every card, same skeleton:**
178
+
179
+ ```
180
+ ## §n of N · <name> ← position, always
181
+ <one line: what this section decides>
182
+
183
+ <the evidence — table, list, or a linked artifact. Never a wall.>
184
+
185
+ **Recommendation:** <X>, because <one sentence>.
186
+ <the decision, as named options>
187
+ ```
188
+
189
+ **Three rules underneath it:**
190
+
191
+ | Rule | Why |
192
+ |---|---|
193
+ | The card fits one screen — about 25 lines. Overflow goes into the design file, and the card links it. | Without a number this is advice, not a contract, and advice is what produced the walls. |
194
+ | No paragraph runs past three lines. Longer means it is a table or a list. | Prose is the failure mode. A table cannot sprawl. |
195
+ | Rejected alternatives get one line each with a why-not; the full reasoning lives in the file. | Alternatives are why the recommendation can be trusted, and are also what bloats the card. |
196
+
197
+ The per-section stops stay. They were never the problem — the problem was that
198
+ the design existed only as scrollback, so the thread was lost between them. The
199
+ `§n of N` marker and the live file are what hold it.
200
+
201
+ **Visuals.** Load `blueprint` when a section's decision turns on one of its five
202
+ questions — what entities exist · what happens in what order · what talks to
203
+ what · what states are legal · what goes where on a screen. Inside discovery
204
+ the artifact is *linked from the design doc*, never opened in its own tab: the
205
+ running preview reloads and shows the link, so the reader stays where they are.
206
+
207
+ ## The Design File and the Live Preview (Step 3 onward)
208
+
209
+ **The file is created at §1, not at sign-off.** Write
210
+ `.condux/designs/YYYY-MM-DD-<feature>.md` with frontmatter
211
+ `status: in-progress` when Step 3 opens, and append each section to it as it is
212
+ agreed. This is the whole mechanism behind the card contract: the card can stay
213
+ small precisely because the design has somewhere else to live.
214
+
215
+ ```markdown
216
+ ---
217
+ status: in-progress
218
+ date: YYYY-MM-DD
219
+ feature: <slug>
220
+ ---
221
+ ```
222
+
223
+ At Step 7, flip `status` to `signed-off`. `/draft-plan` and the `planner` agent
224
+ both read that value; **a design file with `status: in-progress` does not
225
+ satisfy their gate**, which is what keeps an abandoned discovery from being
226
+ planned against. (A file with no `status` field at all predates this contract
227
+ and was only ever written at sign-off, so absence means `signed-off`.)
228
+
229
+ **The preview runs from §1, by default.** Launch it with the design file, in
230
+ manual mode — no `--steer`, which would block on a decision:
231
+
232
+ ```bash
233
+ node /path/to/plan-review/references/annotate-server.js .condux/designs/<file>.md --no-reject
151
234
  ```
152
235
 
236
+ Manual mode renders, watches the directory and live-reloads over SSE without
237
+ blocking, so every appended section appears in the tab the reader already has
238
+ open. It still accepts a submitted decision, which means **one server covers
239
+ the whole of discovery** — launched at §1, still serving at sign-off. Never
240
+ start a second one.
241
+
242
+ Announce it and move on — do not ask first:
243
+
244
+ > "Design preview running at http://127.0.0.1:7777 — it updates as we go. Say
245
+ > the word if you'd rather I close it."
246
+
247
+ The preview's purpose is to help make the *next* decision, so gating it behind
248
+ an opt-in defeats what it is for; and discovery only runs on the LARGE tier, so
249
+ there is no small case to protect from the ceremony. The default is visible and
250
+ reversible, never silent.
251
+
252
+ **Fail open.** No Node, no browser, headless, port taken — say so once in a
253
+ single line and continue terminal-only. The design file is still written and
254
+ still appended to; only the preview is missing. Never block discovery on it,
255
+ and never retry in a loop. `--no-open` exists for the headless case.
256
+
257
+ `.condux/` is gitignored working state, created on demand at the git root (see
258
+ `/workflow` → Artifacts). The bootstrap check now happens at §1 rather than at
259
+ sign-off — still ask only once.
260
+
153
261
  ## Output
154
262
 
155
263
  A short design summary covering:
@@ -162,51 +270,50 @@ A short design summary covering:
162
270
  Detail-round answers (Step 4) belong in the spec concern files, not the
163
271
  summary — the summary stays short; the spec carries the detail.
164
272
 
165
- Save to: `.condux/designs/YYYY-MM-DD-<feature>.md` — always, at sign-off
166
- (Step 7). The saved file is what `/draft-plan`'s gate check globs for; a
167
- design that lives only in conversation doesn't count as signed off.
273
+ Lives at: `.condux/designs/YYYY-MM-DD-<feature>.md`, created at §1 and
274
+ appended to per section (see The Design File and the Live Preview). Step 7
275
+ does not write it — it flips its `status` to `signed-off`, and that flip is
276
+ what `/draft-plan`'s gate check reads. A design that lives only in
277
+ conversation doesn't count as signed off, and neither does one still marked
278
+ `in-progress`.
168
279
 
169
- `.condux/` is gitignored working state, created on demand at the git root
170
- (see `/workflow` → Artifacts). Before the first write, make sure it's
171
- ignored — see the bootstrap step there. Honour an `AGENTS.md` path override
172
- if the project defines one.
280
+ Honour an `AGENTS.md` path override if the project defines one.
173
281
 
174
282
  For full design mockups — UI wireframes and renders in the house token
175
283
  language, data-model / flow / architecture diagrams — load the `blueprint`
176
- skill; the design doc links the files it produces. At sign-off, offer to
284
+ skill; the design doc links the files it produces, and the running preview
285
+ shows the link rather than a new tab opening. At sign-off, offer to
177
286
  promote the chosen wireframes to render mode (a style-block swap). For
178
287
  *picking between* side-by-side options in the browser, see
179
288
  `references/mockup-picker.md` (it can point at blueprint's files).
180
289
 
181
290
  ## Design Review Loop
182
291
 
183
- After saving, always offer — mirroring `/draft-plan`'s post-save review:
292
+ At Step 7, after the status flip, always offer — mirroring `/draft-plan`'s
293
+ post-save review:
184
294
 
185
- > "Design saved to `<path>`. Want to review it in the browser before we plan,
186
- > or go straight to /draft-plan?"
295
+ > "Design signed off at `<path>`. Want a pass over it in the browser before we
296
+ > plan, or go straight to /draft-plan?"
187
297
 
188
- **If review chosen:** locate `annotate-server.js` from the installed
189
- `plan-review` skill (`find ~/.claude ~/.codex ~/.agents -name
190
- annotate-server.js -path '*plan-review*' 2>/dev/null | head -1`) and launch
191
- it in `--steer` mode against the saved design file (or the spec directory,
192
- if the design was saved as a tech spec — see Spec Integration below):
298
+ **The server is already running** — it has been since §1, and the reader has
299
+ been watching the design accumulate in it. Do not launch another and do not
300
+ open another tab. `--no-reject` is independent of `--steer`, so the design
301
+ stage's **accept-or-fix** semantics (no Reject verdict — that belongs to plan
302
+ review) are already in force from the §1 launch.
193
303
 
194
- ```bash
195
- node /path/to/plan-review/references/annotate-server.js .condux/designs/<file>.md --steer --no-reject
196
- ```
304
+ **If a review pass is chosen:** point the reader at the tab they already have,
305
+ ask them to annotate and submit a decision, and read the result — the submitted
306
+ decision lands in the feedback file in manual mode rather than being long-polled:
197
307
 
198
- Poll `GET http://127.0.0.1:7777/api/decision` (long-poll — blocks until a
199
- decision is submitted) and branch on the result. Design review is
200
- **accept-or-fix** — `--no-reject` hides the Reject verdict, which belongs to
201
- plan review, not the design stage (directory/spec review hides it on its own;
202
- the flag matters for single-file design review):
308
+ - **Approve** → proceed to `/draft-plan`, carrying any feedback notes into the plan.
309
+ - **Request Revisions** → revise the design file in place per the feedback (the
310
+ open tab live-reloads over SSE), then ask again.
203
311
 
204
- - **Approve** → design is signed off; proceed to `/draft-plan`, carrying any
205
- feedback notes into the plan.
206
- - **Request Revisions** → revise the design file in place per the feedback
207
- (the open tab live-reloads over SSE), then poll again.
312
+ **If the preview failed open at §1** (no Node, no browser, headless) there is no
313
+ tab to point at. Say so in one line and go straight to planning; do not retry
314
+ the launch here.
208
315
 
209
- **If straight to planning chosen:** proceed directly, no server launch.
316
+ **If straight to planning chosen:** proceed directly.
210
317
 
211
318
  ## Spec Integration (Live Preview)
212
319
 
@@ -21,11 +21,27 @@ Turn a signed-off design into a clear, executable plan. Lean task cards, not mic
21
21
  `.condux/designs/*<slug>*.md` and both spec scopes —
22
22
  `<package-root>/specs/<slug>/` and `<git-root>/specs/<slug>/`, same
23
23
  two-scope lookup as the workflow router (slug = kebab-case of the
24
- feature name) — for an existing signed-off design; if found,
25
- treat this check as satisfied without asking. Otherwise ask: "We
24
+ feature name) — for an existing signed-off design; if found, **read
25
+ its `status`** (see below) and treat this check as satisfied without
26
+ asking only when it is `signed-off`. Otherwise ask: "We
26
27
  haven't aligned on the design yet — run /discovery first, or confirm
27
28
  you want to skip it."
28
29
 
30
+ **Reading `status`.** Discovery creates the design file at its first
31
+ section, not at sign-off, so the file existing no longer means the design
32
+ was approved. Its frontmatter carries the answer:
33
+
34
+ | `status` | Means | Gate |
35
+ |---|---|---|
36
+ | `signed-off` | discovery reached sign-off | satisfied |
37
+ | `in-progress` | discovery started and did not finish | **not** satisfied — ask |
38
+ | *absent* | written before this field existed | satisfied |
39
+
40
+ A missing `status` means `signed-off`. Every design file written before
41
+ this field existed was only ever saved at sign-off, so absence is a
42
+ positive signal, not an unknown — reading it the other way retroactively
43
+ invalidates every design already on disk.
44
+
29
45
  The plan is written as Markdown — optimized for AI agent consumption during
30
46
  execution. To read it in the browser, use `plan-review` (see After Saving);
31
47
  no separate HTML file is produced.
@@ -1345,11 +1345,23 @@
1345
1345
  let DIRMODE=false, docs=[], activeDoc=null;
1346
1346
  const docState={}; // name -> { md, pane, scroll, key, headings }
1347
1347
 
1348
+ // A design file carries its sign-off state in frontmatter, and renderBlocks
1349
+ // maps a bare `---` to <hr> — so without this the reader sees a rule, a
1350
+ // stray `status: …` paragraph and a second rule above every design. Only a
1351
+ // block at position 0 counts; the `---` separators these documents use
1352
+ // between sections must still render as horizontal rules. st.md keeps the
1353
+ // raw text, because the revision diff and scanDocPaths both read it and a
1354
+ // frontmatter-only change has to stay visible there.
1355
+ function stripFrontmatter(md){
1356
+ const m=/^---\r?\n[\s\S]*?\r?\n---\r?\n?/.exec(md);
1357
+ return m?md.slice(m[0].length):md;
1358
+ }
1359
+
1348
1360
  function renderDocPane(doc, md){
1349
1361
  const st=docState[doc];
1350
1362
  st.md=md; st.pane.innerHTML=''; st.headings=[];
1351
1363
  let section='(top)';
1352
- renderBlocks(md).forEach(function(b,idx){
1364
+ renderBlocks(stripFrontmatter(md)).forEach(function(b,idx){
1353
1365
  const id=st.key+'-blk-'+idx;
1354
1366
  const wrap=document.createElement('div'); wrap.className='blk'; wrap.id=id; wrap.innerHTML=b.html;
1355
1367
  if(b.heading){ section=id; st.headings.push({id:id,level:b.heading.level,text:b.heading.text}); }
@@ -22,6 +22,8 @@ Both can run in parallel if they don't depend on each other's output.
22
22
 
23
23
  For LARGE tasks (cross-cutting, unclear scope, multiple subsystems), `/discovery` should have already run before you are invoked — it produces the signed-off design you turn into an executable plan. That design is a saved artifact: glob `.condux/designs/*<slug>*.md` (and `specs/<slug>/` for a tech-spec) and **read it first** — it is your source of truth for scope, chosen approach, and out-of-scope items. Do not re-derive or second-guess design decisions already settled there; if the file is missing for a large task, ask whether discovery has run rather than filling in the design yourself.
24
24
 
25
+ **Check its `status` before trusting it.** Discovery creates the design file at its first section, not at sign-off, so finding the file does not mean the design was approved. Read the frontmatter: `signed-off` (or no `status` field at all, which means the file predates the field and was therefore saved at sign-off) means the design is settled and the paragraph above applies in full. `in-progress` means discovery started and did not finish — stop and ask whether to resume discovery, and do not plan from it. An unfinished design is the one case where the file is present and still must not be treated as source of truth.
26
+
25
27
  ## Task Size Classification
26
28
 
27
29
  - **Large (3+ files OR any architectural change)**: ask up to 3 impact-prioritized clarifying questions in one message, then delegate to `explorer`/`researcher`, then produce the full plan with ADR.
@@ -51,6 +51,15 @@ writing → run the scaffold script → write or update the concern files and
51
51
  `index.md` → offer the live HTML preview. Each step is specified in the
52
52
  sections below.
53
53
 
54
+ **When `discovery` calls this at sign-off**, the design document already
55
+ exists and has since the design's first section — discovery creates it at §1
56
+ and appends to it as each section is agreed. So the input here is a finished
57
+ file on disk, not a summary reconstructed from the conversation: read
58
+ `.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.
62
+
54
63
  ## Required Notifications
55
64
 
56
65
  Always announce and confirm before writing or editing. Never silently modify files.
@@ -86,8 +95,24 @@ Parse `commit`, `date`, and the **absolute spec path** from the output — use t
86
95
 
87
96
  Read [references/templates.md](references/templates.md) for the structure of each file.
88
97
 
98
+ **The layering rule.** Every concern file opens with its summary table; the
99
+ reasoning sits underneath; prose appears only where it earns its keep — the
100
+ reasoning a future reader must be able to follow. Fill the table layer first:
101
+ it is what a scanning human, `preflight`'s drift check, and an agent loading
102
+ the spec all read, so write each row as a claim someone could check.
103
+
104
+ **The two-homes rule.** A type in `api.md` says what each field *means* —
105
+ trailing `//` per field, JSDoc only when a line won't do. `fields.md` says
106
+ what *happens to it* — mapping and transformation only. One fact never lives
107
+ in both places: a fact with two homes goes missing from the one being read.
108
+
109
+ **Quirk headings are `## Q<n> — Title`.** The `Q<n>` anchors are a citation
110
+ contract (`durable-citations.test.mjs` resolves them), so numbers are unique,
111
+ ascending, and never renumbered.
112
+
89
113
  - Write only files that have real content
90
- - After writing, update the `## Contents` section in `index.md` with links to the files you created
114
+ - After writing, update the `## Contents` table in `index.md` — one row per
115
+ file created, the `Answers` cell saying what a reader comes to it for
91
116
  - Replace the HTML comment the scaffold left below the title with a one-line
92
117
  `> …` note saying what the spec is for. That note is what `spec-browser`'s
93
118
  catalog shows for the spec; leave it and the spec is listed with nothing to
@@ -168,3 +193,5 @@ feedback file, if a decision is submitted).
168
193
  | Vague decisions | Each decision needs context + rationale + consequences |
169
194
  | Creating empty placeholder files | Only create a file when it has real content |
170
195
  | Forgetting to update index.md Contents | Always link to files you create |
196
+ | Prose blob where the template has a table | Fill the table layer first; prose only for reasoning the table can't carry |
197
+ | Bare interface with the field meanings in fields.md | Meaning goes on the type (`//` per field); fields.md carries only the journey |
@@ -101,6 +101,11 @@ cat > "$SPEC_DIR/index.md" <<EOF
101
101
 
102
102
  ## Contents
103
103
 
104
+ | File | Answers |
105
+ |---|---|
106
+ <!-- One row per concern file you actually create — link + what a reader
107
+ comes to it for. Files that don't exist get no row. -->
108
+
104
109
  ## Changelog
105
110
  - $DATE ($COMMIT): Initial spec
106
111
  EOF
@@ -2,6 +2,13 @@
2
2
 
3
3
  Copy-paste templates for each spec file. Omit sections that don't apply — don't leave empty headings.
4
4
 
5
+ **The layering rule, which every template below follows:** a concern file opens
6
+ with a scannable table and carries its reasoning underneath. The table serves
7
+ the reader scanning for one thing, `preflight`'s drift check, and an agent
8
+ loading the spec as context — all three read the same rows. Prose is reserved
9
+ for the one job that needs it: reasoning a future reader must be able to
10
+ follow. Write each table row as a claim someone could check, not a label.
11
+
5
12
  ---
6
13
 
7
14
  ## index.md
@@ -17,16 +24,20 @@ Copy-paste templates for each spec file. Omit sections that don't apply — don'
17
24
  **Status:** draft | review | stable
18
25
 
19
26
  ## Contents
20
- - [Decisions](decisions.md) — why we built it this way
21
- - [API](api.md) — contracts, endpoints, types
22
- - [Fields](fields.md) — field mappings: BE/3rd-party → UI
23
- - [Implementation](implementation.md) — how it works, key files
24
- - [Quirks](quirks.md) — edge cases and gotchas
27
+
28
+ | File | Answers |
29
+ |---|---|
30
+ | [Decisions](decisions.md) | why it works this way, and what was rejected |
31
+ | [Quirks](quirks.md) | what will bite you, and whether it is mitigated |
25
32
 
26
33
  ## Changelog
27
34
  - {YYYY-MM-DD} ({short-hash}): Initial spec
28
35
  ```
29
36
 
37
+ The Contents table answers *which file do I open* — one row per concern file
38
+ that actually exists, each `Answers` cell saying what a reader comes to it
39
+ for. Files that don't exist get no row.
40
+
30
41
  **Cite committed paths only.** A spec is durable; the design and plan it came
31
42
  from are working state under `.condux/`, gitignored and gone on any other
32
43
  machine. If the changelog or body needs to point at a design or a verification
@@ -41,24 +52,35 @@ rule existed and two were already dead when they were found.
41
52
  ```markdown
42
53
  # Decisions — {Feature Name}
43
54
 
44
- ## {Decision Title}
55
+ | # | Decision | Because | Status |
56
+ |---|---|---|---|
57
+ | 1 | {what was decided, as a claim} | {why, one line} | accepted |
45
58
 
46
- **Date:** {YYYY-MM-DD}
47
- **Status:** accepted | superseded | deprecated
59
+ ## 1. {Decision Title} — {YYYY-MM-DD}
48
60
 
49
- ### Context
50
- Why this decision needed to be made. What constraints or requirements drove it.
61
+ **Decided:** one sentence, stated as a claim.
62
+ **Because:** one sentence — why this option won.
51
63
 
52
- ### Decision
53
- What was decided, stated clearly.
64
+ | Alternative | Why not |
65
+ |---|---|
66
+ | {option considered} | {one line} |
54
67
 
55
- ### Rationale
56
- Why this over the alternatives. Include alternatives considered and why they were rejected.
68
+ **Consequences**
69
+ - {what changes as a result — and where it costs, named}
57
70
 
58
- ### Consequences
59
- What changes as a result — positive and negative trade-offs.
71
+ **Context** *(only when the question's origin is not obvious)*
72
+ {prose — why a decision was needed at all, when the feature doesn't make
73
+ that self-evident}
60
74
  ```
61
75
 
76
+ The summary table is mandatory and answers "which decisions exist" without
77
+ reading the file. The alternatives table is mandatory too — an empty one is
78
+ visible in a way missing prose is not, and a decision recorded without its
79
+ rejected alternatives is assertion, not rationale. `Context` is the one
80
+ conditional block: `Because` covers why *this* option won; `Context` covers
81
+ why the question arose, which is frequently self-evident. Statuses:
82
+ `accepted | superseded | deprecated`.
83
+
62
84
  ---
63
85
 
64
86
  ## api.md
@@ -75,9 +97,12 @@ What changes as a result — positive and negative trade-offs.
75
97
  ## Key Types / Schemas
76
98
 
77
99
  \`\`\`typescript
78
- interface ExampleType {
79
- id: string;
80
- // ...
100
+ // The type says what a field MEANS; fields.md says what HAPPENS to it.
101
+ interface Invoice {
102
+ id: string; // Stripe invoice id, `in_`-prefixed
103
+ amountDue: number; // minor units (cents) — never format directly
104
+ status: InvoiceStatus; // drives the badge; `draft` is hidden in the list
105
+ voidedAt: string | null; // ISO 8601; null unless voided
81
106
  }
82
107
  \`\`\`
83
108
 
@@ -88,6 +113,12 @@ interface ExampleType {
88
113
  | {Service} | {What we use it for} | {Rate limits, quirks} |
89
114
  ```
90
115
 
116
+ **Every field carries its meaning inline** — trailing `//` by default; a JSDoc
117
+ block only when a line won't do (units, constraints, nullability semantics).
118
+ This is the two-homes rule: a fact with two homes goes missing from the one
119
+ you are reading, and the un-annotated type is the home readers actually open.
120
+ `fields.md` keeps only what a type cannot express — the journey.
121
+
91
122
  ---
92
123
 
93
124
  ## fields.md
@@ -95,18 +126,20 @@ interface ExampleType {
95
126
  ```markdown
96
127
  # Fields — {Feature Name}
97
128
 
98
- Document which fields flow from source (BE or 3rd-party API) to destination (UI or your BE),
99
- with descriptions so you can glance at the spec instead of traversing the codebase.
129
+ Document which fields flow from source (BE or 3rd-party API) to destination
130
+ (UI or your BE). The Description column is about the TRANSFORMATION — what
131
+ happens to the field on the way — never about what the field means; meaning
132
+ lives on the type in api.md.
100
133
 
101
134
  ## Response Fields — {Endpoint or Source Name}
102
135
 
103
136
  > Source: `GET /api/...` or `{ThirdParty} → BE → FE`
104
137
 
105
- | Source Field | UI Label / FE Key | Type | Nullable | Description |
138
+ | Source Field | UI Label / FE Key | Type | Nullable | Transformation |
106
139
  |---|---|---|---|---|
107
- | `user_full_name` | Full Name | `string` | no | Display name shown in profile card |
108
- | `created_at` | Created | `string (ISO 8601)` | no | Formatted to `MMM D, YYYY` in UI |
109
- | `metadata.region` | Region | `string` | yes | Omitted from UI when null |
140
+ | `user_full_name` | Full Name | `string` | no | rendered as-is in profile card |
141
+ | `created_at` | Created | `string (ISO 8601)` | no | formatted to `MMM D, YYYY` in UI |
142
+ | `metadata.region` | Region | `string` | yes | omitted from UI when null |
110
143
 
111
144
  ### Forwarding Chain (3rd-party → BE → FE)
112
145
 
@@ -121,10 +154,10 @@ Use this sub-section when your BE proxies a 3rd-party API and renames fields.
121
154
 
122
155
  > Sent from FE to `POST /api/...`
123
156
 
124
- | FE Key | BE Field | Type | Required | Description |
157
+ | FE Key | BE Field | Type | Required | Transformation |
125
158
  |---|---|---|---|---|
126
- | `email` | `email` | `string` | yes | Validated client-side before send |
127
- | `preferredName` | `preferred_name` | `string` | no | Optional; omitted if empty |
159
+ | `email` | `email` | `string` | yes | validated client-side before send |
160
+ | `preferredName` | `preferred_name` | `string` | no | omitted from payload if empty |
128
161
  ```
129
162
 
130
163
  ---
@@ -134,25 +167,35 @@ Use this sub-section when your BE proxies a 3rd-party API and renames fields.
134
167
  ```markdown
135
168
  # Implementation — {Feature Name}
136
169
 
137
- ## Overview
138
- One paragraph on how the feature works end-to-end.
139
-
140
- ## Key Files
141
-
142
170
  | File | Role |
143
171
  |------|------|
144
172
  | `src/...` | ... |
145
173
 
146
- ## Data Flow
147
- Step-by-step description of how data moves through the system.
174
+ ## Data flow
175
+
176
+ 1. {step} — {what happens}
177
+ 2. {step} — {what happens}
148
178
 
149
- ## Patterns Used
150
- Non-obvious patterns, abstractions, or conventions introduced.
179
+ ## Patterns
180
+
181
+ | Pattern | Where | Why not the obvious thing |
182
+ |---|---|---|
183
+ | {pattern used} | {file or layer} | {what it displaced, one line} |
151
184
 
152
185
  ## Dependencies
186
+
153
187
  Internal modules or external packages this feature leans on heavily.
188
+
189
+ ## Overview *(only when the file table does not already tell the story)*
190
+
191
+ {prose — the end-to-end narrative, when the table and data flow leave it
192
+ untold}
154
193
  ```
155
194
 
195
+ Data flow is a numbered list — it is step-by-step by definition and was never
196
+ prose. The Patterns table's third column is mandatory: a pattern recorded
197
+ without the alternative it displaced is trivia, not guidance.
198
+
156
199
  ---
157
200
 
158
201
  ## quirks.md
@@ -160,10 +203,25 @@ Internal modules or external packages this feature leans on heavily.
160
203
  ```markdown
161
204
  # Quirks — {Feature Name}
162
205
 
163
- ## {Quirk Title}
206
+ | # | Quirk | Trigger | Severity | Mitigated |
207
+ |---|---|---|---|---|
208
+ | Q1 | {symptom, one line} | {what sets it off} | low / medium / high | yes / no / partial |
209
+
210
+ ## Q1 — {Quirk Title}
164
211
 
165
- **Severity:** low | medium | high
166
212
  **Discovered:** {date or commit}
167
213
 
168
- Description of the edge case, gotcha, or known issue. Include what triggers it and how it's handled or worked around.
214
+ **Symptom:** what a reader will observe.
215
+ **Trigger:** what sets it off.
216
+ **Cause:** why it happens.
217
+ **Mitigation:** what to do — or "none", said plainly.
218
+
219
+ {prose — only the part that genuinely needs explaining}
169
220
  ```
221
+
222
+ Quirk headings are `## Q<n> — Title`, always — `durable-citations.test.mjs`
223
+ resolves every `Q<n>` a spec cites against these headings, so the format is a
224
+ contract, not a style. Numbers are unique and ascending, never reused and
225
+ never renumbered (citations from other specs may point at them). The
226
+ `Mitigated` column is a checkable claim: `yes / no / partial`, with `partial`
227
+ explained in the body's **Mitigation** field.