@jabworks/condux 0.4.1 → 0.5.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.4.1",
3
+ "version": "0.5.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: code-review
3
- description: "One-shot code review. Produces a diagnostic report categorized by severity (Critical / Important / Minor). Never fixes issues automatically. On-request only — never auto-triggers. After /finalize, ask once: \"Want a code review before merging?\" Trigger phrases: \"review this\", \"review before merge\", \"check this PR\"."
3
+ description: "One-shot code review. Produces a diagnostic report categorized by severity (Critical / Important / Minor). Never fixes issues automatically. On-request only — never auto-triggers. At workflow CP-2 (pre-finalize, on request) or after /finalize, ask once: \"Want a code review before merging?\" Trigger phrases: \"review this\", \"review before merge\", \"check this PR\". Not for reviewing a plan or spec before implementation — that's plan-review. Not for running the change to watch it work — that's live-verification."
4
4
  argument-hint: "<PR URL, diff, branch, or file path>"
5
5
  ---
6
6
 
@@ -17,7 +17,11 @@ One review pass. Categorized findings. You decide what to action. No fixing, no
17
17
 
18
18
  ## When This Runs
19
19
 
20
- After `/finalize` completes, ask once:
20
+ Two sanctioned entry points:
21
+
22
+ - **Workflow CP-2** ("Implementation done") — the user picks "Code review first"
23
+ and this skill runs on the diff before preflight/finalize.
24
+ - **After `/finalize` completes** — ask once:
21
25
 
22
26
  > "Want a code review before merging?"
23
27
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: discovery
3
- description: "Refine a rough idea into a signed-off design. Asks goal-level questions, surfaces alternatives, then runs a post-approach detail round (contracts, mappings, edge cases) that feeds the tech spec; presents the design in sections for sign-off before any planning or code begins. Trigger for LARGE tasks, when scope is unclear, or when the user wants to brainstorm or explore a rough idea. Also when resuming or continuing an existing design or design doc — the existing-design check offers resume-or-fresh. Acts as a soft gate before /draft-plan — if discovery hasn't run, ask the user if they want to skip it consciously."
3
+ description: "Refine a rough idea into a signed-off design. Asks goal-level questions, surfaces alternatives, then runs a post-approach detail round (contracts, mappings, edge cases) that feeds the tech spec (written via technical-spec at sign-off); presents the design in sections for sign-off before any planning or code begins. Trigger for LARGE tasks, when scope is unclear, or when the user wants to brainstorm or explore a rough idea. Also when resuming or continuing an existing design or design doc — the existing-design check offers resume-or-fresh. Acts as a soft gate before /draft-plan — if discovery hasn't run, ask the user if they want to skip it consciously."
4
4
  argument-hint: "<rough idea or feature description>"
5
5
  effort: high
6
6
  ---
@@ -18,7 +18,9 @@ Turn a rough idea into a clear, agreed-upon design. Nothing gets planned or buil
18
18
  ## How It Works
19
19
 
20
20
  Before Step 1, check for an existing design: glob `.condux/designs/*<slug>*.md`
21
- and `specs/<slug>/` (slug = kebab-case of the feature name). If either
21
+ and both spec scopes — `<package-root>/specs/<slug>/` and
22
+ `<git-root>/specs/<slug>/`, the workflow router's two-scope lookup (slug =
23
+ kebab-case of the feature name). If any
22
24
  exists, offer: "Found an existing design for this feature at `<path>` —
23
25
  resume from there, or start a fresh discovery?" Accept either answer, same
24
26
  as any other soft gate in this skill.
@@ -182,12 +184,14 @@ it in `--steer` mode against the saved design file (or the spec directory,
182
184
  if the design was saved as a tech spec — see Spec Integration below):
183
185
 
184
186
  ```bash
185
- node /path/to/plan-review/references/annotate-server.js .condux/designs/<file>.md --steer
187
+ node /path/to/plan-review/references/annotate-server.js .condux/designs/<file>.md --steer --no-reject
186
188
  ```
187
189
 
188
190
  Poll `GET http://127.0.0.1:7777/api/decision` (long-poll — blocks until a
189
191
  decision is submitted) and branch on the result. Design review is
190
- **accept-or-fix** — there is no Reject at this stage:
192
+ **accept-or-fix** — `--no-reject` hides the Reject verdict, which belongs to
193
+ plan review, not the design stage (directory/spec review hides it on its own;
194
+ the flag matters for single-file design review):
191
195
 
192
196
  - **Approve** → design is signed off; proceed to `/draft-plan`, carrying any
193
197
  feedback notes into the plan.
@@ -198,64 +202,12 @@ decision is submitted) and branch on the result. Design review is
198
202
 
199
203
  ## Spec Integration (Live Preview)
200
204
 
201
- Integrates with the `technical-spec` skill to persist the design and render it live while discovery runs.
202
-
203
- ### At discovery start
204
-
205
- Infer the feature slug (kebab-case from `$ARGUMENTS`). Specs live under
206
- `<git-root>/specs/`, mirroring the repo structure: check
207
- `<git-root>/specs/<pkg-relpath>/<feature-slug>/` (pkg-relpath = the nearest
208
- package root's path relative to the git root, empty at the root) and
209
- `<git-root>/specs/<feature-slug>/` for an existing spec.
210
-
211
- If found, offer:
212
-
213
- > "Found an existing spec for this feature. Open live preview while we refine the design? [y/n]"
214
-
215
- If yes, go straight to **Launch preview** below (skip scaffold + write — spec already exists).
216
-
217
- ### At sign-off
218
-
219
- The Markdown design doc (Step 7) is always written. The spec write-back is
220
- **default-on** — announce it rather than ask:
221
-
222
- > "Saving this as a tech spec too (decisions + the concern files from the
223
- > detail round) and opening the live preview — say no to skip."
224
-
225
- Unless the user opts out (the spec directory then becomes the target for the
226
- Design Review Loop above, in directory mode):
227
-
228
- 1. **Find scripts** — the scaffold from technical-spec, the preview from
229
- plan-review (its annotate server renders spec directories):
230
- ```bash
231
- SCAFFOLD=$(find ~/.claude ~/.codex ~/.agents -name "scaffold.sh" -path "*technical-spec*" 2>/dev/null | head -1)
232
- PREVIEW=$(find ~/.claude ~/.codex ~/.agents -name "annotate-server.js" -path "*plan-review*" 2>/dev/null | head -1)
233
- ```
234
- If either is missing, tell the user: "the `technical-spec` / `plan-review` skills weren't found — install the condux plugin to enable spec integration."
235
-
236
- 2. **Scaffold** the spec dir and capture the output:
237
- ```bash
238
- SCAFFOLD_OUT=$(bash "$SCAFFOLD" "<FeatureName>")
239
- SPEC_PATH=$(echo "$SCAFFOLD_OUT" | sed 's/^[^:]*://; s/ .*//')
240
- ```
241
- `SPEC_PATH` is an absolute path (e.g. `/repo/specs/apps/web/wan-config`).
242
- The scaffold script places specs under `<git-root>/specs/`, mirroring the
243
- repo structure, automatically.
244
-
245
- 3. **Write initial spec files** from the design into `$SPEC_PATH/`.
246
- `decisions.md` always (chosen approach + rationale). Then every concern
247
- the detail round produced answers for gets its file: `api.md`,
248
- `fields.md`, `quirks.md`, `implementation.md`. A detail-round answer
249
- that never lands in a spec file is a bug in the flow, not a judgment call.
250
-
251
- 4. **Launch preview** in the background, pointing at the absolute spec path:
252
- ```bash
253
- node "$PREVIEW" "$SPEC_PATH"
254
- ```
255
- Tell user: "Preview is live. The browser updates automatically as spec files change, and you can annotate any file and submit a decision. Ctrl+C in the terminal to stop."
256
-
257
- ### Keeping the spec current
258
-
259
- As discovery continues and design details shift, update the relevant spec files — the preview re-renders on every save. This is the main benefit: the spec stays in sync with the conversation instead of being written once at the end.
260
-
261
- If the user submits a decision in the preview, read `$SPEC_PATH/review.feedback.md` (notes grouped by file) and action it. Spec review is accept-or-fix (directory mode has no Reject): **Approve** = design is signed off, proceed; **Request Revisions** = fix the spec files, then continue the loop.
205
+ Integrates with `technical-spec` to persist the design and render it live while
206
+ discovery runs. At sign-off (Step 7), unless the user opts out: run
207
+ `technical-spec`'s scaffold script to create the spec directory, write the
208
+ design's decisions/contracts/mappings/edge-cases into its concern files
209
+ (`decisions.md`, `api.md`, `fields.md`, `quirks.md`, `implementation.md`), then
210
+ launch `plan-review`'s directory-mode preview against that spec path so it
211
+ live-reloads as the conversation refines the design. Full commands, the
212
+ existing-spec check, and how to action a submitted review decision:
213
+ `references/spec-integration.md`.
@@ -0,0 +1,63 @@
1
+ # Spec Integration (Live Preview)
2
+
3
+ Integrates with the `technical-spec` skill to persist the design and render it live while discovery runs.
4
+
5
+ ### At discovery start
6
+
7
+ Infer the feature slug (kebab-case from `$ARGUMENTS`). Specs live under
8
+ `<git-root>/specs/`, mirroring the repo structure: check
9
+ `<git-root>/specs/<pkg-relpath>/<feature-slug>/` (pkg-relpath = the nearest
10
+ package root's path relative to the git root, empty at the root) and
11
+ `<git-root>/specs/<feature-slug>/` for an existing spec.
12
+
13
+ If found, offer:
14
+
15
+ > "Found an existing spec for this feature. Open live preview while we refine the design? [y/n]"
16
+
17
+ If yes, go straight to **Launch preview** below (skip scaffold + write — spec already exists).
18
+
19
+ ### At sign-off
20
+
21
+ The Markdown design doc (Step 7) is always written. The spec write-back is
22
+ **default-on** — announce it rather than ask:
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."
26
+
27
+ Unless the user opts out (the spec directory then becomes the target for the
28
+ Design Review Loop above, in directory mode):
29
+
30
+ 1. **Find scripts** — the scaffold from technical-spec, the preview from
31
+ plan-review (its annotate server renders spec directories):
32
+ ```bash
33
+ SCAFFOLD=$(find ~/.claude ~/.codex ~/.agents -name "scaffold.sh" -path "*technical-spec*" 2>/dev/null | head -1)
34
+ PREVIEW=$(find ~/.claude ~/.codex ~/.agents -name "annotate-server.js" -path "*plan-review*" 2>/dev/null | head -1)
35
+ ```
36
+ If either is missing, tell the user: "the `technical-spec` / `plan-review` skills weren't found — install the condux plugin to enable spec integration."
37
+
38
+ 2. **Scaffold** the spec dir and capture the output:
39
+ ```bash
40
+ SCAFFOLD_OUT=$(bash "$SCAFFOLD" "<FeatureName>")
41
+ SPEC_PATH=$(echo "$SCAFFOLD_OUT" | sed 's/^[^:]*://; s/ .*//')
42
+ ```
43
+ `SPEC_PATH` is an absolute path (e.g. `/repo/specs/apps/web/wan-config`).
44
+ The scaffold script places specs under `<git-root>/specs/`, mirroring the
45
+ repo structure, automatically.
46
+
47
+ 3. **Write initial spec files** from the design into `$SPEC_PATH/`.
48
+ `decisions.md` always (chosen approach + rationale). Then every concern
49
+ the detail round produced answers for gets its file: `api.md`,
50
+ `fields.md`, `quirks.md`, `implementation.md`. A detail-round answer
51
+ that never lands in a spec file is a bug in the flow, not a judgment call.
52
+
53
+ 4. **Launch preview** in the background, pointing at the absolute spec path:
54
+ ```bash
55
+ node "$PREVIEW" "$SPEC_PATH"
56
+ ```
57
+ Tell user: "Preview is live. The browser updates automatically as spec files change, and you can annotate any file and submit a decision. Ctrl+C in the terminal to stop."
58
+
59
+ ### Keeping the spec current
60
+
61
+ As discovery continues and design details shift, update the relevant spec files — the preview re-renders on every save. This is the main benefit: the spec stays in sync with the conversation instead of being written once at the end.
62
+
63
+ If the user submits a decision in the preview, read `$SPEC_PATH/review.feedback.md` (notes grouped by file) and action it. Spec review is accept-or-fix (directory mode has no Reject): **Approve** = design is signed off, proceed; **Request Revisions** = fix the spec files, then continue the loop.
@@ -18,8 +18,10 @@ Turn a signed-off design into a clear, executable plan. Lean task cards, not mic
18
18
  ## Before Writing
19
19
 
20
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,
21
+ `.condux/designs/*<slug>*.md` and both spec scopes —
22
+ `<package-root>/specs/<slug>/` and `<git-root>/specs/<slug>/`, same
23
+ two-scope lookup as the workflow router (slug = kebab-case of the
24
+ feature name) — for an existing signed-off design; if found,
23
25
  treat this check as satisfied without asking. Otherwise ask: "We
24
26
  haven't aligned on the design yet — run /discovery first, or confirm
25
27
  you want to skip it."
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: live-verification
3
- description: "Verify a change by actually running it — drive the real UI or endpoint, check each claim against observed behaviour, and capture evidence before pushing. Detects what's runnable, checks light mode then dark, and reports claim → evidence → verdict with unverifiable claims named rather than hidden. After /finalize, before committing or pushing a change that has a runnable surface — UI, page, component, endpoint, CLI. Triggers include \"verify it live\", \"did this actually work\", \"check it in the browser\", \"live verify before pushing\", \"does it render right\". Not for typecheck/lint/test (that's finalize), not for auditing plan completeness (preflight), not for reading code to judge it (code-review)."
3
+ description: "Verify a change by actually running it — drive the real UI or endpoint, check each claim against observed behaviour, and capture evidence before pushing. Detects what's runnable, checks light mode then dark, and reports claim → evidence → verdict with unverifiable claims named rather than hidden. After /finalize, before committing, pushing, or merging a change that has a runnable surface — UI, page, component, endpoint, CLI. Triggers include \"verify it live\", \"did this actually work\", \"check it in the browser\", \"verify on preview\", \"check the preview env then merge\", \"live verify before pushing\", \"does it render right\". Not for typecheck/lint/test (that's finalize), not for auditing plan completeness (preflight), not for reading code to judge it (code-review)."
4
4
  argument-hint: "[what to verify — optional; defaults to the current diff]"
5
5
  ---
6
6
 
@@ -156,18 +156,7 @@ Evidence is **working state**: `<git-root>/.condux/verification/`, gitignored,
156
156
  alongside condux's `designs/` and `plans/`. Never the repo root, never the
157
157
  project's `docs/`.
158
158
 
159
- **Bootstrap.** `.condux/` is created on demand at the git root by the first
160
- skill that writes there. Before the first write, check it's ignored:
161
-
162
- ```bash
163
- git check-ignore -q .condux/ || echo "not ignored"
164
- ```
165
-
166
- If it isn't, offer once: "condux keeps its working files in `.condux/` — add
167
- it to `.gitignore` so they stay out of your commits?" On yes, append
168
- `.condux/` to the repo's `.gitignore`. If the user would rather not touch a
169
- tracked file, write it to `.git/info/exclude` instead. Never edit either file
170
- without asking. Not a git repo → fall back to CWD and say so once.
171
-
172
- **Override.** A project can relocate this in `AGENTS.md`; an explicit
173
- override always wins.
159
+ **Bootstrap.** Same contract as every condux skill — run the `.condux/`
160
+ bootstrap from `/workflow` → Artifacts (check `git check-ignore -q .condux/`,
161
+ offer the `.gitignore` line once, `AGENTS.md` override wins) before the first
162
+ write.
@@ -0,0 +1,25 @@
1
+ [
2
+ { "query": "verify it live", "should_trigger": true, "expected_skill": "live-verification" },
3
+ { "query": "did this actually work in the browser", "should_trigger": true, "expected_skill": "live-verification" },
4
+ { "query": "verify on preview then merge", "should_trigger": true, "expected_skill": "live-verification" },
5
+ { "query": "does it render right", "should_trigger": true, "expected_skill": "live-verification" },
6
+ { "query": "check the preview env before pushing", "should_trigger": true, "expected_skill": "live-verification" },
7
+ { "query": "check it in the browser before we ship", "should_trigger": true, "expected_skill": "live-verification" },
8
+ { "query": "live verify before pushing", "should_trigger": true, "expected_skill": "live-verification" },
9
+ { "query": "click through the flow and confirm it works", "should_trigger": true, "expected_skill": "live-verification" },
10
+ { "query": "hit the endpoint and check the response before we push", "should_trigger": true, "expected_skill": "live-verification" },
11
+ { "query": "does dark mode actually look right", "should_trigger": true, "expected_skill": "live-verification" },
12
+ { "query": "run it and watch it work before I commit", "should_trigger": true, "expected_skill": "live-verification" },
13
+ { "query": "confirm the component actually renders now", "should_trigger": true, "expected_skill": "live-verification" },
14
+ { "query": "spin up the app and check the change before pushing", "should_trigger": true, "expected_skill": "live-verification" },
15
+ { "query": "did the button actually fix itself, go look", "should_trigger": true, "expected_skill": "live-verification" },
16
+ { "query": "run typecheck and lint before I commit", "should_trigger": true, "expected_skill": "finalize" },
17
+ { "query": "run the full test suite", "should_trigger": true, "expected_skill": "finalize" },
18
+ { "query": "am I actually done, did I miss anything", "should_trigger": true, "expected_skill": "preflight" },
19
+ { "query": "are all the plan steps covered", "should_trigger": true, "expected_skill": "preflight" },
20
+ { "query": "review this diff before merge", "should_trigger": true, "expected_skill": "code-review" },
21
+ { "query": "review the code quality here", "should_trigger": true, "expected_skill": "code-review" },
22
+ { "query": "let's review the plan before we build", "should_trigger": true, "expected_skill": "plan-review" },
23
+ { "query": "walk me through the plan and annotate it", "should_trigger": true, "expected_skill": "plan-review" },
24
+ { "query": "what does the CSS overflow property do", "should_trigger": false, "expected_skill": null }
25
+ ]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: plan-review
3
- description: "Render a plan in a local browser for inline annotation, then return an approve / request-revisions / deny decision to the agent. Auto-captures the plan via a Claude Code ExitPlanMode hook or a Codex Stop hook, or runs manually on any markdown file or spec directory. Self-contained — no network egress, no third-party runtime deps. When the agent finishes planning (Claude Code ExitPlanMode, or a Codex planning turn) and you want to review/annotate before it implements, or when you invoke /plan-review on a markdown plan or spec directory. Also owns its own machinery — steer-mode review loops, the live spec preview, and installing or troubleshooting the ExitPlanMode / Codex Stop hooks. Phrases include \"let's review the plan\", \"walk me through the plan before we build\", \"annotate the plan\" — use these when the ExitPlanMode or Codex Stop hook doesn't fire. Not for cataloging a whole specs tree; use spec-browser."
3
+ description: "Render a plan in a local browser for inline annotation, then return an approve / request-revisions / deny decision to the agent. Auto-captures the plan via a Claude Code ExitPlanMode hook or a Codex Stop hook, or runs manually on any markdown file or spec directory. Self-contained — no network egress, no third-party runtime deps. When the agent finishes planning (Claude Code ExitPlanMode, or a Codex planning turn) and you want to review/annotate before it implements, or when you invoke /plan-review on a markdown plan or spec directory. Also owns its own machinery — steer-mode review loops, the live spec preview, and installing or troubleshooting the ExitPlanMode / Codex Stop hooks. Phrases include \"let's review the plan\", \"walk me through the plan before we build\", \"annotate the plan\" — use these when the ExitPlanMode or Codex Stop hook doesn't fire. Not for cataloging a whole specs tree; use spec-browser. Not for the implemented diff; use code-review."
4
4
  ---
5
5
 
6
6
  # /plan-review
@@ -19,85 +19,18 @@ network calls** — safe for strict environments.
19
19
 
20
20
  ### Auto — ExitPlanMode hook (the real workflow)
21
21
 
22
- When installed as part of the **condux plugin**, this hook ships in the plugin
23
- (`hooks/hooks.json`) and is auto-registered — no setup. Every time the agent
24
- exits plan mode, the plan is captured and the review UI opens automatically. The
25
- hook blocks until you decide. The plugin entry is:
26
-
27
- ```json
28
- // dist/plugins/condux/hooks/hooks.json (shipped — for reference)
29
- {
30
- "hooks": {
31
- "PreToolUse": [
32
- {
33
- "matcher": "ExitPlanMode",
34
- "hooks": [
35
- {
36
- "type": "command",
37
- "command": "node \"${CLAUDE_PLUGIN_ROOT}/skills/condux/plan-review/references/annotate-server.js\" --hook"
38
- }
39
- ]
40
- }
41
- ]
42
- }
43
- }
44
- ```
45
-
46
- **Standalone (no plugin)?** Wire the same hook by hand in your
47
- `settings.json` (project `.claude/settings.json` or `~/.claude/settings.json`),
48
- swapping `${CLAUDE_PLUGIN_ROOT}/skills/condux/plan-review` for the absolute path:
49
-
50
- ```bash
51
- find ~/.claude ~/.codex ~/.agents -name annotate-server.js -path '*plan-review*' 2>/dev/null | head -1
52
- ```
53
-
54
- What the hook returns to the agent:
55
-
56
- | Your decision | Hook output | Agent behavior |
57
- |---|---|---|
58
- | **Approve** | `permissionDecision: "allow"` (+ notes as `additionalContext` if any) | proceeds to implement |
59
- | **Request Revisions** | `permissionDecision: "deny"`, reason = *revise this plan* + feedback | revises the plan, re-enters plan mode (re-triggers the hook) |
60
- | **Reject** | `permissionDecision: "deny"`, reason = *do not implement, reconsider* + feedback | stops; reconsiders whether the feature should be built, or proposes a different approach |
22
+ Ships with the condux plugin, auto-registered — every `ExitPlanMode` opens the
23
+ review UI and blocks until you decide (Approve / Request Revisions / Reject).
24
+ Standalone installs wire the same hook by hand.
25
+ Full install + troubleshooting: `references/hooks-install.md`.
61
26
 
62
27
  ### Auto — Codex Stop hook
63
28
 
64
- Codex has **no `ExitPlanMode`** interception point, so plan review runs off
65
- Codex's experimental **`Stop` hook**. When a planning turn ends
66
- (`permission_mode === "plan"`), `annotate-server.js --codex-stop` reads the plan
67
- from the Stop payload (`last_assistant_message`, falling back to
68
- `transcript_path`) and opens the same review UI. On any other turn it emits `{}`
69
- and exits, leaving the turn untouched.
70
-
71
- **Installed via the condux plugin?** The `Stop` hook ships with it. The Codex
72
- manifest (`.codex-plugin/plugin.json`) sets `"hooks": "./hooks/codex-hooks.json"`,
73
- which Codex loads **instead of** the default `hooks/hooks.json` (that one is
74
- Claude's `ExitPlanMode` hook, inert on Codex). Just enable `[features] hooks =
75
- true` in `$CODEX_HOME/config.toml`, then **restart Codex** and **trust the hook**
76
- when prompted — no installer needed.
77
-
78
- **Standalone (no plugin)?** Run the installer once — it writes `~/.codex/hooks.json`
79
- + sets the feature flag, then restart Codex and trust the hook:
80
-
81
- ```bash
82
- bash /PATH/TO/plan-review/references/install-codex-hook.sh
83
- # or, after a plugin install:
84
- find ~/.codex ~/.claude -name install-codex-hook.sh -path '*plan-review*' 2>/dev/null | head -1 | xargs bash
85
- ```
86
-
87
- | Your decision | Hook output | Codex behavior |
88
- |---|---|---|
89
- | **Approve** (no notes) | `{}` (turn completes) | plan accepted, turn ends |
90
- | **Approve** (with notes) | `{"decision":"block","reason":<approved + notes>}` | continues the turn; agent implements while addressing the notes |
91
- | **Request Revisions** | `{"decision":"block","reason":<revise + feedback>}` | revises the plan in the same turn (re-triggers on next stop) |
92
- | **Reject** | `{"decision":"block","reason":<do not implement, reconsider + feedback>}` | stops; reconsiders whether the feature should be built, or proposes a different approach |
93
-
94
- Caveats: Codex hooks are **experimental and disabled on Windows**; the review is
95
- **post-render** (after Codex prints the plan), not a pre-interception like Claude
96
- Code. The plugin hook invokes bare `node` (resolved via `${PLUGIN_ROOT}`, the
97
- variable Codex substitutes in plugin hook commands — it does **not** set Claude's
98
- `${CLAUDE_PLUGIN_ROOT}`, so never use that in `codex-hooks.json`) — if Codex
99
- Desktop can't find `node` on `PATH`, fall back to the installer, which bakes in
100
- an **absolute** node path.
29
+ Codex has no `ExitPlanMode` interception point, so review runs off Codex's
30
+ experimental `Stop` hook instead — same review UI, same three decisions.
31
+ Ships with the condux plugin's Codex manifest; standalone installs run
32
+ `install-codex-hook.sh` once.
33
+ Full install + troubleshooting + decision tables: `references/hooks-install.md`.
101
34
 
102
35
  ### Manual — on any file or spec directory
103
36
 
@@ -152,60 +85,19 @@ reflects every revision** — no new tab per round. The decision is also written
152
85
 
153
86
  ## The review surface
154
87
 
155
- A three-pane layout over a **decision bar**: a left sidebar with two tabs —
156
- **Contents** (heading outline with per-section note counts; in directory mode,
157
- each document is a top-level node with its headings nested, click to switch
158
- docs) and **Files** (paths the plan touches, parsed from inline code and
159
- fences, badged **exists**/**new** against the repo; click jumps to the first
160
- mention, repeat clicks cycle) — the centered rendered plan (middle), and a
161
- **Review** rail (right) holding your notes and messages. The decisions live in
162
- a fixed bar along the bottom — `[Reject] ——— [Request revisions] [Approve]` —
163
- with a live summary of what rides along ("3 notes · 1 message will be sent").
164
-
165
- ```
166
- ┌──────────────────────────────────────────────────────────────────┐
167
- │ Step 1 RENDER Plan renders centered in the browser, w/ TOC. │
168
- │ Step 2 ANNOTATE Select text → a toolbar opens above it. Pick │
169
- │ a category (Comment / Issue / Question / │
170
- │ Suggestion / Nitpick) → the note input opens. │
171
- │ Or message the agent in the Review rail. │
172
- │ Step 3 DECIDE Bottom bar: Approve / Request Revisions / │
173
- │ Reject — with a note/message count summary. │
174
- │ Step 4 RETURN Decision + notes (each tagged with its │
175
- │ category and quoting its anchor) go back. │
176
- └──────────────────────────────────────────────────────────────────┘
177
- ```
178
-
179
- Selecting text opens a floating **annotation toolbar** anchored above the
180
- selection (it flips below when there's no room). It starts as a category
181
- **menubar**; choosing a category expands it to reveal the note input and
182
- Save/Cancel. Saving highlights the text and anchors the note; clicking a
183
- highlight or a note cross-links the two. The page live-reloads when the plan
184
- file changes on disk (SSE + `fs.watch`).
185
-
186
- When the agent **revises** the plan, the tab doesn't silently swap the text: a
187
- banner reports the change (`+adds / -dels lines`) with a **View changes** toggle
188
- that shows a unified line diff (old vs. new, folding long unchanged runs), and
189
- the now-orphaned notes clear so the next round starts clean. Submitting a
190
- decision **clears your notes immediately** and replaces the decision bar's
191
- content with a confirmation that states what the agent does next
192
- (implement / revise / rework).
193
-
194
- ## Guarantees (why it passes review)
195
-
196
- - **No egress.** Server binds `127.0.0.1` only; the HTML template embeds its own
197
- markdown renderer and uses a system monospace font — no CDN, no web fonts, no
198
- paste/share service. Audit: `grep -rE 'https?://' references/*.html` returns nothing.
199
- - **No dependencies.** `annotate-server.js` is Node stdlib only.
200
- - **Auditable.** One stdlib server + one self-contained HTML file. The UI is
201
- styled after the **Terminus UI** design system (Button, Badge, Card, Textarea,
202
- Popover) — adapted as vanilla CSS tokens + classes, no React, no bundle.
88
+ Three-pane layout over a decision bar: sidebar (Contents outline + Files list)
89
+ on the left, the rendered plan centered, and a Review rail on the right for
90
+ notes/messages. Select text to annotate (category + note), or message the
91
+ agent directly; decide via `[Reject] ——— [Request revisions] [Approve]` at the
92
+ bottom. Revisions live-reload with a diff banner; no third-party deps or
93
+ network egress (Node stdlib server + self-contained HTML).
94
+ Full UI walkthrough + guarantees: `references/ui.md`.
203
95
 
204
96
  ## Files
205
97
 
206
98
  | File | Role |
207
99
  |---|---|
208
- | `references/annotate-server.js` | Local server. `--hook` (Claude ExitPlanMode), `--codex-stop` (Codex Stop), `<file> --steer` (agent-invoked blocking loop), or `<file|dir>` alone for manual mode. A directory argument reviews every top-level `*.md` in it. |
100
+ | `references/annotate-server.js` | Local server. `--hook` (Claude ExitPlanMode), `--codex-stop` (Codex Stop), `<file> --steer` (agent-invoked blocking loop), or `<file|dir>` alone for manual mode. A directory argument reviews every top-level `*.md` in it. `--no-reject` hides the Reject verdict for accept-or-fix reviews (discovery's design stage passes it; directory mode implies it). |
209
101
  | `references/install-codex-hook.sh` | Registers the Codex `Stop` hook in `~/.codex` and enables the hooks feature flag. |
210
102
  | `references/plan-review-template.html` | Self-contained review UI (renderer + annotation surface). |
211
103
 
@@ -53,6 +53,7 @@ const HOOK_MODE = process.argv.includes('--hook');
53
53
  const CODEX_STOP_MODE = process.argv.includes('--codex-stop');
54
54
  const STEER_MODE = process.argv.includes('--steer');
55
55
  const NO_OPEN = process.argv.includes('--no-open'); // don't launch the browser (tests, headless)
56
+ const NO_REJECT = process.argv.includes('--no-reject'); // accept-or-fix review (design stage) — hide the Reject verdict
56
57
  const STDOUT_JSON = HOOK_MODE || CODEX_STOP_MODE || STEER_MODE; // these modes emit JSON on stdout
57
58
  const log = STDOUT_JSON ? console.error : console.log; // keep stdout clean for hooks
58
59
  const sseClients = new Set();
@@ -309,8 +310,8 @@ function handler(req, res) {
309
310
  // Document manifest. Single-file reviews report dir:false so the client
310
311
  // keeps the classic one-document layout.
311
312
  return sendJson(res, 200, DIR_MODE
312
- ? { dir: true, docs: listDocs() }
313
- : { dir: false, docs: [path.basename(planFile)] });
313
+ ? { dir: true, docs: listDocs(), noReject: true }
314
+ : { dir: false, docs: [path.basename(planFile)], noReject: NO_REJECT });
314
315
  }
315
316
  if (req.method === 'POST' && p === '/api/verify-paths') {
316
317
  // Files tab: check which mentioned paths exist in the repo under review.
@@ -0,0 +1,83 @@
1
+ # Hook Install + Troubleshooting
2
+
3
+ ### Auto — ExitPlanMode hook (the real workflow)
4
+
5
+ When installed as part of the **condux plugin**, this hook ships in the plugin
6
+ (`hooks/hooks.json`) and is auto-registered — no setup. Every time the agent
7
+ exits plan mode, the plan is captured and the review UI opens automatically. The
8
+ hook blocks until you decide. The plugin entry is:
9
+
10
+ ```json
11
+ // dist/plugins/condux/hooks/hooks.json (shipped — for reference)
12
+ {
13
+ "hooks": {
14
+ "PreToolUse": [
15
+ {
16
+ "matcher": "ExitPlanMode",
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/skills/condux/plan-review/references/annotate-server.js\" --hook"
21
+ }
22
+ ]
23
+ }
24
+ ]
25
+ }
26
+ }
27
+ ```
28
+
29
+ **Standalone (no plugin)?** Wire the same hook by hand in your
30
+ `settings.json` (project `.claude/settings.json` or `~/.claude/settings.json`),
31
+ swapping `${CLAUDE_PLUGIN_ROOT}/skills/condux/plan-review` for the absolute path:
32
+
33
+ ```bash
34
+ find ~/.claude ~/.codex ~/.agents -name annotate-server.js -path '*plan-review*' 2>/dev/null | head -1
35
+ ```
36
+
37
+ What the hook returns to the agent:
38
+
39
+ | Your decision | Hook output | Agent behavior |
40
+ |---|---|---|
41
+ | **Approve** | `permissionDecision: "allow"` (+ notes as `additionalContext` if any) | proceeds to implement |
42
+ | **Request Revisions** | `permissionDecision: "deny"`, reason = *revise this plan* + feedback | revises the plan, re-enters plan mode (re-triggers the hook) |
43
+ | **Reject** | `permissionDecision: "deny"`, reason = *do not implement, reconsider* + feedback | stops; reconsiders whether the feature should be built, or proposes a different approach |
44
+
45
+ ### Auto — Codex Stop hook
46
+
47
+ Codex has **no `ExitPlanMode`** interception point, so plan review runs off
48
+ Codex's experimental **`Stop` hook**. When a planning turn ends
49
+ (`permission_mode === "plan"`), `annotate-server.js --codex-stop` reads the plan
50
+ from the Stop payload (`last_assistant_message`, falling back to
51
+ `transcript_path`) and opens the same review UI. On any other turn it emits `{}`
52
+ and exits, leaving the turn untouched.
53
+
54
+ **Installed via the condux plugin?** The `Stop` hook ships with it. The Codex
55
+ manifest (`.codex-plugin/plugin.json`) sets `"hooks": "./hooks/codex-hooks.json"`,
56
+ which Codex loads **instead of** the default `hooks/hooks.json` (that one is
57
+ Claude's `ExitPlanMode` hook, inert on Codex). Just enable `[features] hooks =
58
+ true` in `$CODEX_HOME/config.toml`, then **restart Codex** and **trust the hook**
59
+ when prompted — no installer needed.
60
+
61
+ **Standalone (no plugin)?** Run the installer once — it writes `~/.codex/hooks.json`
62
+ + sets the feature flag, then restart Codex and trust the hook:
63
+
64
+ ```bash
65
+ bash /PATH/TO/plan-review/references/install-codex-hook.sh
66
+ # or, after a plugin install:
67
+ find ~/.codex ~/.claude -name install-codex-hook.sh -path '*plan-review*' 2>/dev/null | head -1 | xargs bash
68
+ ```
69
+
70
+ | Your decision | Hook output | Codex behavior |
71
+ |---|---|---|
72
+ | **Approve** (no notes) | `{}` (turn completes) | plan accepted, turn ends |
73
+ | **Approve** (with notes) | `{"decision":"block","reason":<approved + notes>}` | continues the turn; agent implements while addressing the notes |
74
+ | **Request Revisions** | `{"decision":"block","reason":<revise + feedback>}` | revises the plan in the same turn (re-triggers on next stop) |
75
+ | **Reject** | `{"decision":"block","reason":<do not implement, reconsider + feedback>}` | stops; reconsiders whether the feature should be built, or proposes a different approach |
76
+
77
+ Caveats: Codex hooks are **experimental and disabled on Windows**; the review is
78
+ **post-render** (after Codex prints the plan), not a pre-interception like Claude
79
+ Code. The plugin hook invokes bare `node` (resolved via `${PLUGIN_ROOT}`, the
80
+ variable Codex substitutes in plugin hook commands — it does **not** set Claude's
81
+ `${CLAUDE_PLUGIN_ROOT}`, so never use that in `codex-hooks.json`) — if Codex
82
+ Desktop can't find `node` on `PATH`, fall back to the installer, which bakes in
83
+ an **absolute** node path.
@@ -706,9 +706,11 @@
706
706
  let meta={dir:false,docs:['plan']};
707
707
  try{ meta=await (await fetch('/api/docs')).json(); }catch(e){}
708
708
  DIRMODE=!!meta.dir; docs=meta.docs||[];
709
- // Directory (spec) review is accept-or-fix — a spec documents work already
710
- // decided, so the plan-only "Reject / don't build it" verdict doesn't apply.
711
- if(DIRMODE){ const rj=document.getElementById('btn-reject'); if(rj)rj.style.display='none'; }
709
+ // Accept-or-fix reviews hide the plan-only "Reject / don't build it"
710
+ // verdict: directory (spec) review always — a spec documents work already
711
+ // decided — and single-file review when the server was started with
712
+ // --no-reject (discovery's design stage).
713
+ if(DIRMODE||meta.noReject){ const rj=document.getElementById('btn-reject'); if(rj)rj.style.display='none'; }
712
714
  planEl.innerHTML='';
713
715
  docs.forEach(function(d,i){
714
716
  const pane=document.createElement('div'); pane.className='docpane'; pane.style.display='none';
@@ -0,0 +1,52 @@
1
+ # Review Surface UI
2
+
3
+ ## The review surface
4
+
5
+ A three-pane layout over a **decision bar**: a left sidebar with two tabs —
6
+ **Contents** (heading outline with per-section note counts; in directory mode,
7
+ each document is a top-level node with its headings nested, click to switch
8
+ docs) and **Files** (paths the plan touches, parsed from inline code and
9
+ fences, badged **exists**/**new** against the repo; click jumps to the first
10
+ mention, repeat clicks cycle) — the centered rendered plan (middle), and a
11
+ **Review** rail (right) holding your notes and messages. The decisions live in
12
+ a fixed bar along the bottom — `[Reject] ——— [Request revisions] [Approve]` —
13
+ with a live summary of what rides along ("3 notes · 1 message will be sent").
14
+
15
+ ```
16
+ ┌──────────────────────────────────────────────────────────────────┐
17
+ │ Step 1 RENDER Plan renders centered in the browser, w/ TOC. │
18
+ │ Step 2 ANNOTATE Select text → a toolbar opens above it. Pick │
19
+ │ a category (Comment / Issue / Question / │
20
+ │ Suggestion / Nitpick) → the note input opens. │
21
+ │ Or message the agent in the Review rail. │
22
+ │ Step 3 DECIDE Bottom bar: Approve / Request Revisions / │
23
+ │ Reject — with a note/message count summary. │
24
+ │ Step 4 RETURN Decision + notes (each tagged with its │
25
+ │ category and quoting its anchor) go back. │
26
+ └──────────────────────────────────────────────────────────────────┘
27
+ ```
28
+
29
+ Selecting text opens a floating **annotation toolbar** anchored above the
30
+ selection (it flips below when there's no room). It starts as a category
31
+ **menubar**; choosing a category expands it to reveal the note input and
32
+ Save/Cancel. Saving highlights the text and anchors the note; clicking a
33
+ highlight or a note cross-links the two. The page live-reloads when the plan
34
+ file changes on disk (SSE + `fs.watch`).
35
+
36
+ When the agent **revises** the plan, the tab doesn't silently swap the text: a
37
+ banner reports the change (`+adds / -dels lines`) with a **View changes** toggle
38
+ that shows a unified line diff (old vs. new, folding long unchanged runs), and
39
+ the now-orphaned notes clear so the next round starts clean. Submitting a
40
+ decision **clears your notes immediately** and replaces the decision bar's
41
+ content with a confirmation that states what the agent does next
42
+ (implement / revise / rework).
43
+
44
+ ## Guarantees (why it passes review)
45
+
46
+ - **No egress.** Server binds `127.0.0.1` only; the HTML template embeds its own
47
+ markdown renderer and uses a system monospace font — no CDN, no web fonts, no
48
+ paste/share service. Audit: `grep -rE 'https?://' references/*.html` returns nothing.
49
+ - **No dependencies.** `annotate-server.js` is Node stdlib only.
50
+ - **Auditable.** One stdlib server + one self-contained HTML file. The UI is
51
+ styled after the **Terminus UI** design system (Button, Badge, Card, Textarea,
52
+ Popover) — adapted as vanilla CSS tokens + classes, no React, no bundle.
@@ -77,7 +77,7 @@ Before Step 1, check the **Progress Ledger** (above) for already-completed tasks
77
77
  │ │
78
78
  │ Step 3: GROUP INTO A WAVE │
79
79
  │ Among this round's unblocked tasks needing an agent, check │
80
- │ references/safety-checklist.md (subagent-deployment skill); │
80
+ │ subagent-deployment/references/safety-checklist.md; │
81
81
  │ tasks that clear it form one wave. │
82
82
  │ │
83
83
  │ Step 4: DISPATCH THE WAVE │
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: technical-spec
3
- description: Use when a feature plan, design session, or implementation milestone is complete and the decisions, API contracts, implementation details, and quirks should be persisted for future reference. Also use when the user says "save spec", "document this", "write up what we decided", or "spec this out".
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\", or \"spec this out\". Not for turning a rough idea into a design first — that's discovery."
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
@@ -46,42 +46,10 @@ Only create files that have actual content. Don't create empty files.
46
46
 
47
47
  ## Workflow
48
48
 
49
- ```dot
50
- digraph save_spec {
51
- rankdir=TB;
52
- "Infer feature name from context" [shape=box];
53
- "Feature name clear?" [shape=diamond];
54
- "Ask user for feature name" [shape=box];
55
- "Notify user — confirm before writing" [shape=box];
56
- "User approves?" [shape=diamond];
57
- "Stop" [shape=box];
58
- "Run scaffold.sh <feature>" [shape=box];
59
- "Output: exists or created?" [shape=diamond];
60
- "Write content files, update index.md Contents" [shape=box];
61
- "Read index.md, update changed files only" [shape=box];
62
- "Ask: open live HTML preview?" [shape=diamond];
63
- "Locate + run plan-review annotate-server.js on the spec dir" [shape=box];
64
- "Tell user: Ctrl+C when done reviewing" [shape=box];
65
- "Done" [shape=doublecircle];
66
-
67
- "Infer feature name from context" -> "Feature name clear?";
68
- "Feature name clear?" -> "Notify user — confirm before writing" [label="yes"];
69
- "Feature name clear?" -> "Ask user for feature name" [label="no"];
70
- "Ask user for feature name" -> "Notify user — confirm before writing";
71
- "Notify user — confirm before writing" -> "User approves?";
72
- "User approves?" -> "Stop" [label="no"];
73
- "User approves?" -> "Run scaffold.sh <feature>" [label="yes"];
74
- "Run scaffold.sh <feature>" -> "Output: exists or created?";
75
- "Output: exists or created?" -> "Write content files, update index.md Contents" [label="created"];
76
- "Output: exists or created?" -> "Read index.md, update changed files only" [label="exists"];
77
- "Write content files, update index.md Contents" -> "Ask: open live HTML preview?";
78
- "Read index.md, update changed files only" -> "Ask: open live HTML preview?";
79
- "Ask: open live HTML preview?" -> "Locate + run plan-review annotate-server.js on the spec dir" [label="yes"];
80
- "Ask: open live HTML preview?" -> "Done" [label="no"];
81
- "Locate + run plan-review annotate-server.js on the spec dir" -> "Tell user: Ctrl+C when done reviewing";
82
- "Tell user: Ctrl+C when done reviewing" -> "Done";
83
- }
84
- ```
49
+ Infer the feature name (ask if unclear) → confirm with the user before
50
+ writing → run the scaffold script → write or update the concern files and
51
+ `index.md` → offer the live HTML preview. Each step is specified in the
52
+ sections below.
85
53
 
86
54
  ## Required Notifications
87
55
 
@@ -170,7 +170,7 @@ Two tiers, split by durability — not by which skill produced them.
170
170
  | Tier | Where | Contents | Git |
171
171
  |---|---|---|---|
172
172
  | **Durable** | `<git-root>/specs/` | tech specs (`technical-spec`), browsable via `spec-browser` | committed |
173
- | **Working state** | `<git-root>/.condux/` | `designs/` · `plans/` · `progress/` · `scratch/` | gitignored |
173
+ | **Working state** | `<git-root>/.condux/` | `designs/` · `plans/` · `progress/` · `scratch/` · `verification/` (live-verification evidence) | gitignored |
174
174
 
175
175
  The spec is what you keep; the design and plan are scaffolding for building
176
176
  it. Don't promote working state into `docs/` or the repo root — a project's