@jabworks/condux 0.2.0 → 0.3.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.
Files changed (48) hide show
  1. package/README.md +27 -29
  2. package/index.js +21 -0
  3. package/package.json +6 -4
  4. package/skills/code-review/SKILL.md +136 -0
  5. package/skills/code-review/evals/trigger_eval.json +22 -0
  6. package/skills/discovery/SKILL.md +242 -0
  7. package/skills/discovery/evals/trigger_eval.json +24 -0
  8. package/skills/discovery/references/choice-server.js +216 -0
  9. package/skills/discovery/references/mockup-picker.md +90 -0
  10. package/skills/discovery/references/package.json +3 -0
  11. package/skills/draft-plan/SKILL.md +229 -0
  12. package/skills/draft-plan/evals/trigger_eval.json +22 -0
  13. package/skills/draft-plan/references/plan-template.md +96 -0
  14. package/skills/finalize/SKILL.md +123 -0
  15. package/skills/finalize/evals/trigger_eval.json +22 -0
  16. package/skills/finalize/references/rationalization-table.md +15 -0
  17. package/skills/plan-review/SKILL.md +215 -0
  18. package/skills/plan-review/evals/trigger_eval.json +22 -0
  19. package/skills/plan-review/references/annotate-server.js +465 -0
  20. package/skills/plan-review/references/install-codex-hook.sh +112 -0
  21. package/skills/plan-review/references/package.json +3 -0
  22. package/skills/plan-review/references/plan-review-template.html +730 -0
  23. package/skills/preflight/SKILL.md +128 -0
  24. package/skills/preflight/evals/trigger_eval.json +26 -0
  25. package/skills/root-cause-analysis/SKILL.md +82 -0
  26. package/skills/root-cause-analysis/evals/trigger_eval.json +22 -0
  27. package/skills/subagent-deployment/SKILL.md +105 -0
  28. package/skills/subagent-deployment/evals/trigger_eval.json +22 -0
  29. package/skills/subagent-deployment/references/safety-checklist.md +54 -0
  30. package/skills/subagent-execution/SKILL.md +182 -0
  31. package/skills/subagent-execution/agents/coder.md +55 -0
  32. package/skills/subagent-execution/agents/explorer.md +77 -0
  33. package/skills/subagent-execution/agents/planner.md +101 -0
  34. package/skills/subagent-execution/agents/researcher.md +78 -0
  35. package/skills/subagent-execution/evals/trigger_eval.json +22 -0
  36. package/skills/subagent-execution/references/install-codex-agents.mjs +98 -0
  37. package/skills/subagent-execution/references/review-package.sh +29 -0
  38. package/skills/subagent-execution/references/spawn-rules.md +88 -0
  39. package/skills/subagent-execution/references/task-brief.sh +39 -0
  40. package/skills/technical-spec/SKILL.md +190 -0
  41. package/skills/technical-spec/evals/trigger_eval.json +23 -0
  42. package/skills/technical-spec/references/scaffold.sh +98 -0
  43. package/skills/technical-spec/references/templates.md +159 -0
  44. package/skills/test-first-development/SKILL.md +121 -0
  45. package/skills/test-first-development/evals/trigger_eval.json +22 -0
  46. package/skills/test-first-development/references/rationalization-table.md +16 -0
  47. package/skills/workflow/SKILL.md +241 -0
  48. package/skills/workflow/evals/trigger_eval.json +30 -0
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env node
2
+ // Local option-picker surface for /discovery visual mockups. Serves an
3
+ // agent-authored, self-contained HTML mockup, injects click-to-select wiring,
4
+ // and delivers the user's pick back to the agent over a long-poll. No npm deps.
5
+ // Binds 127.0.0.1 only. One-shot: the server exits once a choice is delivered.
6
+ //
7
+ // Usage:
8
+ // node choice-server.js <mockup.html> [--multi] [--port 7788]
9
+ //
10
+ // The agent tags each option element in the mockup with data-choice="<label>",
11
+ // launches this server in the background, then BLOCKS on
12
+ // GET /api/choice (a long-poll) which resolves when the user picks:
13
+ // {"choices":["Option B"],"note":"<free text>","submittedAt":"<iso>"}
14
+ //
15
+ // Single mode (default): clicking an option submits it immediately.
16
+ // Multi mode (--multi): clicking toggles; a bottom bar sends the set + note.
17
+ //
18
+ // Default port 7788 (distinct from plan-review's 7777) so a discovery picker
19
+ // and a plan-review steer server can run at once. Diagnostics go to stderr.
20
+ 'use strict';
21
+
22
+ const http = require('http');
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+ const { exec } = require('child_process');
26
+
27
+ const log = console.error; // stdout stays clean; the agent talks to us over HTTP
28
+
29
+ const MULTI = process.argv.includes('--multi');
30
+ const portArg = (function () { const i = process.argv.indexOf('--port'); return i >= 0 ? parseInt(process.argv[i + 1], 10) : NaN; })();
31
+ const PORT = !isNaN(portArg) ? portArg : 7788;
32
+
33
+ let choiceWaiter = null; // pending GET /api/choice response
34
+ let pendingChoice = null; // choice that arrived before the agent polled
35
+ let delivered = false; // one-shot guard
36
+
37
+ let mockupFile;
38
+
39
+ function fail(msg) { console.error(' choice-picker: ' + msg); process.exit(1); }
40
+
41
+ function readMockup() {
42
+ try { return fs.readFileSync(mockupFile, 'utf8'); } catch (e) { return ''; }
43
+ }
44
+
45
+ // Injected client: wires [data-choice] elements to POST /api/choice. Kept
46
+ // dependency-free and defensive so it works inside whatever HTML the agent wrote.
47
+ function injectedScript() {
48
+ return `
49
+ <style>
50
+ #__vc_banner{position:fixed;top:0;left:0;right:0;z-index:99998;font:600 13px/1.4 system-ui,sans-serif;
51
+ background:#1f2937;color:#fff;padding:10px 16px;text-align:center;box-shadow:0 1px 6px rgba(0,0,0,.25)}
52
+ body{padding-top:44px}
53
+ [data-choice]{cursor:pointer;transition:outline-color .12s,box-shadow .12s;outline:2px solid transparent;outline-offset:2px}
54
+ [data-choice]:hover{outline-color:#93c5fd}
55
+ [data-choice].__vc_sel{outline-color:#2563eb;box-shadow:0 0 0 4px rgba(37,99,235,.18)}
56
+ #__vc_bar{position:fixed;bottom:0;left:0;right:0;z-index:99998;display:none;gap:10px;align-items:center;
57
+ background:#111827;color:#fff;padding:12px 16px;box-shadow:0 -1px 8px rgba(0,0,0,.3);font:14px system-ui,sans-serif}
58
+ #__vc_bar.__vc_show{display:flex}
59
+ #__vc_note{flex:1;padding:8px 10px;border-radius:6px;border:1px solid #374151;background:#1f2937;color:#fff;font:14px system-ui,sans-serif}
60
+ #__vc_send{padding:8px 16px;border:0;border-radius:6px;background:#2563eb;color:#fff;font:600 14px system-ui,sans-serif;cursor:pointer}
61
+ #__vc_send:disabled{background:#374151;cursor:default}
62
+ #__vc_done{position:fixed;inset:0;z-index:99999;display:none;align-items:center;justify-content:center;
63
+ background:rgba(17,24,39,.92);color:#fff;font:600 18px system-ui,sans-serif;text-align:center;padding:24px}
64
+ #__vc_done.__vc_show{display:flex}
65
+ </style>
66
+ <div id="__vc_banner"></div>
67
+ <div id="__vc_bar"><span id="__vc_count">0 selected</span>
68
+ <input id="__vc_note" placeholder="Optional note (e.g. B, but with A's header)…" />
69
+ <button id="__vc_send" disabled>Send selection →</button></div>
70
+ <div id="__vc_done">✓ Sent to the agent — you can close this tab.</div>
71
+ <script>
72
+ (function(){
73
+ var MULTI = ${MULTI ? 'true' : 'false'};
74
+ var opts = [].slice.call(document.querySelectorAll('[data-choice]'));
75
+ var banner = document.getElementById('__vc_banner');
76
+ var done = document.getElementById('__vc_done');
77
+ if(!opts.length){ banner.textContent = 'No options found — tag each option element with data-choice="…".'; return; }
78
+ banner.textContent = MULTI
79
+ ? 'Click options to select, add an optional note, then Send. Your pick goes back to the agent.'
80
+ : 'Click an option to send your choice to the agent.';
81
+ var locked = false;
82
+ function post(payload){
83
+ if(locked) return; locked = true;
84
+ fetch('/api/choice',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
85
+ .then(function(){ done.classList.add('__vc_show'); })
86
+ .catch(function(){ locked = false; alert('Could not reach the picker server.'); });
87
+ }
88
+ if(!MULTI){
89
+ opts.forEach(function(el){
90
+ el.addEventListener('click', function(){ post({choices:[el.getAttribute('data-choice')]}); });
91
+ });
92
+ return;
93
+ }
94
+ var bar = document.getElementById('__vc_bar');
95
+ var count = document.getElementById('__vc_count');
96
+ var note = document.getElementById('__vc_note');
97
+ var send = document.getElementById('__vc_send');
98
+ var sel = [];
99
+ function refresh(){
100
+ count.textContent = sel.length + ' selected';
101
+ send.disabled = sel.length === 0;
102
+ bar.classList.toggle('__vc_show', true);
103
+ }
104
+ opts.forEach(function(el){
105
+ el.addEventListener('click', function(){
106
+ var label = el.getAttribute('data-choice');
107
+ var i = sel.indexOf(label);
108
+ if(i >= 0){ sel.splice(i,1); el.classList.remove('__vc_sel'); }
109
+ else { sel.push(label); el.classList.add('__vc_sel'); }
110
+ refresh();
111
+ });
112
+ });
113
+ send.addEventListener('click', function(){ if(sel.length) post({choices:sel, note:note.value.trim()}); });
114
+ })();
115
+ </script>`;
116
+ }
117
+
118
+ function serveMockup(res) {
119
+ let html = readMockup();
120
+ const inject = injectedScript();
121
+ if (/<\/body>/i.test(html)) html = html.replace(/<\/body>/i, inject + '\n</body>');
122
+ else html += inject;
123
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
124
+ res.end(html);
125
+ }
126
+
127
+ function sendJson(res, code, obj) {
128
+ res.writeHead(code, { 'Content-Type': 'application/json' });
129
+ res.end(JSON.stringify(obj));
130
+ }
131
+
132
+ // Deliver a choice to the agent's long-poll, then shut down (one-shot).
133
+ function deliver(payload) {
134
+ if (delivered) return;
135
+ delivered = true;
136
+ if (choiceWaiter) {
137
+ try { choiceWaiter.writeHead(200, { 'Content-Type': 'application/json' }); choiceWaiter.end(JSON.stringify(payload)); } catch (e) { /* client gone */ }
138
+ choiceWaiter = null;
139
+ } else {
140
+ pendingChoice = payload; // agent hasn't polled yet — the next GET picks it up
141
+ delivered = false; // not truly delivered until a GET drains it
142
+ return;
143
+ }
144
+ log('\n Choice: ' + JSON.stringify(payload.choices) + (payload.note ? ' note: ' + payload.note : '') + ' — delivered to agent. Stopping.\n');
145
+ setTimeout(function () { process.exit(0); }, 300);
146
+ }
147
+
148
+ function handler(req, res) {
149
+ const url = new URL(req.url, 'http://127.0.0.1');
150
+ const p = url.pathname;
151
+
152
+ if (req.method === 'GET' && p === '/') return serveMockup(res);
153
+
154
+ if (req.method === 'GET' && p === '/api/choice') {
155
+ if (pendingChoice) { const c = pendingChoice; pendingChoice = null; delivered = true; sendJson(res, 200, c); log('\n Choice delivered to agent. Stopping.\n'); return setTimeout(function () { process.exit(0); }, 300); }
156
+ res.setTimeout(0); // a human may take minutes — don't close the idle socket
157
+ choiceWaiter = res;
158
+ req.on('close', function () { if (choiceWaiter === res) choiceWaiter = null; });
159
+ return;
160
+ }
161
+
162
+ if (req.method === 'POST' && p === '/api/choice') {
163
+ let body = '';
164
+ req.on('data', function (c) { body += c; if (body.length > 1e6) req.destroy(); });
165
+ req.on('end', function () {
166
+ try {
167
+ const data = JSON.parse(body);
168
+ const choices = Array.isArray(data.choices) ? data.choices : (data.choice ? [data.choice] : []);
169
+ if (!choices.length) return sendJson(res, 400, { error: 'no choices' });
170
+ sendJson(res, 200, { status: 'received' });
171
+ deliver({ choices: choices, note: (data.note || '').trim(), submittedAt: new Date().toISOString() });
172
+ } catch (e) {
173
+ sendJson(res, 400, { error: 'invalid JSON' });
174
+ }
175
+ });
176
+ return;
177
+ }
178
+
179
+ res.writeHead(404);
180
+ res.end();
181
+ }
182
+
183
+ let server;
184
+ function listen() {
185
+ server = http.createServer(handler);
186
+ server.on('error', function (e) {
187
+ if (e && e.code === 'EADDRINUSE') fail('port ' + PORT + ' is in use — pass a free --port <n>.');
188
+ fail(String((e && e.message) || e));
189
+ });
190
+ server.listen(PORT, '127.0.0.1', function () {
191
+ const url = 'http://127.0.0.1:' + server.address().port;
192
+ log('\n Option picker → ' + url + (MULTI ? ' (multi-select)' : ''));
193
+ log(' Mockup → ' + mockupFile);
194
+ log(' Choice → GET ' + url + '/api/choice (long-poll)');
195
+ log('\n Pick in the browser; the choice returns to the agent. Ctrl+C to stop.\n');
196
+ const opener = process.platform === 'darwin' ? 'open' :
197
+ process.platform === 'win32' ? 'start ""' : 'xdg-open';
198
+ exec(opener + ' ' + url, function () {});
199
+ });
200
+ }
201
+
202
+ process.on('SIGINT', function () {
203
+ log('\n Option picker stopped.\n');
204
+ if (server) server.close(function () { process.exit(0); }); else process.exit(0);
205
+ });
206
+
207
+ // First non-flag arg is the mockup file (skip --port's value).
208
+ const args = process.argv.slice(2);
209
+ let file = null;
210
+ for (let i = 0; i < args.length; i++) {
211
+ if (args[i] === '--port') { i++; continue; }
212
+ if (args[i][0] !== '-') { file = args[i]; break; }
213
+ }
214
+ if (!file || !fs.existsSync(file)) fail('mockup file not found — pass a self-contained HTML file path.');
215
+ mockupFile = path.resolve(file);
216
+ listen();
@@ -0,0 +1,90 @@
1
+ # Mockup Picker
2
+
3
+ Reference for `/discovery`. Use when spatial or visual content communicates better
4
+ than text alone — HTML option mockups, plus the click-to-pick server that returns
5
+ the user's choice straight to the agent.
6
+
7
+ ## When to Go Visual
8
+
9
+ **Use a browser visual** when:
10
+ - Comparing 2–4 UI layout options side-by-side
11
+ - Architecture diagrams where spatial relationships matter
12
+ - Component hierarchy that's easier to parse visually
13
+ - Design polish decisions where aesthetic is the question
14
+
15
+ **Stay in terminal** when:
16
+ - Clarifying requirements (A/B/C prose is fine)
17
+ - Tradeoff analysis (a markdown table works)
18
+ - The question has a clear right answer
19
+ - The user would answer in one word
20
+
21
+ ## How to Generate
22
+
23
+ Write a **self-contained HTML file** — inline all CSS, no external dependencies:
24
+
25
+ ```bash
26
+ # Write the file, then open:
27
+ xdg-open /tmp/discovery-<topic>-$(date +%Y%m).html # Linux
28
+ open /tmp/discovery-<topic>-$(date +%Y%m).html # macOS
29
+ ```
30
+
31
+ Use semantic filenames: `discovery-checkout-flow-202601.html`
32
+
33
+ Tag each option's container element with `data-choice="<label>"` (e.g.
34
+ `<div data-choice="Option A">`). This is inert for a plain open-in-browser
35
+ glance, but it's what the interactive picker below wires up — so add it by
36
+ default.
37
+
38
+ ## HTML Guidelines
39
+
40
+ - Max 2–4 options per page — more causes decision paralysis
41
+ - Show real content, not lorem ipsum
42
+ - Label each option clearly: **Option A**, **Option B**
43
+ - Tag each option container with `data-choice="Option A"` for click-to-select
44
+ - One-line rationale under each option
45
+ - Keep it light — mockup fidelity, not production polish
46
+
47
+ ## Interactive Pick (Optional)
48
+
49
+ For a plain glance, opening the file is enough — the user tells you their pick
50
+ in chat. When you want the choice to come **straight back to you** without the
51
+ user re-typing it, serve the mockup through the picker server. The agent
52
+ launches it; the user never starts anything.
53
+
54
+ Locate the script from the installed `discovery` skill and launch it in the
55
+ background, pointing at the mockup file:
56
+
57
+ ```bash
58
+ CHOICE=$(find ~/.claude ~/.agents ~/.codex -name "choice-server.js" -path "*/discovery/*" 2>/dev/null | head -1)
59
+ node "$CHOICE" /tmp/discovery-checkout-flow-202601.html # single-select
60
+ node "$CHOICE" /tmp/discovery-checkout-flow-202601.html --multi # multi-select
61
+ ```
62
+
63
+ It opens the browser automatically. In single mode a click submits instantly;
64
+ in `--multi` mode clicks toggle a selection and a bottom bar sends the set plus
65
+ an optional note. Then **block on the long-poll** and continue once it resolves:
66
+
67
+ ```bash
68
+ curl -s http://127.0.0.1:7788/api/choice
69
+ # → {"choices":["Option B"],"note":"B, but with A's header","submittedAt":"…"}
70
+ ```
71
+
72
+ The server is one-shot: it delivers the pick and exits — no HTML is written to
73
+ disk, nothing for the user to clean up. Port defaults to `7788` (distinct from
74
+ `plan-review`'s `7777`, so both can run at once); pass `--port <n>` to override.
75
+
76
+ ## What NOT to Do
77
+
78
+ ```
79
+ ✗ Building a multi-file app just for a mockup
80
+ ✗ Making the user start or manage a server (the agent launches the picker itself)
81
+ ✗ Showing more than 4 options at once
82
+ ✗ Lorem ipsum placeholders when real content is possible
83
+ ```
84
+
85
+ ## Return to Terminal
86
+
87
+ After the user reviews the visual, return to the discovery sign-off flow. If
88
+ you used the picker, the chosen option(s) and any note arrive over the
89
+ long-poll; otherwise capture the decision from chat. Note which option was
90
+ chosen, then continue with `/draft-plan` or the next step.
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,229 @@
1
+ ---
2
+ name: draft-plan
3
+ description: "Turns a signed-off design into an executable plan of lean task cards (what, why, gotchas, dependencies). Writes Markdown; review in the browser via plan-review. Run for LARGE tasks after /discovery sign-off. Never writes a plan without a signed-off design — if discovery hasn't run, apply the soft gate first."
4
+ argument-hint: "<feature name or design summary>"
5
+ effort: high
6
+ ---
7
+
8
+ # /draft-plan
9
+
10
+ Turn a signed-off design into a clear, executable plan. Lean task cards, not micro-step novels.
11
+
12
+ ## Usage
13
+
14
+ ```
15
+ /draft-plan $ARGUMENTS
16
+ ```
17
+
18
+ ## Before Writing
19
+
20
+ 1. Confirm discovery has run and design is signed off. First glob
21
+ `.condux/designs/*<slug>*.md` and `specs/<slug>/` (slug = kebab-case
22
+ of the feature name) for an existing signed-off design — if found,
23
+ treat this check as satisfied without asking. Otherwise ask: "We
24
+ haven't aligned on the design yet — run /discovery first, or confirm
25
+ you want to skip it."
26
+
27
+ The plan is written as Markdown — optimized for AI agent consumption during
28
+ execution. To read it in the browser, use `plan-review` (see After Saving);
29
+ no separate HTML file is produced.
30
+
31
+ ## How It Works
32
+
33
+ ```
34
+ ┌──────────────────────────────────────────────────────────────────┐
35
+ │ DRAFT-PLAN │
36
+ ├──────────────────────────────────────────────────────────────────┤
37
+ │ Step 1: MAP FILES │
38
+ │ List every file to be created or modified. │
39
+ │ Assign one clear responsibility per file. │
40
+ │ Decomposition decisions get locked in here. │
41
+ │ │
42
+ │ Step 2: WRITE TASK CARDS │
43
+ │ Each card = one meaningful unit of work. │
44
+ │ See Task Card Format below. │
45
+ │ │
46
+ │ Step 3: INLINE SELF-REVIEW │
47
+ │ Check against design: │
48
+ │ ✓ Every requirement maps to a task │
49
+ │ ✓ No TBDs, TODOs, or "implement later" │
50
+ │ ✓ No undefined references (types, functions, methods) │
51
+ │ ✓ No "similar to Task N" shortcuts │
52
+ │ ✓ Dependencies between tasks are explicit │
53
+ │ │
54
+ │ Step 4: PRESENT TO USER │
55
+ │ Show plan in sections, get sign-off before saving. │
56
+ │ │
57
+ │ Step 5: SAVE │
58
+ │ Write to .condux/plans/ per AGENTS.md or default path. │
59
+ │ Do NOT modify the plan file after saving. │
60
+ └──────────────────────────────────────────────────────────────────┘
61
+ ```
62
+
63
+ ## Task Card Format
64
+
65
+ Each task card is a **top-level `##` heading** — this makes every task a
66
+ first-class entry in the plan-review navigation menu (the TOC is generated
67
+ from headings, and `###` renders as a greyed sub-entry).
68
+
69
+ ```markdown
70
+ ## Task N: <Short Name>
71
+
72
+ **What:** One paragraph — what this task builds or changes.
73
+
74
+ **Why:** One sentence — why this is needed / what it enables.
75
+
76
+ **Files:**
77
+
78
+ - Create: `exact/path/to/file.ts`
79
+ - Modify: `exact/path/to/existing.ts:123-145`
80
+
81
+ **Interfaces:**
82
+
83
+ - Consumes: what this task uses from earlier tasks — exact names / signatures
84
+ - Produces: what later tasks rely on — exact function names, parameter and
85
+ return types (or "None" for a leaf task)
86
+
87
+ **Sketch:** _(optional)_
88
+
89
+ ```ts
90
+ // only the code worth annotating before it's written
91
+ ```
92
+
93
+ **Gotchas:**
94
+
95
+ - Use `dayjs` for date handling, not native JS Date
96
+ - This touches the auth middleware — don't change its signature
97
+ - [Any project conventions or known quirks relevant to this task]
98
+
99
+ **Dependencies:** Task 2, Task 3 (or "None")
100
+ ```
101
+
102
+ The `Interfaces` block carries the typed contract between tasks: a task's
103
+ implementer (especially a subagent) sees only their own card, so `Consumes`
104
+ / `Produces` is how neighbouring tasks agree on exact names and types. This
105
+ is what prevents drift like `clearLayers()` in Task 3 vs `clearFullLayers()`
106
+ in Task 7.
107
+
108
+ ## Code Sketches
109
+
110
+ Plans are reviewed by annotation before any code is written, so the cheapest
111
+ place to catch a bad approach is the plan. Include a **Sketch** whenever
112
+ seeing the code changes whether you'd approve the task:
113
+
114
+ - ✓ The non-obvious algorithm or the tricky transform
115
+ - ✓ A key data shape, schema, or type/interface definition
116
+ - ✓ A function signature whose contract other tasks depend on
117
+
118
+ Keep sketches to the code that carries a decision. They are illustrative
119
+ intent for the reviewer to tweak — not the final implementation, and not a
120
+ substitute for the implementer's judgement. Do **not** sketch:
121
+
122
+ - ✗ Boilerplate the implementer will obviously write (CRUD, wiring, imports)
123
+ - ✗ Full file bodies — show the part worth reviewing, elide the rest with `…`
124
+ - ✗ Test code (that belongs to `/test-first-development`)
125
+ - ✗ The TDD micro-step cycle (write test → run → implement → run → commit)
126
+
127
+ ## Plan Document Structure
128
+
129
+ Fill in `references/plan-template.md` — it is the canonical skeleton, kept
130
+ consistent so the plan-review nav renders the same predictable TOC every
131
+ time (`Overview · Global Constraints · Files Affected · Task Checklist ·
132
+ Task 1…N`). Do not reinvent the section set or reorder it.
133
+
134
+ ```markdown
135
+ # Plan: <Feature Name>
136
+
137
+ > Date: YYYY-MM-DD
138
+
139
+ ## Overview
140
+
141
+ **Goal:** one sentence. **Approach:** 2-3 sentences. **Tech / conventions:** key libs and rules.
142
+
143
+ ## Global Constraints
144
+
145
+ - Project-wide rules copied verbatim from the design/spec (delete if none).
146
+
147
+ ## Files Affected
148
+
149
+ - `path/to/file.ts` — what it does / what changes
150
+
151
+ ## Task Checklist
152
+
153
+ - [ ] Task 1: ...
154
+ - [ ] Task 2: ...
155
+
156
+ ---
157
+
158
+ [Task cards follow — each a top-level ## heading]
159
+ ```
160
+
161
+ ## Save Path
162
+
163
+ Write the plan to `.condux/plans/YYYY-MM-DD-<feature>.md`.
164
+
165
+ `.condux/` is gitignored working state, created on demand at the git root
166
+ (see `/workflow` → Artifacts). Before the first write, make sure it's
167
+ ignored — see the bootstrap step there.
168
+
169
+ Check `AGENTS.md` for project-specific overrides.
170
+
171
+ ## After Saving
172
+
173
+ Once the plan file is saved, always ask — regardless of whether this
174
+ skill was invoked via `/workflow` or standalone:
175
+
176
+ > "Plan saved to `<path>`. Want to review it in the browser before
177
+ > implementing, or go straight to implementation?"
178
+
179
+ Accept either answer, same as any other soft gate in this skill.
180
+
181
+ **If review chosen:** locate `annotate-server.js` from the installed
182
+ `plan-review` skill (`find ~/.claude ~/.codex ~/.agents -name
183
+ annotate-server.js -path '*plan-review*' 2>/dev/null | head -1`) and
184
+ launch it in `--steer` mode against the saved plan file:
185
+ ```bash
186
+ node /path/to/plan-review/references/annotate-server.js .condux/plans/<file>.md --steer
187
+ ```
188
+ Poll `GET http://127.0.0.1:7777/api/decision` (long-poll — blocks until a
189
+ decision is submitted) and branch on the result:
190
+ - **Approve** → proceed to implementation, using any feedback as notes.
191
+ - **Request Revisions** → revise the plan file in place per the feedback
192
+ (the open browser tab live-reloads over SSE), then poll again.
193
+ - **Deny** → stop; report the feedback and rework the approach before
194
+ re-planning.
195
+
196
+ **If straight to implementation chosen:** proceed directly, no server
197
+ launch.
198
+
199
+ This applies to the plan doc this skill produces (LARGE tier).
200
+ `/workflow`'s MEDIUM-tier quick-plan uses the same section shape and card
201
+ fields (Overview · Files · Interfaces · Sketch · Gotchas) inline and lean —
202
+ it is not written via this skill, but stays consistent with this structure.
203
+
204
+ ## Plan Failures — Never Write These
205
+
206
+ ```
207
+ ✗ "TBD", "TODO", "implement later", "fill in details"
208
+ ✗ "Add appropriate error handling" (be specific)
209
+ ✗ "Similar to Task N" (repeat the content)
210
+ ✗ Steps that describe what to do without saying what changes
211
+ ✗ References to types or functions not defined anywhere in the plan
212
+ ✗ Micro-steps (write test → run test → write code → run test → commit)
213
+ ```
214
+
215
+ ## Task Granularity
216
+
217
+ Tasks should be **meaningful units of work**, not micro-steps. A task is something a developer would recognize as a coherent piece of work — not "write one function" and not "implement the whole feature."
218
+
219
+ Ask yourself: could this task be reviewed as a standalone PR? If yes, it's the right size.
220
+
221
+ ## What Does NOT Happen
222
+
223
+ ```
224
+ ✗ Full implementations or boilerplate (sketch decision-carrying code only — see Code Sketches)
225
+ ✗ Exact commands with expected output
226
+ ✗ Test code in the plan (tests are written during /test-first-development)
227
+ ✗ Modifying the plan file after it's saved
228
+ ✗ Writing a plan without design sign-off
229
+ ```
@@ -0,0 +1,22 @@
1
+ [
2
+ { "query": "write the implementation plan", "should_trigger": true, "expected_skill": "draft-plan", "accept": ["workflow"] },
3
+ { "query": "turn the design into task cards", "should_trigger": true, "expected_skill": "draft-plan" },
4
+ { "query": "plan out the epic we signed off yesterday", "should_trigger": true, "expected_skill": "draft-plan" },
5
+ { "query": "create the .condux/plans file for this feature", "should_trigger": true, "expected_skill": "draft-plan" },
6
+ { "query": "break this down into tasks with dependencies", "should_trigger": true, "expected_skill": "draft-plan" },
7
+ { "query": "write-plan for checkout v2", "should_trigger": true, "expected_skill": "draft-plan" },
8
+ { "query": "we havent designed this yet but write a plan anyway", "should_trigger": true, "expected_skill": "draft-plan", "accept": ["discovery"] },
9
+ { "query": "sketch the code for task 3 in the plan", "should_trigger": true, "expected_skill": "draft-plan", "kind": "in-context" },
10
+ { "query": "the plan needs revision per the review feedback", "should_trigger": true, "expected_skill": "draft-plan" },
11
+ { "query": "whats the task card format again", "should_trigger": true, "expected_skill": "draft-plan", "kind": "in-context" },
12
+ { "query": "plan for migrating to app router, design is signed off", "should_trigger": true, "expected_skill": "draft-plan" },
13
+ { "query": "how big should a task be, one function or the whole feature", "should_trigger": true, "expected_skill": "draft-plan", "kind": "in-context" },
14
+ { "query": "can I edit the plan file after saving it", "should_trigger": true, "expected_skill": "draft-plan", "kind": "in-context" },
15
+ { "query": "quick inline plan for a medium sized task", "should_trigger": true, "expected_skill": "workflow" },
16
+ { "query": "review the plan in the browser before implementing", "should_trigger": true, "expected_skill": "plan-review" },
17
+ { "query": "execute the plan with agents", "should_trigger": true, "expected_skill": "subagent-execution" },
18
+ { "query": "design isnt agreed yet, help me align first", "should_trigger": true, "expected_skill": "discovery" },
19
+ { "query": "add a task to my todo list", "should_trigger": false, "expected_skill": null },
20
+ { "query": "plan my sprint for next week", "should_trigger": false, "expected_skill": null },
21
+ { "query": "make a project timeline gantt chart", "should_trigger": false, "expected_skill": null }
22
+ ]
@@ -0,0 +1,96 @@
1
+ # Plan: <Feature Name>
2
+
3
+ > Date: YYYY-MM-DD
4
+
5
+ ## Overview
6
+
7
+ **Goal:** One sentence — what this builds.
8
+
9
+ **Approach:** 2–3 sentences on the chosen direction.
10
+
11
+ **Tech / conventions:** Key libraries, patterns, and rules in play for this work.
12
+
13
+ ## Global Constraints
14
+
15
+ Project-wide rules that every task must honour — copy exact values verbatim
16
+ from the design/spec, one line each. Delete this section only if there are
17
+ genuinely none.
18
+
19
+ - <version floor / dependency limit>
20
+ - <naming or copy rule>
21
+ - <platform / runtime requirement>
22
+
23
+ ## Files Affected
24
+
25
+ - `path/to/file.ts` — what it does / what changes
26
+ - `path/to/other.ts:120-160` — the specific region touched
27
+
28
+ ## Task Checklist
29
+
30
+ - [ ] Task 1: <Short Name>
31
+ - [ ] Task 2: <Short Name>
32
+ - [ ] Task 3: <Short Name>
33
+
34
+ ---
35
+
36
+ ## Task 1: <Short Name>
37
+
38
+ **What:** One paragraph — what this task builds or changes.
39
+
40
+ **Why:** One sentence — why this is needed / what it enables.
41
+
42
+ **Files:**
43
+
44
+ - Create: `exact/path/to/file.ts`
45
+ - Modify: `exact/path/to/existing.ts:123-145`
46
+
47
+ **Interfaces:**
48
+
49
+ - Consumes: what this task uses from earlier tasks — exact names / signatures
50
+ - Produces: what later tasks rely on — exact function names, parameter and
51
+ return types. A task's implementer sees only their own card; this block is
52
+ how neighbouring tasks learn the names and types they share. Use "None" for
53
+ a leaf task.
54
+
55
+ **Sketch:** _(optional — include only where seeing the code changes whether
56
+ you'd approve: the non-obvious algorithm, a tricky transform, a key data
57
+ shape or type definition. Skip boilerplate the implementer will obviously
58
+ write.)_
59
+
60
+ ```ts
61
+ type Layer = { id: string; visible: boolean };
62
+
63
+ // core logic worth reviewing before it's written
64
+ function mergeLayers(base: Layer[], incoming: Layer[]): Layer[] {
65
+ // …the actual approach, concrete enough to annotate and tweak
66
+ }
67
+ ```
68
+
69
+ **Gotchas:**
70
+
71
+ - Use `dayjs` for date handling, not native JS `Date`
72
+ - This touches the auth middleware — don't change its signature
73
+ - <any project convention or known quirk relevant to this task>
74
+
75
+ **Dependencies:** Task 2, Task 3 (or "None")
76
+
77
+ ## Task 2: <Short Name>
78
+
79
+ **What:** …
80
+
81
+ **Why:** …
82
+
83
+ **Files:**
84
+
85
+ - Create: `…`
86
+
87
+ **Interfaces:**
88
+
89
+ - Consumes: …
90
+ - Produces: …
91
+
92
+ **Gotchas:**
93
+
94
+ - …
95
+
96
+ **Dependencies:** …