agentic-sdlc-wizard 1.86.0 → 1.87.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/AI_SETUP_LANES.md +28 -22
- package/CHANGELOG.md +18 -0
- package/CLAUDE_CODE_SDLC_WIZARD.md +20 -20
- package/README.md +16 -8
- package/cli/init.js +0 -1
- package/cli/templates/settings.json +0 -4
- package/hooks/codex-gate-check.sh +29 -5
- package/hooks/codex-review-stop-check.sh +6 -1
- package/hooks/hooks.json +0 -4
- package/hooks/instructions-loaded-check.sh +39 -19
- package/hooks/model-effort-check.sh +27 -21
- package/hooks/precompact-seam-check.sh +16 -171
- package/hooks/sdlc-prompt-check.sh +5 -63
- package/hooks/tdd-pretool-check.sh +16 -1
- package/package.json +1 -1
- package/skills/feedback/SKILL.md +1 -1
- package/skills/sdlc/SKILL.md +3 -5
- package/skills/setup/SKILL.md +4 -4
- package/skills/update/SKILL.md +3 -4
- package/hooks/goal-confidence-check.sh +0 -82
package/AI_SETUP_LANES.md
CHANGED
|
@@ -9,13 +9,17 @@ This is **guidance, not a hard rule**. Maintainer override is always allowed.
|
|
|
9
9
|
| Role | Model | Effort |
|
|
10
10
|
|------|-------|--------|
|
|
11
11
|
| **Advisor** | Fable 5 (via `advisorModel: "fable"`) | `high` (server-side) |
|
|
12
|
-
| **Driver** | Sonnet 5 (`claude-sonnet-5`) | `
|
|
13
|
-
| **Reviewer** | Codex (GPT-5.
|
|
14
|
-
| **Escalation** | Opus 4.8 xhigh or Fable 5 review | When stuck or high-stakes |
|
|
12
|
+
| **Driver** | Sonnet 5 (`claude-sonnet-5`) | `medium` default, escalate `high` → `xhigh` for hard tasks |
|
|
13
|
+
| **Reviewer** | Codex (GPT-5.6 Sol) xhigh | — |
|
|
14
|
+
| **Escalation** | Opus 4.8 xhigh takes over as driver (or run a Fable 5 review pass) | When stuck (2 failed attempts / LOW confidence) or high-stakes |
|
|
15
15
|
|
|
16
|
-
The new standard. Sonnet 5 beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 80.4% vs 65.4%)
|
|
16
|
+
The new standard. Sonnet 5 beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 80.4% vs 65.4%) and generally uses less Max quota — but the savings are not a fixed ratio: Sonnet 5's newer tokenizer produces ~30% more tokens for the same text than Opus 4.6's (per Anthropic's pricing docs), and community cost reports suggest the advantage narrows at `high`/`xhigh`. No controlled Sonnet-5-vs-Opus-4.6 quota measurement exists — check your own burn with `/usage`. Fable 5 advises at key decision points via native `advisorModel` (v2.1.170+). GPT-5.6 Sol xhigh reviews cross-family. Escalate to Opus 4.8 xhigh for the hardest debugging or architecture decisions — don't run Opus as the daily driver.
|
|
17
17
|
|
|
18
|
-
**Effort escalation ladder:** Start at `
|
|
18
|
+
**Effort escalation ladder:** Start at `medium` — CodeRabbit's testing found it captures most of Sonnet 5's upside at the lowest cost. Raise to `high` when medium struggles, `xhigh` for hard debugging, multi-file migrations, or long agent runs. `max` is rarely worth it — doubles cost for marginal gains per the same CodeRabbit testing.
|
|
19
|
+
|
|
20
|
+
**Two escalation axes — don't conflate them.** The effort ladder above raises reasoning *within* the Sonnet 5 driver. Model escalation is a different move: it *swaps the driver* — after 2 failed attempts, LOW confidence, or on a high-stakes change, Opus 4.8 xhigh takes over as driver (or run a Fable 5 review pass on the diff). Cranking Sonnet's effort past `xhigh` is not the escalation path.
|
|
21
|
+
|
|
22
|
+
**Advisor failure has a fallback, not a shrug.** `advisor()` is a server-side tool and does fail during API incidents. When it errors, spawn a Fable subagent as the fallback reviewer — the same rule the `/sdlc` skill carries ("if down, spawn Fable subagent"). The advisor check is never skipped; only its transport changes.
|
|
19
23
|
|
|
20
24
|
**Requires:** Claude Code v2.1.197+ (Sonnet 5 alias resolution), Fable 5 access for advisor.
|
|
21
25
|
|
|
@@ -25,7 +29,7 @@ The new standard. Sonnet 5 beats Opus 4.6 on every coding benchmark (SWE-bench V
|
|
|
25
29
|
|------|-------|--------|
|
|
26
30
|
| **Advisor** | Fable 5 (via `advisorModel: "fable"`) | `high` (server-side) |
|
|
27
31
|
| **Driver** | Opus 4.6 (`claude-opus-4-6`) | `max` |
|
|
28
|
-
| **Reviewer** | Codex (GPT-5.
|
|
32
|
+
| **Reviewer** | Codex (GPT-5.6 Sol) xhigh | — |
|
|
29
33
|
|
|
30
34
|
The consistency-first lane. Opus 4.6 is the only model where `max` effort works without overthinking — months of field data, Active through at least Feb 2027, proven predictable. Lower benchmark scores than Sonnet 5 but higher consistency. Choose this when you've tuned prompts to Opus 4.6 behavior and reliability matters more than peak capability.
|
|
31
35
|
|
|
@@ -37,10 +41,10 @@ The consistency-first lane. Opus 4.6 is the only model where `max` effort works
|
|
|
37
41
|
|------|-------|--------|
|
|
38
42
|
| **Planner** | Opus 4.8 (via Plan Mode — Shift+Tab) | `xhigh` |
|
|
39
43
|
| **Advisor** | Fable 5 or Opus 4.8 (via `advisorModel`) | — |
|
|
40
|
-
| **Driver** | Sonnet 5 (auto execute mode) | `high` |
|
|
41
|
-
| **Reviewer** | Codex (GPT-5.
|
|
44
|
+
| **Driver** | Sonnet 5 (auto execute mode) | `medium`, escalate `high` for hard runs |
|
|
45
|
+
| **Reviewer** | Codex (GPT-5.6 Sol) xhigh | — |
|
|
42
46
|
|
|
43
|
-
Cost-efficient hybrid using CC's native `opusplan` alias. Opus 4.8 reasons during Plan Mode, Sonnet 5 executes. Max-bundled — no API credit drain. Pin `model: "opusplan"` + `advisorModel: "fable"` in project settings. Sonnet 5 now uses 1M context natively (no `[1m]` suffix needed). GPT-5.
|
|
47
|
+
Cost-efficient hybrid using CC's native `opusplan` alias. Opus 4.8 reasons during Plan Mode, Sonnet 5 executes. Max-bundled — no API credit drain. Pin `model: "opusplan"` + `advisorModel: "fable"` in project settings. Sonnet 5 now uses 1M context natively (no `[1m]` suffix needed). GPT-5.6 Sol xhigh is the cross-model reviewer.
|
|
44
48
|
|
|
45
49
|
**Note:** Opus 4.6 cannot advise Sonnet 5 (rejected in the advisor pairing table). Use Fable 5 or Opus 4.8 as advisor for this lane.
|
|
46
50
|
|
|
@@ -56,7 +60,7 @@ The "just do the thing" lane. No TDD enforcement, no cross-model review, no plan
|
|
|
56
60
|
|
|
57
61
|
## When to Use Setup A
|
|
58
62
|
|
|
59
|
-
The default choice for most SDLC work — full discipline (TDD, cross-model review) at
|
|
63
|
+
The default choice for most SDLC work — full discipline (TDD, cross-model review) at generally lower quota cost than Setup B (see Credit-Spend Warning below):
|
|
60
64
|
|
|
61
65
|
- Feature implementation and routine development
|
|
62
66
|
- Documentation and examples
|
|
@@ -116,11 +120,13 @@ Setup D is for work where SDLC discipline overhead exceeds the value:
|
|
|
116
120
|
|
|
117
121
|
## Final Review Policy
|
|
118
122
|
|
|
119
|
-
**Setups A, B, and C end at GPT-5.
|
|
123
|
+
**Setups A, B, and C end at GPT-5.6 Sol xhigh as the cross-model reviewer.** Claude can't grade its own homework — the reviewer always belongs to a different lab with different blind spots. See [CLAUDE_CODE_SDLC_WIZARD.md → "Cross-Model Review (Codex)"](CLAUDE_CODE_SDLC_WIZARD.md) for the handoff protocol.
|
|
120
124
|
|
|
121
125
|
**Setup D has no reviewer** — the blast radius doesn't justify it. If you're unsure whether a task is truly Lite, it probably isn't. Escalate.
|
|
122
126
|
|
|
123
|
-
If GPT-5.
|
|
127
|
+
If GPT-5.6 Sol isn't available on your OpenAI account, Codex auto-falls back to Terra — still keep `model_reasoning_effort="xhigh"`. Lower reasoning misses subtle bugs that the reviewer is the last gate to catch.
|
|
128
|
+
|
|
129
|
+
**Escalation for unusually risky PRs:** `xhigh` is the evidence-based default — OpenAI's own migration guidance is to preserve the prior effort baseline, and no published data shows `max` or Pro mode catching meaningfully more real bugs than `xhigh` on ordinary PR review. For a PR you'd genuinely lose sleep over (security-sensitive, high blast radius, touches the installer or a consumer-facing template), escalate the reviewer to `max` or Pro mode — a once-per-PR gate is exactly the kind of low-frequency, high-stakes call site where the extra cost is easiest to justify. Don't make it the default.
|
|
124
130
|
|
|
125
131
|
## Version Requirement
|
|
126
132
|
|
|
@@ -140,10 +146,10 @@ If the advisor returns "Advisor unavailable," the server-side harness failed to
|
|
|
140
146
|
|
|
141
147
|
**Step 1 — restart the session.** Exit and run `claude` (not `--resume`). A fresh process re-initializes the server handshake. This resolves most advisor failures.
|
|
142
148
|
|
|
143
|
-
**Step 2 — if the API incident persists:**
|
|
149
|
+
**Step 2 — if the API incident persists, swap the transport, not the check:**
|
|
144
150
|
|
|
145
|
-
-
|
|
146
|
-
-
|
|
151
|
+
- Spawn a Fable subagent as the fallback reviewer — the `/sdlc` skill's standing rule ("if down, spawn Fable subagent"). Batch your plan or open questions into one subagent consult at each point where you'd have called `advisor()`. Runs interactively on your Max subscription like any other agent.
|
|
152
|
+
- Keep driving with your lane's model (`/model sonnet` for Setup A, `/model claude-opus-4-6` for Setup B). The subagent replaces the advisor's transport; the Codex xhigh PR gate remains the separate final backstop, not a substitute for the advisor check.
|
|
147
153
|
|
|
148
154
|
**Last resort (scripted/CI only):**
|
|
149
155
|
|
|
@@ -155,15 +161,15 @@ Whichever path you use, the cross-model PR review gate still applies.
|
|
|
155
161
|
|
|
156
162
|
## Credit-Spend Warning
|
|
157
163
|
|
|
158
|
-
**Setup B (Opus 4.6 max as both planner and driver) burns the 5-hour cap faster than Setup A** — Opus 4.6 max driving implementation is the expensive path; Sonnet 5
|
|
164
|
+
**Setup B (Opus 4.6 max as both planner and driver) burns the 5-hour cap faster than Setup A** — Opus 4.6 max driving implementation is the expensive path; Sonnet 5 at `medium`/`high` generally uses less quota for comparable benchmark results (the advantage narrows at `xhigh` — more turns per task plus tokenizer overhead). If you're hitting the cap mid-session on Setup B:
|
|
159
165
|
|
|
160
|
-
- Drop to Setup A (Sonnet 5) for the remainder of the day — same discipline,
|
|
166
|
+
- Drop to Setup A (Sonnet 5) for the remainder of the day — same discipline, typically lower quota burn (widest advantage at `medium`)
|
|
161
167
|
- Or drop to Setup D for grunt work that doesn't need deep reasoning
|
|
162
|
-
- Or use Sonnet directly for the final mechanical edits, then run the GPT-5.
|
|
168
|
+
- Or use Sonnet directly for the final mechanical edits, then run the GPT-5.6 Sol reviewer over the whole diff at the end
|
|
163
169
|
|
|
164
170
|
**Setup D uses Sonnet** — same model as Setup A's driver, Max-bundled. One less model to manage if you're already on Setup A.
|
|
165
171
|
|
|
166
|
-
The reviewer (GPT-5.
|
|
172
|
+
The reviewer (GPT-5.6 Sol xhigh) is billed against your OpenAI account, separately. Watch both bills.
|
|
167
173
|
|
|
168
174
|
## Autocompact Thresholds
|
|
169
175
|
|
|
@@ -201,11 +207,11 @@ Credit allocations: Pro $20/mo, Max 5x $100/mo, Max 20x $200/mo. **No rollover.*
|
|
|
201
207
|
|
|
202
208
|
### What this means for the lanes
|
|
203
209
|
|
|
204
|
-
- **Setup A — Sonnet 5 + Fable advisor:** Sonnet 5's native 1M context — interactive session, Max-bundled, no `[1m]` suffix needed. Fable 5 advisor via `advisorModel: "fable"` — also Max-bundled. GPT-5.
|
|
205
|
-
- **Setup B — Opus 4.6 Stability:** Opus 4.6 max driver on Max, 1M context included at standard rates (see above). Fable 5 advisor, Max-bundled. GPT-5.
|
|
210
|
+
- **Setup A — Sonnet 5 + Fable advisor:** Sonnet 5's native 1M context — interactive session, Max-bundled, no `[1m]` suffix needed. Fable 5 advisor via `advisorModel: "fable"` — also Max-bundled. GPT-5.6 Sol xhigh reviewer on ChatGPT subscription. Generally lower Max quota consumption than Setup B at the `medium` default (savings shrink at higher effort).
|
|
211
|
+
- **Setup B — Opus 4.6 Stability:** Opus 4.6 max driver on Max, 1M context included at standard rates (see above). Fable 5 advisor, Max-bundled. GPT-5.6 Sol xhigh reviewer, separate.
|
|
206
212
|
- **Setup C — OpusPlan Hybrid:** **fully Max-bundled.** `opusplan` uses Opus (plan mode) + Sonnet (execute mode), both at their native context windows — no credit drain.
|
|
207
213
|
- **⚠️ Avoid `sonnet[1m]` as a manual pin outside Setup A/C:** if your provider or gateway doesn't resolve Sonnet 5 to its native 1M automatically, forcing a `[1m]`-suffixed pin on an older Sonnet can draw from your usage credits pool ($3/$15 per Mtok) instead of your Max subscription. The `/model` picker shows this explicitly — watch for "Draws from usage credits."
|
|
208
|
-
- **Reviewer (GPT-5.
|
|
214
|
+
- **Reviewer (GPT-5.6 Sol xhigh) in all three triads:** billed against your OpenAI account, completely separate from Anthropic.
|
|
209
215
|
- **CI loops that use `claude -p` post-June-15:** these now bill against the separate Anthropic credit pool, not your Max subscription. The wizard's CI shepherd loops (E2E scoring, weekly-update jobs) are local-only on the maintainer's machine and stay on Max; consumer-repo CI integrations may need to budget the new credit pool.
|
|
210
216
|
|
|
211
217
|
### Bottom line
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ All notable changes to the SDLC Wizard.
|
|
|
4
4
|
|
|
5
5
|
> **Note:** This changelog is for humans to read. Don't manually apply these changes - just run the wizard ("Check for SDLC wizard updates") and it handles everything automatically.
|
|
6
6
|
|
|
7
|
+
## [1.87.0] - 2026-07-14
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **🏆 First external contribution in this repo's history: [@thejesh23](https://github.com/thejesh23)** (#444, PR #445 — merged under his authorship). GitHub Copilot CLI ≥ 1.0.65 tightened `argument-hint` frontmatter validation to string-only and silently dropped all 7 wizard skills from its command menu. Bare brackets (`argument-hint: [task description]`) parse as a YAML flow sequence, not a string — the feedback skill's hint even parsed as an array wrapping a *mapping* — and Claude Code's lenient rendering had hidden it since the fields were introduced. His report pinned the exact breaking version with primary-source links and listed every affected file (it matched our own repo-wide sweep exactly); his fix updated the live skills and the `cowork/` copies together. Out of 300+ merged PRs, contributor #1. Maintainer's words, on the record: *"he deserves it and I am forever grateful."*
|
|
11
|
+
- **#444 regression test** (PR #447): `test_argument_hint_frontmatter_is_string` parses every live + cowork SKILL.md frontmatter with real YAML and fails on any non-string `argument-hint`; also guards the wizard doc's copy-source examples (the frontmatter reference-table cell was #445's one untouched straggler — consumers copy these blocks, so an unquoted example re-inherits the bug into generated repos). Hardened per Codex round-1 finding: the grep uses `argument-hint:[[:space:]]*\[` because an exactly-one-space pattern false-greened on zero/two-space variants (mutation-verified both directions). Anti-vacuity guards prevent the test from passing on zero files or unparsed frontmatter. Cross-vendor SKILL.md compatibility is now tracked as ROADMAP #448.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **GPT-5.6 Sol replaces GPT-5.5 as the cross-model reviewer** across all live guidance (#439, PR #441): `AI_SETUP_LANES.md`, `README.md`, `CLAUDE_CODE_SDLC_WIZARD.md`, both sdlc SKILL.md copies, `AGENTS.md`, repo `CLAUDE.md`. The unpinned auto-detect design is deliberately preserved (Codex CLI resolves your account's best model — proven live when it picked up Sol with zero config change); fallback chain documented as Sol → Terra. Reviewer effort stays `xhigh` per OpenAI's own migration guidance; Pro/`max` documented as escalation for unusually risky PRs. Historical citations (vending-bench, E2E audit, CHANGELOG) explicitly untouched and regression-guarded — rewriting them would falsify what actually ran.
|
|
15
|
+
- **Sonnet 5's documented default effort is now `medium`** (was `high`), and the "~5x less Max quota" claim is gone (#440, PR #443). Codex traced the 5x figure to commit `ab6fc9c` with zero supporting measurement anywhere; all 8 instances across 6 live-guidance files replaced with qualified language sourced to Anthropic's tokenizer note (Sonnet 5's newer tokenizer produces ~30% more tokens than Opus 4.6's for the same text; community cost reports suggest the advantage narrows at `high`/`xhigh`; no controlled measurement exists — check `/usage`). CodeRabbit — the source the wizard already cited — actually recommends `medium`. Escalation ladder is now `medium` → `high` → `xhigh`; fresh Fable and Codex opinions independently converged on this. `hooks/model-effort-check.sh` floor updated to match so the hook doesn't nag users following the wizard's own default (`medium` now silent; explicit `low` and the settings-only-`max` quirk still warn; worst-case warning output re-fitted under the 500-char cap after Codex caught the cap test had gone vacuous). 4 new mutation-verified doc-consistency tests plus a repo-wide guard banning the unqualified-multiplier phrasing class.
|
|
16
|
+
- **Setup A semantics made explicit** (PR #446, README "Reading Setup A precisely" + `AI_SETUP_LANES.md`): effort escalation happens *inside* the Sonnet 5 driver; model escalation *swaps the driver* to Opus 4.8 xhigh (2 failed attempts / LOW confidence / high-stakes); `advisor()` failure falls back to spawning a Fable subagent — never to skipping the check. The advisor-outage procedure's "continue with no advisor" path (which directly contradicted the new rule two sections above it — Codex round-1 catch) now routes to the subagent fallback: swap the transport, not the check. Section-scoped negative test assertions keep the skip-path from returning.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- ROADMAP #236 bloat-hunt follow-through (PR #440): hook/test cleanups, ROADMAP archive split.
|
|
20
|
+
- ROADMAP #434 sub-item statuses corrected against git history instead of re-asserted (PR #442).
|
|
21
|
+
|
|
22
|
+
### Why
|
|
23
|
+
Seven consumer-affecting commits had accumulated on main since v1.86.0 (July 5) with no npm release — discovered when the repo's first external bug report (#444) revealed that `npx agentic-sdlc-wizard@latest init` was still installing skills Copilot CLI silently drops even after the fix was merged and celebrated, with nothing in the process that would ever have prompted a release. Merge-to-main does not publish; only a `v*` tag does. Release-drift detection (own-package npm-vs-main watcher, in the style of `cc-version-drift.yml`) is tracked as ROADMAP #449 so this class of stranding is machine-caught, not memory-caught.
|
|
24
|
+
|
|
7
25
|
## [1.86.0] - 2026-07-05
|
|
8
26
|
|
|
9
27
|
### Fixed
|
|
@@ -253,11 +253,11 @@ Claude Code's **effort level** controls how much thinking the model does before
|
|
|
253
253
|
|
|
254
254
|
| Model | Recommended Effort | Why |
|
|
255
255
|
|-------|--------------------|-----|
|
|
256
|
-
| Sonnet 5 (recommended default) | `
|
|
256
|
+
| Sonnet 5 (recommended default) | `medium`, escalate to `high`/`xhigh` for hard tasks | CodeRabbit testing: `medium` captures most of the upside at the lowest cost; blanket `xhigh`/`max` defaults add cost for marginal gains |
|
|
257
257
|
| Opus 4.8 (escalation only) | `xhigh` | `max` triggers excessive reasoning on 4.7/4.8 — documented 40-60x cache-token jump vs `high` (see "Opus 4.6 Stability" tier below) |
|
|
258
258
|
| Fable 5 (advisor) | `high` (its own designed default) | Adaptive thinking always on; `xhigh`/`max` mainly move the thinking-token budget with small marginal gain for review work |
|
|
259
259
|
| Opus 4.6 (Stability lane) | `max` | The one model where `max` doesn't overthink — no `xhigh` support at all (only low/medium/high/max) |
|
|
260
|
-
| OpenAI/Codex (cross-model reviewer) | `xhigh`
|
|
260
|
+
| OpenAI/Codex (cross-model reviewer) | `xhigh` default, escalate to `max`/Pro for unusually risky PRs | Lower reasoning misses subtle bugs the reviewer exists to catch; see `AI_SETUP_LANES.md`'s Final Review Policy for when to escalate |
|
|
261
261
|
|
|
262
262
|
**Strict effort behavior (Opus 4.7+, carried forward in 4.8):**
|
|
263
263
|
- **`xhigh` was introduced in 4.7** — sits between `high` and `max`, designed for coding and agentic work (30+ minute tasks with token budgets in the millions)
|
|
@@ -341,7 +341,7 @@ CC 2.1.117 expanded the `cleanupPeriodDays` setting to also cover `~/.claude/tas
|
|
|
341
341
|
---
|
|
342
342
|
name: sdlc
|
|
343
343
|
description: Full SDLC workflow for implementing features, fixing bugs, refactoring code
|
|
344
|
-
argument-hint: [task description]
|
|
344
|
+
argument-hint: "[task description]"
|
|
345
345
|
---
|
|
346
346
|
|
|
347
347
|
## Task
|
|
@@ -433,7 +433,7 @@ Skills support these frontmatter fields:
|
|
|
433
433
|
| `effort` | Set reasoning effort level | `effort: high` |
|
|
434
434
|
| `paths` | Restrict skill to specific file patterns | `paths: ["src/**/*.ts", "tests/**"]` |
|
|
435
435
|
| `context` | Context mode (`fork` = isolated subagent) | `context: fork` |
|
|
436
|
-
| `argument-hint` | Hint for `$ARGUMENTS` placeholder | `argument-hint: [task description]` |
|
|
436
|
+
| `argument-hint` | Hint for `$ARGUMENTS` placeholder (quote it — bare brackets parse as a YAML array and break strict loaders like Copilot CLI, #444) | `argument-hint: "[task description]"` |
|
|
437
437
|
| `disable-model-invocation` | Prevent skill from being auto-invoked by model | `disable-model-invocation: true` |
|
|
438
438
|
|
|
439
439
|
**Key fields explained:**
|
|
@@ -526,7 +526,7 @@ See the dedicated subsection under [Tasks System](#tasks-system-v2116) (above, i
|
|
|
526
526
|
|
|
527
527
|
### MCP-tool hooks audit (ROADMAP #218, CC 2.1.118)
|
|
528
528
|
|
|
529
|
-
CC 2.1.118 introduced `type: "mcp_tool"` for hooks — a hook can now directly invoke an MCP tool instead of running a bash script. **Audit (2026-04-26) of the 5 wizard hooks that existed at the time concluded: none migrate, all stay bash.** This subsection documents the per-hook reasoning so future audits don't redo the work; if a future PR migrates a hook to MCP, update this entry with the new rationale rather than deleting it. **Not yet re-audited**:
|
|
529
|
+
CC 2.1.118 introduced `type: "mcp_tool"` for hooks — a hook can now directly invoke an MCP tool instead of running a bash script. **Audit (2026-04-26) of the 5 wizard hooks that existed at the time concluded: none migrate, all stay bash.** This subsection documents the per-hook reasoning so future audits don't redo the work; if a future PR migrates a hook to MCP, update this entry with the new rationale rather than deleting it. **Not yet re-audited**: 3 hooks shipped since 2026-04-26 (`codex-gate-check.sh`, `token-spike-check.sh`, `codex-review-stop-check.sh`) — the project now registers 8 hooks total (see `.claude/settings.json`), but this table only covers the original 5.
|
|
530
530
|
|
|
531
531
|
**Decision criteria applied** (any one rules out MCP):
|
|
532
532
|
|
|
@@ -536,11 +536,11 @@ CC 2.1.118 introduced `type: "mcp_tool"` for hooks — a hook can now directly i
|
|
|
536
536
|
|
|
537
537
|
**Per-hook decision** (each row applies at least one criterion explicitly):
|
|
538
538
|
|
|
539
|
-
- **`sdlc-prompt-check.sh`** (UserPromptSubmit, ~
|
|
540
|
-
- **`instructions-loaded-check.sh`** (~
|
|
541
|
-
- **`tdd-pretool-check.sh`** (~
|
|
542
|
-
- **`model-effort-check.sh`** (~
|
|
543
|
-
- **`precompact-seam-check.sh`** (~
|
|
539
|
+
- **`sdlc-prompt-check.sh`** (UserPromptSubmit, ~137 lines) — emits the SDLC BASELINE text on every prompt (fires-once-per-session sentinel), plus a setup-wizard redirect when SDLC.md/TESTING.md are missing. Decision: **Stay bash.** Portability criterion: same script ships to Codex sibling unchanged. Local-state criterion: sentinel cache is local-only. **#236(b) 2026-07-06:** the ROADMAP #195 effort-bump signal log described here previously was removed — never fired in ~2 months of live use.
|
|
540
|
+
- **`instructions-loaded-check.sh`** (~291 lines) — InstructionsLoaded event; wizard-version + CC-version staleness nudges (both npm-cached daily), cross-model-review staleness check, autocompact compound-misconfig check, dual-channel-install check. Decision: **Stay bash.** Portability criterion: Codex sibling has its own equivalent of session-start validation; bash port is direct. Local-state criterion: cache files are local. **#236(b) 2026-07-06:** the SDLC.md/TESTING.md missing-file warning previously described here was removed (redundant with `sdlc-prompt-check.sh`'s louder version).
|
|
541
|
+
- **`tdd-pretool-check.sh`** (~129 lines) — PreToolUse on Write/Edit/MultiEdit; emits a TDD reminder, and (since #436) **blocks** with `exit 2` when a `src/**` write (or `SDLC_TDD_SRC_PATTERN`-overridden path, added #236(b) for this repo's own `src/`-less dogfooding) happens before any test file was touched this session (an edit-ordering proxy for TDD RED, session-scoped via a cache-dir sentinel). Decision: **Stay bash.** Fail-closed gating criterion applies now that this hook blocks: bash `exit 2` fails closed by definition, whereas an `mcp_tool` hook's block decision is lost if the MCP server errors — wrong default for a gate. Portability criterion: still trivially portable.
|
|
542
|
+
- **`model-effort-check.sh`** (~87 lines) — SessionStart event; reads `CLAUDE_CODE_EFFORT_LEVEL` env var (falling back to `effortLevel` in the settings cascade), emits nothing when effort is `high`/`xhigh`/`max`/unset, otherwise a loud warning. Decision: **Stay bash.** Portability criterion: env-var read maps 1:1 to any agent runtime. Local-state criterion: not applicable, hook is stateless. **#236(b) 2026-07-06:** unset used to loud-warn too (CC's own default state) — now silent; only an explicit low-effort value or the settings-only-`max` quirk warns.
|
|
543
|
+
- **`precompact-seam-check.sh`** (~101 lines) — PreCompact event (matcher: `manual`); blocks manual `/compact` with exit 2 + stderr message when a git rebase/merge/cherry-pick is in progress. Decision: **Stay bash.** Fail-closed gating criterion: bash exit 2 fails closed by definition; an MCP `mcp_tool` hook returning `decision: "block"` works on the happy path, but if the MCP server crashes/times out the action proceeds — that flips the safety property from fail-closed to fail-open. For a hook whose entire job is to prevent context loss at bad seams, fail-open is the wrong default. **#236(b) 2026-07-06:** this hook used to also block on `.reviews/handoff.json` being `PENDING_*` (mid cross-model-review-round), with 3 self-heal paths mitigating that branch's false-positive rate — removed; every real firing on record was a false positive, never a true positive.
|
|
544
544
|
|
|
545
545
|
**When to revisit this audit:**
|
|
546
546
|
|
|
@@ -1085,9 +1085,9 @@ This is **Setup C (OpusPlan Hybrid/Saver)** in `AI_SETUP_LANES.md`. CC's native
|
|
|
1085
1085
|
|
|
1086
1086
|
| Layer | Setup C (OpusPlan) | Setup A (default) | Setup B (Stability) |
|
|
1087
1087
|
|-------|--------------------|--------------------|----------------------|
|
|
1088
|
-
| Planner | Opus 4.8 `xhigh` (Plan Mode) | Sonnet 5 `high`→`xhigh` | Opus 4.6 `max` |
|
|
1089
|
-
| Driver | Sonnet 5 `
|
|
1090
|
-
| Reviewer | GPT-5.
|
|
1088
|
+
| Planner | Opus 4.8 `xhigh` (Plan Mode) | Sonnet 5 `medium`→`high`→`xhigh` | Opus 4.6 `max` |
|
|
1089
|
+
| Driver | Sonnet 5 `medium` (execute mode) | Sonnet 5 `medium`→`high`→`xhigh` | Opus 4.6 `max` |
|
|
1090
|
+
| Reviewer | GPT-5.6 Sol xhigh | GPT-5.6 Sol xhigh | GPT-5.6 Sol xhigh |
|
|
1091
1091
|
|
|
1092
1092
|
**How to opt in:**
|
|
1093
1093
|
```json
|
|
@@ -1110,7 +1110,7 @@ Set effort per-session with `/effort` (planner `xhigh`, driver `high`) rather th
|
|
|
1110
1110
|
**Prove-It Gate (#233 acceptance criterion):** mixed-mode ships only if pair-tested on 3+ simple repos shows Sonnet-coder + Opus-reviewer produces ≥ same SDLC scores as full-Opus baseline. The first version of the heuristic ships v1.38.0; pair-test results land in CHANGELOG before recommending mixed-mode as the default for any tier.
|
|
1111
1111
|
|
|
1112
1112
|
**Tradeoffs (be honest):**
|
|
1113
|
-
- The Sonnet driver will drop some fine-grained self-review moves compared to an Opus-coder run — it's fast, less deliberate. The Opus planner and GPT-5.
|
|
1113
|
+
- The Sonnet driver will drop some fine-grained self-review moves compared to an Opus-coder run — it's fast, less deliberate. The Opus planner and GPT-5.6 Sol reviewer catch them, but expect more "fix in round 2" cycles.
|
|
1114
1114
|
- Mixed-mode disables auto-mode (same as any pinned model). The pin is per-session — to switch back, remove the `model` line.
|
|
1115
1115
|
|
|
1116
1116
|
### Latest tier — Opus 4.8 (escalation model, #395)
|
|
@@ -2213,7 +2213,7 @@ chmod +x .claude/hooks/sdlc-prompt-check.sh
|
|
|
2213
2213
|
|
|
2214
2214
|
## Step 5: Create the TDD Hook
|
|
2215
2215
|
|
|
2216
|
-
**Illustrative, not exhaustive:** this teaches the PreToolUse/exit-2 blocking mechanic with one hook. The wizard ships **
|
|
2216
|
+
**Illustrative, not exhaustive:** this teaches the PreToolUse/exit-2 blocking mechanic with one hook. The wizard ships **8 production hooks total** — only this one and Step 4's light hook have hand-typed templates in this doc; the other 6 (`codex-gate-check.sh`, `instructions-loaded-check.sh`, `model-effort-check.sh`, `precompact-seam-check.sh`, `codex-review-stop-check.sh`, `token-spike-check.sh`) don't, because there's no substitute for the real files. **For the complete, always-in-sync set, run `npx agentic-sdlc-wizard@latest init`** instead of hand-building hooks 3-8 from prose descriptions elsewhere in this doc.
|
|
2217
2217
|
|
|
2218
2218
|
Create `.claude/hooks/tdd-pretool-check.sh`:
|
|
2219
2219
|
|
|
@@ -2274,7 +2274,7 @@ Create `.claude/skills/sdlc/SKILL.md`:
|
|
|
2274
2274
|
---
|
|
2275
2275
|
name: sdlc
|
|
2276
2276
|
description: Full SDLC workflow for implementing features, fixing bugs, refactoring code, testing, releasing, publishing, and deploying. Use this skill when implementing, fixing, refactoring, testing, adding features, building new code, or releasing/publishing/deploying.
|
|
2277
|
-
argument-hint: [task description]
|
|
2277
|
+
argument-hint: "[task description]"
|
|
2278
2278
|
---
|
|
2279
2279
|
# SDLC Skill - Full Development Workflow
|
|
2280
2280
|
|
|
@@ -2385,7 +2385,7 @@ Before presenting approach, STATE your confidence:
|
|
|
2385
2385
|
| FAILED 2x | Something's wrong | STOP. ASK USER immediately | **Escalate effort now** — you're burning cycles at lower effort |
|
|
2386
2386
|
| CONFUSED | Can't diagnose why something is failing | STOP. Describe what you tried, ask for help | **Escalate effort now** — stop spinning |
|
|
2387
2387
|
|
|
2388
|
-
"Model default" and "escalate" are model-aware, not a blanket `max` — see "Recommended Effort Level" above for the per-model table (Sonnet 5: `high`→`xhigh`; Opus 4.8: `xhigh`; Opus 4.6: `max`; Fable: `high`).
|
|
2388
|
+
"Model default" and "escalate" are model-aware, not a blanket `max` — see "Recommended Effort Level" above for the per-model table (Sonnet 5: `medium`→`high`→`xhigh`; Opus 4.8: `xhigh`; Opus 4.6: `max`; Fable: `high`).
|
|
2389
2389
|
|
|
2390
2390
|
**Dynamic bumping is NOT optional.** "Consider higher effort" is the same as "ignore this" in practice. If your confidence drops or tests fail twice, bump effort BEFORE the next attempt — spinning at low effort is an SDLC failure mode.
|
|
2391
2391
|
|
|
@@ -3075,7 +3075,7 @@ If deployment fails or post-deploy verification catches issues:
|
|
|
3075
3075
|
|
|
3076
3076
|
**SDLC.md:**
|
|
3077
3077
|
```markdown
|
|
3078
|
-
<!-- SDLC Wizard Version: 1.
|
|
3078
|
+
<!-- SDLC Wizard Version: 1.87.0 -->
|
|
3079
3079
|
<!-- Setup Date: [DATE] -->
|
|
3080
3080
|
<!-- Completed Steps: step-0.1, step-0.2, step-0.4, step-1, step-2, step-3, step-4, step-5, step-6, step-7, step-8, step-9 -->
|
|
3081
3081
|
<!-- Git Workflow: [PRs or Solo] -->
|
|
@@ -3852,12 +3852,12 @@ Use an independent AI model from a different company as a code reviewer. The aut
|
|
|
3852
3852
|
|
|
3853
3853
|
**Why this works:** Two AI systems from different companies (e.g., Claude writes, GPT reviews) provide adversarial diversity. They have fundamentally different training, different failure modes, and different strengths. What one misses, the other catches.
|
|
3854
3854
|
|
|
3855
|
-
**Use the best model at the deepest reasoning.** This is your quality gate — don't economize on it. Always use the latest, most capable model available (**GPT-5.
|
|
3855
|
+
**Use the best model at the deepest reasoning.** This is your quality gate — don't economize on it. Always use the latest, most capable model available (**GPT-5.6 Sol if you have access**, otherwise Terra) at `xhigh` reasoning effort (non-negotiable — lower settings miss subtle errors; preserve this baseline rather than downgrading it on a model bump). Cheaper/faster models miss things. The whole point is catching what the authoring model couldn't. For unusually risky PRs, escalating to `max` or Pro mode is defensible — see `AI_SETUP_LANES.md`'s Final Review Policy — but `xhigh` is the default; no published data shows the higher tiers catching meaningfully more real bugs on ordinary PR review.
|
|
3856
3856
|
|
|
3857
3857
|
**Prerequisites:**
|
|
3858
3858
|
- Codex CLI installed: `npm i -g @openai/codex`
|
|
3859
3859
|
- OpenAI API key configured: `export OPENAI_API_KEY=...`
|
|
3860
|
-
- Codex CLI picks up your OpenAI account's best available model automatically. If you have GPT-5.
|
|
3860
|
+
- Codex CLI picks up your OpenAI account's best available model automatically. If you have GPT-5.6 Sol access, `codex exec` uses it; otherwise it falls back to Terra. No config change needed on your side.
|
|
3861
3861
|
- This is a local workflow tool — not required for CI/CD
|
|
3862
3862
|
|
|
3863
3863
|
**The Protocol:**
|
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ export OPENAI_API_KEY=sk-...
|
|
|
123
123
|
codex --version # confirm ready
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
That's it. Codex picks up your OpenAI account's best available model automatically — **if you have GPT-5.
|
|
126
|
+
That's it. Codex picks up your OpenAI account's best available model automatically — **if you have GPT-5.6 Sol, it uses Sol; otherwise it falls back to Terra**. No model config needed.
|
|
127
127
|
|
|
128
128
|
**How to use it:** after Claude's self-review passes, write a one-file mission brief and run:
|
|
129
129
|
|
|
@@ -142,7 +142,7 @@ codex exec -c 'model_reasoning_effort="xhigh"' -s danger-full-access \
|
|
|
142
142
|
|
|
143
143
|
The wizard ships a **default recommendation**, not a mandate. You can swap to any Claude model — newer, older, or sibling tier — at any time. `/model` per session, or pin in `.claude/settings.json`.
|
|
144
144
|
|
|
145
|
-
**Default: Sonnet 5 at `
|
|
145
|
+
**Default: Sonnet 5 at `medium` effort, escalating to `high`/`xhigh`** (Setup A in `AI_SETUP_LANES.md`). Sonnet 5 (launched 2026-06-30) beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 2.1 80.4% vs 65.4%) while generally using less Max quota — savings vary by effort level and narrow at `high`/`xhigh` (newer tokenizer, more agentic turns per task). Opus 4.6 remains available as **Setup B — Stability** for proven-consistency workflows; here's why it's no longer the default.
|
|
146
146
|
|
|
147
147
|
### Why Opus 4.6 was the flagship, and why that changed
|
|
148
148
|
|
|
@@ -156,7 +156,7 @@ Two weeks of in-the-wild data after Opus 4.8's launch (2026-05-28) showed a clea
|
|
|
156
156
|
- **[BSWEN effort decision guide](https://docs.bswen.com/blog/2026-04-19-claude-code-effort-level-decision-guide/)** — "Max on Opus causes overthinking on routine stuff. xHigh is the sweet spot for autonomous work"
|
|
157
157
|
- **r/Claudeopus field reports** — one maintainer's literal A/B: "12 hours with 4.8 zero deliverables; plugged in 4.6, spec written + 133 tests green in one session." Top comment: "4.6 had the best overall balance at max"
|
|
158
158
|
|
|
159
|
-
That research still stands — it's why **Opus 4.6 remains Setup B (Stability)** rather than being dropped entirely, and why the wizard escalates to Opus **4.8** (not a blanket "latest") only when Sonnet 5 gets stuck. But Sonnet 5's June 30 launch changed the calculus for the *default*: it beats Opus 4.6 on every benchmark above at
|
|
159
|
+
That research still stands — it's why **Opus 4.6 remains Setup B (Stability)** rather than being dropped entirely, and why the wizard escalates to Opus **4.8** (not a blanket "latest") only when Sonnet 5 gets stuck. But Sonnet 5's June 30 launch changed the calculus for the *default*: it beats Opus 4.6 on every benchmark above at generally lower quota cost, so it's no longer a tradeoff between "reliable but weaker" and "strong but overthinks" — Sonnet 5 doesn't have Opus 4.8's overthinking problem in the first place.
|
|
160
160
|
|
|
161
161
|
4.6 remains Anthropic-supported until **≥ Feb 5, 2027** per the [official deprecation page](https://platform.claude.com/docs/en/about-claude/model-deprecations), so Setup B stays a safe long-term choice if you've tuned a workflow to its behavior specifically.
|
|
162
162
|
|
|
@@ -172,10 +172,10 @@ That research still stands — it's why **Opus 4.6 remains Setup B (Stability)**
|
|
|
172
172
|
Or pin in `.claude/settings.json`:
|
|
173
173
|
|
|
174
174
|
```json
|
|
175
|
-
{ "model": "sonnet", "advisorModel": "fable", "effortLevel": "
|
|
175
|
+
{ "model": "sonnet", "advisorModel": "fable", "effortLevel": "medium" }
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
**Effort is model-aware, not blanket `max`.** Sonnet 5: `
|
|
178
|
+
**Effort is model-aware, not blanket `max`.** Sonnet 5: `medium` default (CodeRabbit-tested), escalate `/effort high` → `xhigh` for hard tasks. Opus 4.8: `xhigh` (its own `max` overthinks). Opus 4.6: `max` (its one `xhigh`-less sweet spot). Set per-session with `/effort`, not a shell-rc or settings env var — persisting effort that way silently overrides a later `/effort` change after you switch models (see `SDLC.md`'s Lessons Learned for a real incident this caused). OpenAI/Codex reviewer: `xhigh` default — escalate to `max`/Pro mode only for unusually risky PRs (see `AI_SETUP_LANES.md`'s Final Review Policy).
|
|
179
179
|
|
|
180
180
|
### Four Setup Lanes
|
|
181
181
|
|
|
@@ -183,13 +183,21 @@ The wizard defines four AI coding setups in [`AI_SETUP_LANES.md`](AI_SETUP_LANES
|
|
|
183
183
|
|
|
184
184
|
| Lane | Advisor | Driver | Reviewer | Escalation |
|
|
185
185
|
|------|---------|--------|----------|------------|
|
|
186
|
-
| **A — Recommended** | Fable 5 (advisorModel) | Sonnet 5, `high`→`xhigh` | GPT-5.
|
|
187
|
-
| **B — Stability** | Fable 5 (advisorModel) | Opus 4.6 max | GPT-5.
|
|
188
|
-
| **C — Saver** | Fable 5 or Opus 4.8 (advisorModel) | Opus 4.8 plans, Sonnet 5 executes | GPT-5.
|
|
186
|
+
| **A — Recommended** | Fable 5 (advisorModel) | Sonnet 5, `medium`→`high`→`xhigh` | GPT-5.6 Sol xhigh | Opus 4.8 xhigh or Fable review |
|
|
187
|
+
| **B — Stability** | Fable 5 (advisorModel) | Opus 4.6 max | GPT-5.6 Sol xhigh | None |
|
|
188
|
+
| **C — Saver** | Fable 5 or Opus 4.8 (advisorModel) | Opus 4.8 plans, Sonnet 5 executes | GPT-5.6 Sol xhigh | None |
|
|
189
189
|
| **D — Lite** | None | Sonnet 5, `medium` | None | None |
|
|
190
190
|
|
|
191
191
|
Setup D's whole point: **the discipline of knowing when NOT to use discipline.** When blast radius is low and you just need fast cheap hands, skip the SDLC overhead.
|
|
192
192
|
|
|
193
|
+
### Reading Setup A precisely
|
|
194
|
+
|
|
195
|
+
Clarified 2026-07-13 after these exact points kept getting re-confused; each rule states its why:
|
|
196
|
+
|
|
197
|
+
- **Effort escalation stays inside the driver.** Sonnet 5 starts at `medium`; `/effort high` when it struggles, `xhigh` for hard debugging or long agent runs. Why `medium` and not `high`: the old "start at `high`" guidance was removed in ROADMAP #440 — it had no measurement behind it, and CodeRabbit's testing (the source this repo already cites) found `medium` captures most of Sonnet 5's upside without paying for the top effort tiers, while community cost reports suggest the quota advantage erodes at `high`/`xhigh`.
|
|
198
|
+
- **Model escalation swaps the driver.** After 2 failed attempts, LOW confidence, or on high-stakes changes, Opus 4.8 xhigh takes over as driver (or run a Fable 5 review pass on the diff). Why a swap and not more effort: the lane's policy treats repeated failure as a sign the *approach* needs different eyes, not deeper reasoning on the same track — so once the effort ladder is exhausted, the next rung is a different model, not a bigger bill.
|
|
199
|
+
- **Advisor failure has a fallback, not a shrug.** Fable 5 advises via `advisorModel: "fable"`; when `advisor()` errors (it's a server-side tool — API incidents happen), spawn a Fable subagent as the fallback reviewer, exactly as the `/sdlc` skill prescribes. Why: the advisor's job is catching wrong approaches *before* they're built, so a transport failure changes how the advice is obtained — not whether the check happens.
|
|
200
|
+
|
|
193
201
|
**A note on `[1m]` and billing.** Sonnet 5 always runs at its native 1M context — no `[1m]` suffix needed, no separate billing tier. For Opus, the `[1m]` suffix is the 1M-context alias; as of [March 2026](https://claude.com/blog/1m-context-ga), 1M context is GA at standard pricing — **no long-context surcharge, no premium tier, no API-only restriction.** Interactive Claude Code sessions on Max / Team / Enterprise plans include 1M context automatically. (Pro users need "Enable usage credits" turned on once.) The [June 15, 2026 billing split](https://codersera.com/blog/anthropic-june-2026-billing-change-claude-code/) moved *headless* surfaces — `claude -p`, Agent SDK, GitHub Actions, third-party apps — off the Max subscription onto a separate metered credit pool. Interactive Claude Code in your terminal stays on Max. Full details in [`AI_SETUP_LANES.md` § How Billing Works](AI_SETUP_LANES.md#how-billing-works--1m-context-max-plan-and-the-june-15-split).
|
|
194
202
|
|
|
195
203
|
## How It Works
|
package/cli/init.js
CHANGED
|
@@ -25,7 +25,6 @@ const FILES = [
|
|
|
25
25
|
{ src: 'hooks/instructions-loaded-check.sh', dest: '.claude/hooks/instructions-loaded-check.sh', executable: true, base: REPO_ROOT },
|
|
26
26
|
{ src: 'hooks/model-effort-check.sh', dest: '.claude/hooks/model-effort-check.sh', executable: true, base: REPO_ROOT },
|
|
27
27
|
{ src: 'hooks/precompact-seam-check.sh', dest: '.claude/hooks/precompact-seam-check.sh', executable: true, base: REPO_ROOT },
|
|
28
|
-
{ src: 'hooks/goal-confidence-check.sh', dest: '.claude/hooks/goal-confidence-check.sh', executable: true, base: REPO_ROOT },
|
|
29
28
|
{ src: 'hooks/codex-gate-check.sh', dest: '.claude/hooks/codex-gate-check.sh', executable: true, base: REPO_ROOT },
|
|
30
29
|
{ src: 'hooks/token-spike-check.sh', dest: '.claude/hooks/token-spike-check.sh', executable: true, base: REPO_ROOT },
|
|
31
30
|
{ src: 'hooks/codex-review-stop-check.sh', dest: '.claude/hooks/codex-review-stop-check.sh', executable: true, base: REPO_ROOT },
|
|
@@ -32,13 +32,37 @@ TOOL_INPUT=$(cat)
|
|
|
32
32
|
# still can't run past the field's true (unescaped) closing quote because
|
|
33
33
|
# neither alternative in the group can match a bare `"`. Scoped to just
|
|
34
34
|
# this field, so unrelated fields containing the phrase can't false-trigger.
|
|
35
|
+
# #236(b): under `set -e`, a grep with no match exits 1 and kills the whole
|
|
36
|
+
# script with an undefined exit code (a "command" field can be absent, e.g.
|
|
37
|
+
# an old-format payload) — `|| true` makes "no match" a clean, deliberate
|
|
38
|
+
# empty COMMAND_FIELD instead of a crash.
|
|
35
39
|
COMMAND_FIELD=$(printf '%s' "$TOOL_INPUT" \
|
|
36
|
-
| grep -oE '"command"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)*"')
|
|
40
|
+
| grep -oE '"command"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)*"' || true)
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
# Codex cross-model review finding (#236(b) round 1, 2026-07-06): a `-c`/`-C`
|
|
43
|
+
# value containing a space inside quotes is a real, valid git invocation
|
|
44
|
+
# (e.g. `git -c user.name="A B" commit`) but broke the structural match below
|
|
45
|
+
# — `\S+` stops at the embedded space, so the flag-value alternative never
|
|
46
|
+
# matches and the whole "git ... commit" pattern silently fails, letting the
|
|
47
|
+
# commit through unreviewed. Fix: strip COMMAND_FIELD down to just the raw
|
|
48
|
+
# value content (COMMAND_VALUE, still JSON-escaped), then collapse every
|
|
49
|
+
# quoted sub-span — both JSON-escaped `\"..\"` and plain `'..'` — to a single
|
|
50
|
+
# placeholder token before the structural match runs, so a quoted value can
|
|
51
|
+
# never look like more than one word to it.
|
|
52
|
+
COMMAND_VALUE=$(printf '%s' "$COMMAND_FIELD" \
|
|
53
|
+
| sed -E 's/^"command"[[:space:]]*:[[:space:]]*"(.*)"$/\1/')
|
|
54
|
+
MASKED_COMMAND=$(printf '%s' "$COMMAND_VALUE" \
|
|
55
|
+
| sed -E -e 's/\\"[^\\]*\\"/Q/g' -e "s/'[^']*'/Q/g")
|
|
56
|
+
|
|
57
|
+
# #236(b): literal substring "git commit" misses git's own global-flag forms
|
|
58
|
+
# — `git -C <dir> commit` and `git -c k=v commit` are valid invocations that
|
|
59
|
+
# never contain that exact two-word substring, and previously sailed through
|
|
60
|
+
# unreviewed. Regex allows any number of -C/-c (with their required value),
|
|
61
|
+
# --long-flag, or single-letter-flag tokens between "git" and "commit".
|
|
62
|
+
if ! printf '%s' "$MASKED_COMMAND" \
|
|
63
|
+
| grep -qE '\bgit(\s+(-C\s+\S+|-c\s+\S+|--\S+|-[A-Za-z]))*\s+commit\b'; then
|
|
64
|
+
exit 0
|
|
65
|
+
fi
|
|
42
66
|
|
|
43
67
|
REVIEW_FILE=".reviews/handoff.json"
|
|
44
68
|
|
|
@@ -62,6 +62,11 @@ if [ -n "$SESSION_ID" ]; then
|
|
|
62
62
|
fi
|
|
63
63
|
fi
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
# #236(b): on exit 0, stderr is never surfaced (to the user or to Claude) —
|
|
66
|
+
# only stdout JSON is. An earlier stderr+exit-0 version of this line was
|
|
67
|
+
# silently discarded since the day this hook shipped (#436).
|
|
68
|
+
cat << 'EOF'
|
|
69
|
+
{"hookSpecificOutput": {"hookEventName": "Stop", "additionalContext": "NOTE: uncommitted changes with no REVIEWED/CERTIFIED cross-model review artifact. If this work is heading to a commit, run Codex review before committing."}}
|
|
70
|
+
EOF
|
|
66
71
|
|
|
67
72
|
exit 0
|
package/hooks/hooks.json
CHANGED
|
@@ -12,31 +12,19 @@ source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
|
12
12
|
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
|
|
13
13
|
|
|
14
14
|
# CWD walk-up finds nearest SDLC project (#173: silent exit for non-SDLC dirs)
|
|
15
|
+
# #236(b): the missing-SDLC.md/TESTING.md warning that used to live here was
|
|
16
|
+
# removed — sdlc-prompt-check.sh already fires the same "SETUP NOT COMPLETE"
|
|
17
|
+
# warning, louder and on every prompt (this hook only fires at session
|
|
18
|
+
# start/resume), making this copy pure duplicate context.
|
|
15
19
|
if find_sdlc_root; then
|
|
16
20
|
PROJECT_DIR="$SDLC_ROOT"
|
|
17
21
|
elif find_partial_sdlc_root; then
|
|
18
|
-
# Partial setup — one file exists but not both. Warn about missing files
|
|
19
22
|
PROJECT_DIR="$SDLC_ROOT"
|
|
20
23
|
else
|
|
21
24
|
# Not an SDLC project at all — exit silently
|
|
22
25
|
exit 0
|
|
23
26
|
fi
|
|
24
27
|
|
|
25
|
-
MISSING=""
|
|
26
|
-
|
|
27
|
-
if [ ! -f "$PROJECT_DIR/SDLC.md" ]; then
|
|
28
|
-
MISSING="${MISSING:+${MISSING}, }SDLC.md"
|
|
29
|
-
fi
|
|
30
|
-
|
|
31
|
-
if [ ! -f "$PROJECT_DIR/TESTING.md" ]; then
|
|
32
|
-
MISSING="${MISSING:+${MISSING}, }TESTING.md"
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
if [ -n "$MISSING" ]; then
|
|
36
|
-
echo "WARNING: Missing SDLC wizard files: ${MISSING}"
|
|
37
|
-
echo "Invoke Skill tool, skill=\"setup-wizard\" to generate them."
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
28
|
# Version update check (non-blocking, best-effort).
|
|
41
29
|
# Fetches npm latest at most once per 24h (ROADMAP #196). Prints a stronger
|
|
42
30
|
# multi-line nudge when the gap is ≥3 minor versions — the one-liner gets
|
|
@@ -258,11 +246,43 @@ fi
|
|
|
258
246
|
# Claude Code version check (non-blocking, best-effort)
|
|
259
247
|
# Gate on CLAUDE_PROJECT_DIR — only Claude Code sets this. Without it, we're
|
|
260
248
|
# running under Codex/OpenCode where a CC update nudge is misleading (#375).
|
|
249
|
+
# #236(b): was an uncached npm network call on every session start with a
|
|
250
|
+
# bare `!=` comparison (fires in either direction, including when local is
|
|
251
|
+
# actually AHEAD of the cached/published "latest") — the exact bug class
|
|
252
|
+
# already fixed above for the wizard's own version check (#254 Bug 2). Now
|
|
253
|
+
# reuses the same 24h cache + semver_lt direction check.
|
|
261
254
|
if [ -n "${CLAUDE_PROJECT_DIR:-}" ] && command -v claude > /dev/null 2>&1 && command -v npm > /dev/null 2>&1; then
|
|
262
255
|
CC_LOCAL=$(claude --version 2>/dev/null | grep -o '[0-9][0-9.]*' | head -1) || true
|
|
263
|
-
if [ -n "$CC_LOCAL" ]; then
|
|
264
|
-
|
|
265
|
-
|
|
256
|
+
if [ -n "$CC_LOCAL" ] && [[ "$CC_LOCAL" =~ $SEMVER_RE ]]; then
|
|
257
|
+
CC_CACHE_DIR="${SDLC_WIZARD_CACHE_DIR:-$HOME/.cache/sdlc-wizard}"
|
|
258
|
+
CC_CACHE_FILE="$CC_CACHE_DIR/latest-cc-version"
|
|
259
|
+
CC_LATEST=""
|
|
260
|
+
|
|
261
|
+
if [ -f "$CC_CACHE_FILE" ]; then
|
|
262
|
+
if stat -f %m "$CC_CACHE_FILE" > /dev/null 2>&1; then
|
|
263
|
+
CC_CACHE_MTIME=$(stat -f %m "$CC_CACHE_FILE")
|
|
264
|
+
else
|
|
265
|
+
CC_CACHE_MTIME=$(stat -c %Y "$CC_CACHE_FILE" 2>/dev/null || echo 0)
|
|
266
|
+
fi
|
|
267
|
+
CC_CACHE_AGE=$(( $(date +%s) - CC_CACHE_MTIME ))
|
|
268
|
+
if [ "$CC_CACHE_AGE" -lt 86400 ]; then
|
|
269
|
+
CC_CACHE_CONTENT=$(cat "$CC_CACHE_FILE" 2>/dev/null) || CC_CACHE_CONTENT=""
|
|
270
|
+
if [[ "$CC_CACHE_CONTENT" =~ $SEMVER_RE ]] && ! semver_lt "$CC_CACHE_CONTENT" "$CC_LOCAL"; then
|
|
271
|
+
CC_LATEST="$CC_CACHE_CONTENT"
|
|
272
|
+
fi
|
|
273
|
+
fi
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
if [ -z "$CC_LATEST" ]; then
|
|
277
|
+
CC_NPM_RESULT=$(npm view @anthropic-ai/claude-code version 2>/dev/null) || true
|
|
278
|
+
if [[ "$CC_NPM_RESULT" =~ $SEMVER_RE ]]; then
|
|
279
|
+
CC_LATEST="$CC_NPM_RESULT"
|
|
280
|
+
mkdir -p "$CC_CACHE_DIR" 2>/dev/null || true
|
|
281
|
+
printf '%s' "$CC_LATEST" > "$CC_CACHE_FILE" 2>/dev/null || true
|
|
282
|
+
fi
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
if [ -n "$CC_LATEST" ] && semver_lt "$CC_LOCAL" "$CC_LATEST"; then
|
|
266
286
|
echo "Claude Code update available: ${CC_LOCAL} → ${CC_LATEST} (run: npm install -g @anthropic-ai/claude-code)"
|
|
267
287
|
fi
|
|
268
288
|
fi
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# SessionStart hook — effort/model nudge.
|
|
3
3
|
#
|
|
4
|
-
# Behavior (
|
|
4
|
+
# Behavior (#440 update — medium joins the floor):
|
|
5
5
|
# CLAUDE_CODE_EFFORT_LEVEL env var takes precedence over effortLevel in settings.
|
|
6
6
|
# CC docs: max is session-only in settings.json — only the env var persists it.
|
|
7
7
|
# This hook cannot detect the active model (SessionStart payload has no model
|
|
8
8
|
# field, per ROADMAP #180), so it uses a floor that's correct across models:
|
|
9
|
-
# `
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
9
|
+
# `medium` is Sonnet 5's documented default (CodeRabbit testing: most of the
|
|
10
|
+
# upside at the lowest cost — escalate high -> xhigh for hard tasks); `high`
|
|
11
|
+
# is Fable's default; xhigh is Opus 4.8's floor; max remains the sweet spot
|
|
12
|
+
# on Opus 4.6 (no xhigh support). Blanket max is WRONG for Sonnet 5/Opus 4.8
|
|
13
|
+
# (wastes tokens for no quality gain — see AI_SETUP_LANES.md per-model table).
|
|
13
14
|
#
|
|
14
|
-
# effort=high, xhigh, or max -> silent (all acceptable — model-dependent)
|
|
15
|
-
# anything else
|
|
15
|
+
# effort=medium, high, xhigh, or max -> silent (all acceptable — model-dependent)
|
|
16
|
+
# anything else -> LOUD WARNING
|
|
16
17
|
#
|
|
17
18
|
# Non-blocking: always exits 0.
|
|
18
19
|
|
|
@@ -49,32 +50,37 @@ if [ -z "$effort" ]; then
|
|
|
49
50
|
done
|
|
50
51
|
fi
|
|
51
52
|
|
|
52
|
-
# high/xhigh are always silent (persist fine via settings.json, no CC
|
|
53
|
-
# max is silent EXCEPT when it's settings-only — CC docs: max is
|
|
54
|
-
# in settings.json, only the env var actually persists it.
|
|
55
|
-
if [ "$effort" = "high" ] || [ "$effort" = "xhigh" ]; then
|
|
53
|
+
# medium/high/xhigh are always silent (persist fine via settings.json, no CC
|
|
54
|
+
# quirk). max is silent EXCEPT when it's settings-only — CC docs: max is
|
|
55
|
+
# session-only in settings.json, only the env var actually persists it.
|
|
56
|
+
if [ "$effort" = "medium" ] || [ "$effort" = "high" ] || [ "$effort" = "xhigh" ]; then
|
|
56
57
|
exit 0
|
|
57
58
|
fi
|
|
58
59
|
if [ "$effort" = "max" ] && [ "$settings_max" -eq 0 ]; then
|
|
59
60
|
exit 0
|
|
60
61
|
fi
|
|
61
62
|
|
|
63
|
+
# #236(b): unset (no env var, no settings entry) is CC's own current default —
|
|
64
|
+
# not a problem state on its own (e.g. a deliberate Fable-session config).
|
|
65
|
+
# Only warn on an EXPLICITLY set low-effort value or the settings-only-max
|
|
66
|
+
# quirk below (CC silently ignores settings.json's "max" — genuinely
|
|
67
|
+
# non-obvious, worth keeping).
|
|
68
|
+
if [ -z "$effort" ]; then
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
62
72
|
if [ "$settings_max" -eq 1 ] && [ -z "${CLAUDE_CODE_EFFORT_LEVEL:-}" ]; then
|
|
63
73
|
effort_display="max (settings-only — CC ignores this)"
|
|
64
|
-
elif [ -z "$effort" ]; then
|
|
65
|
-
effort_display="unset"
|
|
66
74
|
else
|
|
67
75
|
effort_display="$effort"
|
|
68
76
|
fi
|
|
69
77
|
|
|
70
|
-
echo "
|
|
71
|
-
echo " WARNING: effort '$effort_display' —
|
|
72
|
-
echo "
|
|
73
|
-
echo ""
|
|
74
|
-
echo "
|
|
75
|
-
echo " Avoid shell-rc env var persistence — silently overrides model switches."
|
|
76
|
-
echo ""
|
|
78
|
+
echo "=============================================================="
|
|
79
|
+
echo " WARNING: effort '$effort_display' — below the SDLC floor (medium)."
|
|
80
|
+
echo " Degraded reasoning, shallow TDD, weak self-review."
|
|
81
|
+
echo " Run: /effort medium (Sonnet 5) or your model's floor — see AI_SETUP_LANES.md"
|
|
82
|
+
echo " Avoid shell-rc env persistence — overrides model switches."
|
|
77
83
|
echo " recommended models: $RECOMMENDED_MODELS"
|
|
78
|
-
echo "
|
|
84
|
+
echo "=============================================================="
|
|
79
85
|
|
|
80
86
|
exit 0
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# PreCompact hook - block manual /compact
|
|
2
|
+
# PreCompact hook - block manual /compact mid-git-operation
|
|
3
3
|
# Fires on manual /compact only (auto-compact is threshold-driven; blocking
|
|
4
4
|
# it could push past 100% context and lose everything). Matcher: "manual"
|
|
5
5
|
# in .claude/settings.json.
|
|
6
6
|
#
|
|
7
7
|
# Requires Claude Code v2.1.105+ (PreCompact event introduced April 13, 2026).
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
9
|
+
# #236(b): the original design also blocked on .reviews/handoff.json being
|
|
10
|
+
# PENDING_REVIEW/PENDING_RECHECK (mid cross-model-review-round). Removed —
|
|
11
|
+
# every real firing on record over ~2.5 months was a false positive (a
|
|
12
|
+
# completed rebase's stale REBASE_HEAD, or an abandoned PENDING handoff),
|
|
13
|
+
# never a true positive, and ~150 of this file's 256 lines were self-heal
|
|
14
|
+
# machinery mitigating that false-positive rate (3 heal paths + dry-run
|
|
15
|
+
# scaffolding). The git-op check below has no such record.
|
|
16
|
+
#
|
|
17
|
+
# Seam policy: compacting mid-git-operation loses evidence the operation
|
|
18
|
+
# needs to finish correctly. Block when a rebase/merge/cherry-pick is in
|
|
19
|
+
# progress; allow otherwise.
|
|
16
20
|
|
|
17
21
|
# Token-bloat fix: when both project + plugin register this hook, plugin yields.
|
|
18
22
|
# Use parameter expansion (not `dirname`) so the PATH-restricted gh-missing test
|
|
@@ -30,164 +34,9 @@ ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
|
30
34
|
|
|
31
35
|
HOLD_REASONS=""
|
|
32
36
|
|
|
33
|
-
# #240:
|
|
34
|
-
# without
|
|
35
|
-
#
|
|
36
|
-
# lookup (skip the file read entirely)
|
|
37
|
-
# SDLC_DRY_RUN_GIT_STATE=rebase|merge|cherry-pick — simulates an in-flight
|
|
38
|
-
# git operation
|
|
39
|
-
# When set, dry-run values short-circuit the real-state checks below. The
|
|
40
|
-
# hook still emits the same HOLD/silent decision so consumers can smoke-test
|
|
41
|
-
# every code path. No filesystem writes — purely read-only simulation.
|
|
42
|
-
|
|
43
|
-
# Check 1: Codex review mid-cycle
|
|
44
|
-
# Self-heal paths (ordered by preference):
|
|
45
|
-
# (a) #209: handoff has pr_number + gh reports PR MERGED → implicit CERTIFIED (silent)
|
|
46
|
-
# (c) #257: handoff has no pr_number BUT every SHA cited in fixes_applied[]
|
|
47
|
-
# is in HEAD's ancestry AND .reviews/latest-review.md contains CERTIFIED
|
|
48
|
-
# (without "NOT CERTIFIED") → implicit CERTIFIED (silent). Catches the
|
|
49
|
-
# solo-developer pattern: write fixes, commit them, run targeted
|
|
50
|
-
# recheck, see CERTIFIED in latest-review.md, ship — and forget to
|
|
51
|
-
# update handoff.json status. The visible signals (commits landed +
|
|
52
|
-
# review file) already say "done" so blocking is high false-positive.
|
|
53
|
-
# (b) #229: handoff has no pr_number, no SHA-ancestry heal, but mtime >
|
|
54
|
-
# SDLC_HANDOFF_STALE_DAYS days → implicit CERTIFIED with WARN
|
|
55
|
-
# (forgotten artifact; blocking forever is worse UX). Default: 14 days.
|
|
56
|
-
HANDOFF="$ROOT/.reviews/handoff.json"
|
|
57
|
-
# Validate SDLC_HANDOFF_STALE_DAYS as non-negative integer. Anything else
|
|
58
|
-
# (empty, "foo", "-3", "10.5") silently falls back to 14 — we don't want a
|
|
59
|
-
# typo in the user's env to leak a bash arithmetic error to stderr every
|
|
60
|
-
# time the hook runs (caught by Codex P2 review of PR #227).
|
|
61
|
-
STALE_DAYS_RAW="${SDLC_HANDOFF_STALE_DAYS:-14}"
|
|
62
|
-
case "$STALE_DAYS_RAW" in
|
|
63
|
-
''|*[!0-9]*) STALE_DAYS=14 ;;
|
|
64
|
-
*) STALE_DAYS="$STALE_DAYS_RAW" ;;
|
|
65
|
-
esac
|
|
66
|
-
STALE_WARN=""
|
|
67
|
-
# #240: dry-run override skips the real handoff.json read.
|
|
68
|
-
if [ -n "${SDLC_DRY_RUN_HANDOFF_STATUS:-}" ]; then
|
|
69
|
-
STATUS="$SDLC_DRY_RUN_HANDOFF_STATUS"
|
|
70
|
-
case "$STATUS" in
|
|
71
|
-
PENDING_REVIEW|PENDING_RECHECK)
|
|
72
|
-
HOLD_REASONS="${HOLD_REASONS} - Codex review is ${STATUS}. Round-1 evidence lives in this context — compacting now loses what round-2 needs to re-verify.
|
|
73
|
-
Resolve: wait for CERTIFIED (or escalate) before /compact."$'\n'
|
|
74
|
-
;;
|
|
75
|
-
esac
|
|
76
|
-
elif [ -f "$HANDOFF" ]; then
|
|
77
|
-
STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$HANDOFF" 2>/dev/null | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
|
|
78
|
-
case "$STATUS" in
|
|
79
|
-
PENDING_REVIEW|PENDING_RECHECK)
|
|
80
|
-
PR_NUMBER=$(grep -o '"pr_number"[[:space:]]*:[[:space:]]*[0-9][0-9]*' "$HANDOFF" 2>/dev/null | head -1 | grep -o '[0-9][0-9]*$')
|
|
81
|
-
HEALED=0
|
|
82
|
-
if [ -n "$PR_NUMBER" ]; then
|
|
83
|
-
# Path (a): PR-linked self-heal (#209). Applies regardless of mtime —
|
|
84
|
-
# an OPEN PR with old mtime is still a live review.
|
|
85
|
-
if command -v gh >/dev/null 2>&1; then
|
|
86
|
-
PR_STATE=$(gh pr view "$PR_NUMBER" --json state --jq .state 2>/dev/null)
|
|
87
|
-
[ "$PR_STATE" = "MERGED" ] && HEALED=1
|
|
88
|
-
fi
|
|
89
|
-
else
|
|
90
|
-
# Path (c) #257: SHA-ancestry self-heal. Look for git SHAs cited
|
|
91
|
-
# in fixes_applied[]; if every cited SHA is reachable from HEAD
|
|
92
|
-
# AND .reviews/latest-review.md says CERTIFIED, the review IS
|
|
93
|
-
# closed, the user just forgot to bump status. Silent heal.
|
|
94
|
-
REVIEW_MD="$ROOT/.reviews/latest-review.md"
|
|
95
|
-
if [ -f "$REVIEW_MD" ] \
|
|
96
|
-
&& grep -qE '\bCERTIFIED\b' "$REVIEW_MD" 2>/dev/null \
|
|
97
|
-
&& ! grep -qE '\bNOT CERTIFIED\b' "$REVIEW_MD" 2>/dev/null; then
|
|
98
|
-
# Extract the fixes_applied[] block via bracket-depth
|
|
99
|
-
# tracking — naive `/\]/` matching breaks on `]` inside
|
|
100
|
-
# string literals (e.g. "[x] FIXED in <sha>" markdown
|
|
101
|
-
# checkboxes), which would let phantom SHAs after the
|
|
102
|
-
# broken-early bracket leak past path (c) and false-heal.
|
|
103
|
-
# Codex P1 round 1.
|
|
104
|
-
FIXES_BLOCK=$(awk '
|
|
105
|
-
BEGIN { in_block = 0; depth = 0; started = 0 }
|
|
106
|
-
/"fixes_applied"/ { in_block = 1 }
|
|
107
|
-
in_block {
|
|
108
|
-
print
|
|
109
|
-
in_string = 0
|
|
110
|
-
escaped = 0
|
|
111
|
-
for (i = 1; i <= length($0); i++) {
|
|
112
|
-
c = substr($0, i, 1)
|
|
113
|
-
# Honor JSON backslash escapes: \" inside a
|
|
114
|
-
# string is a literal quote, NOT a string
|
|
115
|
-
# terminator. Without this, a fixes_applied
|
|
116
|
-
# entry containing `\"]` falsely flips the
|
|
117
|
-
# in_string flag and exits the array early —
|
|
118
|
-
# letting later phantom SHAs leak past path
|
|
119
|
-
# (c) and false-heal (Codex round 2 P1).
|
|
120
|
-
if (escaped) { escaped = 0; continue }
|
|
121
|
-
if (c == "\\") { escaped = 1; continue }
|
|
122
|
-
if (c == "\"") { in_string = !in_string; continue }
|
|
123
|
-
if (in_string) continue
|
|
124
|
-
if (c == "[") { depth++; started = 1 }
|
|
125
|
-
else if (c == "]") { depth-- }
|
|
126
|
-
}
|
|
127
|
-
if (started && depth <= 0) in_block = 0
|
|
128
|
-
}
|
|
129
|
-
' "$HANDOFF" 2>/dev/null)
|
|
130
|
-
if [ -n "$FIXES_BLOCK" ] && [ -d "$ROOT/.git" ]; then
|
|
131
|
-
# Strip UUIDs (8-4-4-4-12 hex pattern) BEFORE extracting
|
|
132
|
-
# SHA candidates. UUIDs have a fixed shape; their hex
|
|
133
|
-
# segments would otherwise match \b[0-9a-f]{7,40}\b and
|
|
134
|
-
# fail the ancestry check, false-blocking certified
|
|
135
|
-
# reviews that cite UUIDs in fixes_applied (mission
|
|
136
|
-
# UUIDs, Linear/Jira ticket IDs, etc.). Codex P2 round 1.
|
|
137
|
-
# POSIX-compatible: no `\b` (BSD sed doesn't support it).
|
|
138
|
-
# The hyphenated 8-4-4-4-12 shape is specific enough
|
|
139
|
-
# that false-stripping a real SHA is implausible.
|
|
140
|
-
CLEANED=$(echo "$FIXES_BLOCK" | sed -E 's/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}//g')
|
|
141
|
-
SHAS=$(echo "$CLEANED" | grep -oE '\b[0-9a-f]{7,40}\b' | sort -u)
|
|
142
|
-
if [ -n "$SHAS" ]; then
|
|
143
|
-
# Every cited SHA must be reachable from HEAD —
|
|
144
|
-
# phantom SHAs (e.g. typos, references to other
|
|
145
|
-
# repos) correctly fail ancestry and block the heal.
|
|
146
|
-
ALL_IN_HEAD=1
|
|
147
|
-
for sha in $SHAS; do
|
|
148
|
-
if ! git -C "$ROOT" merge-base --is-ancestor "$sha" HEAD 2>/dev/null; then
|
|
149
|
-
ALL_IN_HEAD=0
|
|
150
|
-
break
|
|
151
|
-
fi
|
|
152
|
-
done
|
|
153
|
-
[ "$ALL_IN_HEAD" -eq 1 ] && HEALED=1
|
|
154
|
-
fi
|
|
155
|
-
fi
|
|
156
|
-
fi
|
|
157
|
-
# Path (b): stale-handoff auto-expire (#229). Only when no pr_number
|
|
158
|
-
# AND path (c) didn't already heal. We must not short-circuit
|
|
159
|
-
# PR-linked reviews.
|
|
160
|
-
if [ "$HEALED" -ne 1 ]; then
|
|
161
|
-
# Try GNU stat first (Linux: `-c %Y` gives mtime, BSD stat errors out
|
|
162
|
-
# so `||` fires). Then BSD stat (macOS: `-f %m` gives mtime). The
|
|
163
|
-
# reverse order fails on Linux because `stat -f` on GNU means
|
|
164
|
-
# `--file-system` and dumps filesystem info to stdout (non-error).
|
|
165
|
-
MTIME=$(stat -c %Y "$HANDOFF" 2>/dev/null || stat -f %m "$HANDOFF" 2>/dev/null)
|
|
166
|
-
# Numeric guard: if stat fails both flavors or returns junk, skip
|
|
167
|
-
# the stale-check entirely and fall through to HOLD (safe default).
|
|
168
|
-
case "$MTIME" in
|
|
169
|
-
''|*[!0-9]*) ;;
|
|
170
|
-
*)
|
|
171
|
-
NOW=$(date +%s)
|
|
172
|
-
AGE_DAYS=$(( (NOW - MTIME) / 86400 ))
|
|
173
|
-
if [ "$AGE_DAYS" -ge "$STALE_DAYS" ]; then
|
|
174
|
-
HEALED=1
|
|
175
|
-
STALE_WARN="WARN: handoff.json is ${STATUS} and ${AGE_DAYS}d old with no pr_number — treating as stale CERTIFIED (override: set SDLC_HANDOFF_STALE_DAYS or close out the review)."
|
|
176
|
-
fi
|
|
177
|
-
;;
|
|
178
|
-
esac
|
|
179
|
-
fi
|
|
180
|
-
fi
|
|
181
|
-
if [ "$HEALED" -ne 1 ]; then
|
|
182
|
-
HOLD_REASONS="${HOLD_REASONS} - Codex review is ${STATUS}. Round-1 evidence lives in this context — compacting now loses what round-2 needs to re-verify.
|
|
183
|
-
Resolve: wait for CERTIFIED (or escalate) before /compact."$'\n'
|
|
184
|
-
fi
|
|
185
|
-
;;
|
|
186
|
-
esac
|
|
187
|
-
fi
|
|
188
|
-
|
|
189
|
-
# Check 2: in-progress git operation
|
|
190
|
-
# #240: dry-run override simulates a git op without needing a real .git/.
|
|
37
|
+
# #240: SDLC_DRY_RUN_GIT_STATE=rebase|merge|cherry-pick simulates an
|
|
38
|
+
# in-flight git operation without needing a real .git/ state, so consumers
|
|
39
|
+
# can smoke-test every code path (read-only, no writes).
|
|
191
40
|
GITDIR="$ROOT/.git"
|
|
192
41
|
# Step 1: when dry-run var matches a known scenario, simulate it.
|
|
193
42
|
# Otherwise (unset, empty, or unknown value) fall through to the real
|
|
@@ -241,16 +90,12 @@ fi
|
|
|
241
90
|
|
|
242
91
|
if [ -n "$HOLD_REASONS" ]; then
|
|
243
92
|
{
|
|
244
|
-
echo "HOLD: manual /compact
|
|
93
|
+
echo "HOLD: manual /compact mid-git-operation."
|
|
245
94
|
echo ""
|
|
246
95
|
echo "$HOLD_REASONS"
|
|
247
|
-
echo "Natural seams: commit boundary, Codex CERTIFIED, PR merge, ROADMAP item DONE."
|
|
248
96
|
echo "Override: resolve the blocker above, or temporarily disable this hook in .claude/settings.json."
|
|
249
97
|
} >&2
|
|
250
98
|
exit 2
|
|
251
99
|
fi
|
|
252
100
|
|
|
253
|
-
# Stale-handoff unblock: emit a one-line WARN so the user knows the hook
|
|
254
|
-
# self-healed over an abandoned PENDING artifact (but still allow /compact).
|
|
255
|
-
[ -n "$STALE_WARN" ] && echo "$STALE_WARN" >&2
|
|
256
101
|
exit 0
|
|
@@ -35,19 +35,12 @@ else
|
|
|
35
35
|
exit 0
|
|
36
36
|
fi
|
|
37
37
|
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
EFFORT_CACHE_DIR="${SDLC_WIZARD_CACHE_DIR:-$HOME/.cache/sdlc-wizard}"
|
|
44
|
-
EFFORT_SIGNALS="$EFFORT_CACHE_DIR/effort-signals.log"
|
|
45
|
-
PROMPT_TEXT=""
|
|
38
|
+
# #236(b): the ROADMAP #195 effort auto-bump detector that used to live here
|
|
39
|
+
# (phrase-matching low-confidence signals, loud '/effort xhigh' nudge after
|
|
40
|
+
# ≥2 in 30 min) was removed — never fired in ~2 months of live use, the
|
|
41
|
+
# largest unproven component in this file. SESSION_ID is still needed below
|
|
42
|
+
# for the BASELINE fires-once sentinel, so stdin is still read for it.
|
|
46
43
|
SESSION_ID=""
|
|
47
|
-
# Read stdin once regardless of jq availability — session_id extraction
|
|
48
|
-
# is jq-independent (Codex round 1 P1: BASELINE gate failed when jq was
|
|
49
|
-
# missing or broken). Prompt extraction still needs jq because prompt
|
|
50
|
-
# content can contain arbitrary multi-line text + escapes.
|
|
51
44
|
if [ ! -t 0 ]; then
|
|
52
45
|
STDIN_JSON=$(cat)
|
|
53
46
|
if [ -n "$STDIN_JSON" ]; then
|
|
@@ -59,57 +52,6 @@ if [ ! -t 0 ]; then
|
|
|
59
52
|
| grep -o '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
60
53
|
| head -1 \
|
|
61
54
|
| sed 's/.*"\([^"]*\)"$/\1/')
|
|
62
|
-
if command -v jq > /dev/null 2>&1; then
|
|
63
|
-
PROMPT_TEXT=$(printf '%s' "$STDIN_JSON" | jq -r '.prompt // empty' 2>/dev/null) || PROMPT_TEXT=""
|
|
64
|
-
fi
|
|
65
|
-
fi
|
|
66
|
-
fi
|
|
67
|
-
if [ -n "$PROMPT_TEXT" ]; then
|
|
68
|
-
LOWER=$(printf '%s' "$PROMPT_TEXT" | tr '[:upper:]' '[:lower:]')
|
|
69
|
-
SIGNAL_REASON=""
|
|
70
|
-
# Every trigger requires first-person ownership or a structured-label
|
|
71
|
-
# form, so educational/quoted mentions ("How do I name a low confidence
|
|
72
|
-
# badge?", "What does 'failed again' mean?") don't fire.
|
|
73
|
-
case "$LOWER" in
|
|
74
|
-
*"i'm stuck"*|*"i am stuck"*|*"im stuck"*|\
|
|
75
|
-
*"i'm confused"*|*"i am confused"*|*"im confused"*|\
|
|
76
|
-
*"i tried twice"*|*"i've tried twice"*|*"ive tried twice"*|\
|
|
77
|
-
*"i can't figure"*|*"i cant figure"*|\
|
|
78
|
-
*"i'm not sure why"*|*"i am not sure why"*|*"im not sure why"*|\
|
|
79
|
-
*"my confidence is low"*|*"my confidence: low"*|*"confidence: low"*|\
|
|
80
|
-
*"it's still failing"*|*"its still failing"*|\
|
|
81
|
-
*"it keeps failing"*|*"this keeps failing"*|\
|
|
82
|
-
*"it failed again"*|*"this failed again"*|\
|
|
83
|
-
*"failed twice"*|*"failed 2x"*)
|
|
84
|
-
SIGNAL_REASON="low"
|
|
85
|
-
;;
|
|
86
|
-
esac
|
|
87
|
-
if [ -n "$SIGNAL_REASON" ]; then
|
|
88
|
-
# Group the write so redirection errors (e.g., unwritable HOME,
|
|
89
|
-
# cache-dir-is-a-file) land on /dev/null instead of leaking to stderr.
|
|
90
|
-
{
|
|
91
|
-
if mkdir -p "$EFFORT_CACHE_DIR" && [ -d "$EFFORT_CACHE_DIR" ]; then
|
|
92
|
-
# Prune entries older than 1h on every write to cap log size.
|
|
93
|
-
if [ -f "$EFFORT_SIGNALS" ]; then
|
|
94
|
-
PRUNE_THRESH=$(( $(date +%s) - 3600 ))
|
|
95
|
-
awk -v t="$PRUNE_THRESH" '$1+0 >= t' "$EFFORT_SIGNALS" > "${EFFORT_SIGNALS}.tmp" \
|
|
96
|
-
&& mv "${EFFORT_SIGNALS}.tmp" "$EFFORT_SIGNALS"
|
|
97
|
-
fi
|
|
98
|
-
printf '%s\t%s\n' "$(date +%s)" "$SIGNAL_REASON" >> "$EFFORT_SIGNALS"
|
|
99
|
-
fi
|
|
100
|
-
} 2>/dev/null || true
|
|
101
|
-
fi
|
|
102
|
-
fi
|
|
103
|
-
if [ -f "$EFFORT_SIGNALS" ]; then
|
|
104
|
-
NOW=$(date +%s)
|
|
105
|
-
THRESH=$(( NOW - 1800 ))
|
|
106
|
-
RECENT=$(awk -v t="$THRESH" '$1+0 >= t' "$EFFORT_SIGNALS" 2>/dev/null | wc -l | tr -d ' ')
|
|
107
|
-
if [ "${RECENT:-0}" -ge 2 ]; then
|
|
108
|
-
echo ""
|
|
109
|
-
echo "!! EFFORT BUMP REQUIRED: ${RECENT} low-confidence signals in last 30 min !!"
|
|
110
|
-
echo " Run /effort xhigh NOW — spinning at 'high' after confidence drops wastes budget."
|
|
111
|
-
echo " (Auto-enforcement of the SDLC confidence table. ROADMAP #195.)"
|
|
112
|
-
echo ""
|
|
113
55
|
fi
|
|
114
56
|
fi
|
|
115
57
|
|
|
@@ -55,7 +55,22 @@ fi
|
|
|
55
55
|
# slash BEFORE "src", so a cwd-relative file_path like "src/app.js" (no
|
|
56
56
|
# leading slash) never matched and the whole gate silently no-op'd. Second
|
|
57
57
|
# clause catches the relative form.
|
|
58
|
-
|
|
58
|
+
# #236(b): SDLC_TDD_SRC_PATTERN overrides the gated path(s) via env var (set
|
|
59
|
+
# it in the hook's "command" string in .claude/settings.json) instead of
|
|
60
|
+
# editing this shared/distributed script — a "|"-separated list of
|
|
61
|
+
# substrings, e.g. "hooks/|cli/". Falls back to the generic /src/ pattern
|
|
62
|
+
# when unset, so every other install is unaffected.
|
|
63
|
+
SRC_MATCH=0
|
|
64
|
+
if [ -n "${SDLC_TDD_SRC_PATTERN:-}" ]; then
|
|
65
|
+
IFS='|' read -ra _tdd_patterns <<< "$SDLC_TDD_SRC_PATTERN"
|
|
66
|
+
for _p in "${_tdd_patterns[@]}"; do
|
|
67
|
+
[[ "$FILE_PATH" == *"$_p"* ]] && SRC_MATCH=1 && break
|
|
68
|
+
done
|
|
69
|
+
else
|
|
70
|
+
[[ "$FILE_PATH" == *"/src/"* || "$FILE_PATH" == "src/"* ]] && SRC_MATCH=1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [ "$SRC_MATCH" -eq 1 ]; then
|
|
59
74
|
# #436 gate: block implementation-first edits when no test file has been
|
|
60
75
|
# touched yet this session. Degrades to allow without session_id.
|
|
61
76
|
if [ -n "$SESSION_ID" ]; then
|
package/package.json
CHANGED
package/skills/feedback/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: feedback
|
|
3
3
|
description: Submit feedback, bug reports, feature requests, or share SDLC patterns you've discovered. Privacy-first — always asks before scanning.
|
|
4
|
-
argument-hint: [optional: bug | feature | pattern | improvement]
|
|
4
|
+
argument-hint: "[optional: bug | feature | pattern | improvement]"
|
|
5
5
|
effort: medium
|
|
6
6
|
---
|
|
7
7
|
# Feedback — Community Contribution Loop
|
package/skills/sdlc/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sdlc
|
|
3
3
|
description: Full SDLC workflow for implementing features, fixing bugs, refactoring code, testing, releasing, publishing, and deploying. Use this skill when implementing, fixing, refactoring, testing, adding features, building new code, or releasing/publishing/deploying.
|
|
4
|
-
argument-hint: [task description]
|
|
4
|
+
argument-hint: "[task description]"
|
|
5
5
|
---
|
|
6
6
|
# SDLC Skill - Full Development Workflow
|
|
7
7
|
|
|
@@ -119,7 +119,7 @@ Native `/goal <condition>` (**v2.1.143+**). Haiku evaluator re-checks transcript
|
|
|
119
119
|
|
|
120
120
|
## Recommended Model
|
|
121
121
|
|
|
122
|
-
**Recommended: Sonnet 5 `high`→`xhigh`** — beats Opus 4.6,
|
|
122
|
+
**Recommended: Sonnet 5 `medium`→`high`→`xhigh`** — beats Opus 4.6 on benchmarks, generally lower quota (savings narrow at high/xhigh). Escalate to **Opus 4.8 `xhigh`** when stuck. **Opus 4.6 `max`** valid for consistency. See `AI_SETUP_LANES.md`.
|
|
123
123
|
|
|
124
124
|
**Effort is model-aware, not blanket `max`** — `max` overthinks on Sonnet 5/Opus 4.8. Set via `/effort` per session, not a shell-rc env var (overrides post-switch — see SDLC.md). `/model` persists; picker `s` does not.
|
|
125
125
|
|
|
@@ -137,7 +137,7 @@ The loop goes back to PLANNING, not TDD RED. Run `/code-review`; issues at confi
|
|
|
137
137
|
|
|
138
138
|
## Cross-Model Review (REQUIRED for High-Stakes)
|
|
139
139
|
|
|
140
|
-
**When to run:** high-stakes changes (auth, payments, data), releases/publishes, complex refactors. **When to skip (log justification):** trivial, hotfixes, risk < review cost. **Prerequisites:** Codex CLI + OpenAI API key. **Reviewer:** `gpt-5.
|
|
140
|
+
**When to run:** high-stakes changes (auth, payments, data), releases/publishes, complex refactors. **When to skip (log justification):** trivial, hotfixes, risk < review cost. **Prerequisites:** Codex CLI + OpenAI API key. **Reviewer:** `gpt-5.6-sol` xhigh — adversarial diversity.
|
|
141
141
|
|
|
142
142
|
PROTOCOL is universal across domains; only `review_instructions` and `verification_checklist` change.
|
|
143
143
|
|
|
@@ -148,8 +148,6 @@ PROTOCOL is universal across domains; only `review_instructions` and `verificati
|
|
|
148
148
|
|
|
149
149
|
**Convergence:** 2 rounds sweet spot, 3 max, escalate after — except large migrations: judge by finding trend, not count.
|
|
150
150
|
|
|
151
|
-
**Enforcement:** `hooks/goal-confidence-check.sh` warns when `/goal` skips the 95%-confidence or DLC-binding gates (#360).
|
|
152
|
-
|
|
153
151
|
**Multi-reviewer:** respond to each independently. **Non-code domains:** add `"audience"`/`"stakes"` keys.
|
|
154
152
|
|
|
155
153
|
### Release Review Focus
|
package/skills/setup/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-wizard
|
|
3
3
|
description: Setup wizard — scans codebase, builds confidence per data point, only asks what it can't figure out, generates SDLC files. Use for first-time setup or re-running setup.
|
|
4
|
-
argument-hint: [optional: regenerate | verify-only]
|
|
4
|
+
argument-hint: "[optional: regenerate | verify-only]"
|
|
5
5
|
effort: high
|
|
6
6
|
---
|
|
7
7
|
# Setup Wizard - Confidence-Driven Project Configuration
|
|
@@ -245,7 +245,7 @@ The output is JSON: `{ tier: "simple" | "complex", score, signals }`. Use the re
|
|
|
245
245
|
> How do you want to configure the model for this repo?
|
|
246
246
|
>
|
|
247
247
|
> - **[N] No pin (default):** Auto-mode. CC picks model per turn. Simplest, no advisor.
|
|
248
|
-
> - **[s] Sonnet 5 + Fable** *(Setup A — recommended if you want a pin):* Pins `model: "sonnet"`, `advisorModel: "fable"`. Native 1M context, no `[1m]` suffix needed. Beats Opus 4.6 on every coding benchmark
|
|
248
|
+
> - **[s] Sonnet 5 + Fable** *(Setup A — recommended if you want a pin):* Pins `model: "sonnet"`, `advisorModel: "fable"`. Native 1M context, no `[1m]` suffix needed. Beats Opus 4.6 on every coding benchmark, generally lower Max quota. Effort: `medium`, escalate `high` → `xhigh` for hard tasks.
|
|
249
249
|
> - **[o] OpusPlan Hybrid** *(Setup C — cost-conscious, still want Opus reasoning):* Pins `model: "opusplan"`. Opus 4.8 plans (Shift+Tab), Sonnet 5 executes. Max-bundled. No API credit drain (#390).
|
|
250
250
|
> - **[b] Opus 4.6 Stability** *(Setup B — legacy flagship, proven consistency for high-stakes/complex repos):* Pins `model: "claude-opus-4-6"`. Opus 4.6 max everywhere. Max-bundled (auto-upgrades to 1M on Max plans).
|
|
251
251
|
>
|
|
@@ -259,14 +259,14 @@ The output is JSON: `{ tier: "simple" | "complex", score, signals }`. Use the re
|
|
|
259
259
|
{
|
|
260
260
|
"model": "sonnet",
|
|
261
261
|
"advisorModel": "fable",
|
|
262
|
-
"effortLevel": "
|
|
262
|
+
"effortLevel": "medium",
|
|
263
263
|
"env": {
|
|
264
264
|
"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "75"
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
```
|
|
268
268
|
|
|
269
|
-
Tell the user: "Sonnet 5 + Fable — the wizard's recommended pin (Setup A). Effort
|
|
269
|
+
Tell the user: "Sonnet 5 + Fable — the wizard's recommended pin (Setup A). Effort: `medium`, escalate `/effort high` → `xhigh` for hard tasks. Requires CC v2.1.170+ — run `! claude update` if needed."
|
|
270
270
|
|
|
271
271
|
**If the user answers `o` (opusplan):** Edit `.claude/settings.json` and add:
|
|
272
272
|
|
package/skills/update/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: update-wizard
|
|
3
3
|
description: Smart update for SDLC wizard — shows changelog, compares files, lets you selectively adopt changes while preserving customizations.
|
|
4
|
-
argument-hint: [optional: check-only | force-all]
|
|
4
|
+
argument-hint: "[optional: check-only | force-all]"
|
|
5
5
|
effort: high
|
|
6
6
|
---
|
|
7
7
|
# Update Wizard - Smart SDLC Update
|
|
@@ -95,16 +95,15 @@ Parse CHANGELOG entries between the user's installed version and the resolved la
|
|
|
95
95
|
|
|
96
96
|
```
|
|
97
97
|
Installed: 1.42.0
|
|
98
|
-
Latest: 1.
|
|
98
|
+
Latest: 1.87.0
|
|
99
99
|
|
|
100
100
|
What changed:
|
|
101
|
+
- [1.87.0] First external contribution (@thejesh23, #444): argument-hint frontmatter quoted so Copilot CLI ≥1.0.65 loads skills, plus regression test; GPT-5.6 Sol reviewer sweep; Sonnet 5 default effort → medium (unbacked 5x quota claim removed, hook floor matched).
|
|
101
102
|
- [1.86.0] Fix #437: codex-gate-check.sh now blocks stale certifications — a CERTIFIED handoff.json no longer sails through forever; it records commit_sha at cert time and blocks once HEAD moves past it without a re-cert.
|
|
102
103
|
- [1.85.0] Post-ship retrospective: CI Feedback Loop synced to SKILL.md's stronger version, CERTIFIED≠CI lesson, Policy Migration Inventory checklist, stale round-count correction.
|
|
103
104
|
- [1.84.0] Hook enforcement fix: cross-model review gate + TDD RED gate now actually block (#436); model-aware effort docs replace blanket max recommendation.
|
|
104
105
|
- [1.83.0] Model config batch: multi-model hook recommendation (#403), global [1m] pin detection (#391), version race fix (#405), effort config check (#384).
|
|
105
106
|
- [1.82.0] Usage diagnostics: fix /usage row, Reading Usage Signals guide, advisor fallback procedure, Fable effort guidance, autocompact cross-reference.
|
|
106
|
-
- [1.81.0] Native `advisorModel` support: Setup A gets Fable advisor, Setup B gets Opus advisor. Replaces manual subagent spawning. Requires CC v2.1.170+.
|
|
107
|
-
- [1.80.0] Flip default: Opus 4.6 max becomes recommended flagship; Opus 4.8 demoted to opt-in `[l] Latest` tier.
|
|
108
107
|
- [1.75.1] release-workflow fix — Node 22 → 24 (ships npm 11.x), dropped flaky `npm install -g` self-upgrade (hit MODULE_NOT_FOUND on v1.75.0 publish). Explicit npm-version guard.
|
|
109
108
|
- [1.75.0] npm Trusted Publishing — `release.yml` swapped from `NPM_TOKEN` to OIDC. No more token rotation. Requires one-time publisher config on the npm package page.
|
|
110
109
|
- [1.74.0] v1.43 salvage: #338 precedence preamble; #235ab `/insights`; codex `< /dev/null` stdin-hang fix; test env-isolation.
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# /goal SDLC discipline gate (ROADMAP #360).
|
|
3
|
-
#
|
|
4
|
-
# UserPromptSubmit hook. When the user invokes `/goal <condition>`, scan the
|
|
5
|
-
# prior assistant text for a HIGH 95% confidence statement AND check the
|
|
6
|
-
# condition for a DLC binding (`/sdlc`, `/gdlc`, `/ldlc`, etc.). Emit loud
|
|
7
|
-
# warnings on either gap so the SDLC-discipline gap surfaces BEFORE the goal
|
|
8
|
-
# evaluator starts rubber-stamping flailing as progress.
|
|
9
|
-
#
|
|
10
|
-
# PR #355 (v1.77.0) added the guidance text in skills/sdlc/SKILL.md. This
|
|
11
|
-
# hook is the enforcement layer per #360. Non-blocking soft nudge — same
|
|
12
|
-
# pattern as model-effort-check.sh.
|
|
13
|
-
|
|
14
|
-
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
-
source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
16
|
-
|
|
17
|
-
# Plugin + project copies both register this hook → plugin yields (#236).
|
|
18
|
-
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
|
|
19
|
-
|
|
20
|
-
# Must be invoked via hook (stdin JSON), not interactively.
|
|
21
|
-
[ -t 0 ] && exit 0
|
|
22
|
-
STDIN_JSON=$(cat)
|
|
23
|
-
[ -z "$STDIN_JSON" ] && exit 0
|
|
24
|
-
command -v jq > /dev/null 2>&1 || exit 0
|
|
25
|
-
|
|
26
|
-
PROMPT=$(printf '%s' "$STDIN_JSON" | jq -r '.prompt // empty' 2>/dev/null) || exit 0
|
|
27
|
-
[ -z "$PROMPT" ] && exit 0
|
|
28
|
-
|
|
29
|
-
# Only act on `/goal <condition>` invocations. `/goal` alone (status) and
|
|
30
|
-
# `/goal clear` (reset) must stay silent — those aren't discipline events.
|
|
31
|
-
case "$PROMPT" in
|
|
32
|
-
"/goal") exit 0 ;;
|
|
33
|
-
"/goal "[[:space:]]*) exit 0 ;;
|
|
34
|
-
"/goal clear") exit 0 ;;
|
|
35
|
-
"/goal clear "*) exit 0 ;;
|
|
36
|
-
"/goal "*) ;;
|
|
37
|
-
*) exit 0 ;;
|
|
38
|
-
esac
|
|
39
|
-
|
|
40
|
-
CONDITION="${PROMPT#/goal }"
|
|
41
|
-
|
|
42
|
-
# === Confidence gate ===
|
|
43
|
-
# Read transcript_path, slurp JSONL, find last assistant message with text
|
|
44
|
-
# content, scan for HIGH-95% confidence pattern. Silent on missing/unreadable
|
|
45
|
-
# transcript — better to under-warn than crash a soft nudge.
|
|
46
|
-
TRANSCRIPT_PATH=$(printf '%s' "$STDIN_JSON" | jq -r '.transcript_path // empty' 2>/dev/null) || TRANSCRIPT_PATH=""
|
|
47
|
-
HAS_CONFIDENCE=0
|
|
48
|
-
if [ -n "$TRANSCRIPT_PATH" ] && [ -r "$TRANSCRIPT_PATH" ]; then
|
|
49
|
-
LAST_ASSISTANT_TEXT=$(jq -rs '
|
|
50
|
-
[.[] | select(.type == "assistant")]
|
|
51
|
-
| last
|
|
52
|
-
| if . == null then ""
|
|
53
|
-
else (.message.content // []) | map(select(.type == "text") | .text) | join("\n")
|
|
54
|
-
end
|
|
55
|
-
' "$TRANSCRIPT_PATH" 2>/dev/null) || LAST_ASSISTANT_TEXT=""
|
|
56
|
-
if printf '%s' "$LAST_ASSISTANT_TEXT" | grep -qiE 'HIGH \(?95%|confidence:?[[:space:]]+HIGH|HIGH[[:space:]]+95%|95%[[:space:]]+confidence'; then
|
|
57
|
-
HAS_CONFIDENCE=1
|
|
58
|
-
fi
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
if [ "$HAS_CONFIDENCE" -eq 0 ]; then
|
|
62
|
-
echo ""
|
|
63
|
-
echo "!! /GOAL CONFIDENCE GATE: prior turn did not state HIGH 95% confidence !!"
|
|
64
|
-
echo " The /goal Haiku evaluator rubber-stamps flailing as progress below 95%."
|
|
65
|
-
echo " Recommendation: /goal clear → do research → state HIGH 95% confidence → re-issue /goal."
|
|
66
|
-
echo " (Source: skills/sdlc/SKILL.md Long-Running Goals section, ROADMAP #360.)"
|
|
67
|
-
echo ""
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
# === DLC binding gate ===
|
|
71
|
-
# Condition MUST name a DLC (`/sdlc`, `/gdlc`, `/ldlc`, etc.) so the
|
|
72
|
-
# evaluator anchors on "doing it right" not just "doing it".
|
|
73
|
-
if ! printf '%s' "$CONDITION" | grep -qiE '/[a-z]+dlc'; then
|
|
74
|
-
echo ""
|
|
75
|
-
echo "!! /GOAL DLC-BINDING GATE: condition does not name a DLC (/sdlc, /gdlc, /ldlc) !!"
|
|
76
|
-
echo " The evaluator needs a discipline anchor to judge 'doing it right' vs flailing."
|
|
77
|
-
echo " Recommendation: rewrite condition to include 'following /sdlc' (or /gdlc/etc)."
|
|
78
|
-
echo " (Source: skills/sdlc/SKILL.md Long-Running Goals section, ROADMAP #360.)"
|
|
79
|
-
echo ""
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
exit 0
|