@benjaminthomas/spec-driven-dev 1.7.0 → 1.8.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/README.md CHANGED
@@ -97,14 +97,26 @@ words in quotes.
97
97
  **deep**, based on how much it touches and how risky it is (data, security, concurrency, public
98
98
  contracts, unclear requirements). `spec-implement` then runs each task on the model for its tier:
99
99
 
100
- | Tier | Typical task | Claude Code default |
101
- |---|---|---|
102
- | light | copy change, config value, small UI tweak following an existing pattern | `haiku` |
103
- | standard | a normal feature slice: route + service + tests | `sonnet` |
104
- | deep | migrations with backfills, auth/permissions, concurrency, cross-repo contracts | `opus` |
100
+ | Tier | Typical task | Claude Code | Codex CLI | Effort |
101
+ |---|---|---|---|---|
102
+ | light | copy change, config value, small UI tweak following an existing pattern | `haiku` | `gpt-6-luna` | low |
103
+ | standard | a normal feature slice: route + service + tests | `sonnet` | `gpt-6.1-sol` | medium |
104
+ | deep | migrations with backfills, auth/permissions, concurrency, cross-repo contracts | `opus` | `gpt-6.1-sol` | high |
105
+ | escalate | a deep task that still fails after a fix round | `fable` (asks first, as it may use usage credits) | (session model) | xhigh |
105
106
 
106
107
  - **Reviews:** each batch's review runs on at least `standard`, and on the batch's highest tier.
107
- - **Escalation:** a task that still fails after a fix round is retried one tier up.
108
+ - **Escalation:** a task that still fails after a fix round is retried one tier up. A deep task
109
+ that still fails goes to the `escalate` model.
110
+ - **Fallback:** if a model isn't available on your plan or provider, that task runs on your current
111
+ model and the report says so.
112
+ - **Where the defaults come from:** they were checked on 2026-11-06 against
113
+ [Claude Code's model docs](https://code.claude.com/docs/en/model-config) (on Bedrock, Google Cloud,
114
+ and Foundry, `sonnet`/`haiku` point to older versions),
115
+ [Anthropic's model overview](https://platform.claude.com/docs/en/about-claude/models/overview),
116
+ [Codex's config docs](https://developers.openai.com/codex/config-basic), and
117
+ [Cursor's model list](https://cursor.com/help/models-and-usage/available-models). Claude Code
118
+ uses family aliases, which always point to the newest model. Cursor's models depend on your plan,
119
+ so it uses your current model until you fill in the models you can see in its picker.
108
120
  - **Tools that run one model per session** (Cursor, Codex) don't switch silently. Before a heavier
109
121
  batch, they pause and tell you which model to switch to.
110
122
  - **Changing the models:** edit the `models:` section of `.spec-driven.yml`, for example to use a
@@ -156,7 +168,7 @@ straight away, so you can fix it before moving on. Press Enter on an empty line
156
168
  | Lint / typecheck / test / build / dev commands | `package.json` scripts and lockfile (per repo or package) | `pnpm run lint` |
157
169
  | Where specs go | (you choose) | `specs/` |
158
170
  | After you approve a spec | (you choose) | `stop` (wait at each stage) or `run-through` |
159
- | Model per task tier | written with defaults: Claude Code `haiku`/`sonnet`/`opus`, others `default` | edit `models:` later |
171
+ | Model and effort per task tier | written with the defaults above | edit `models:` / `effort:` later |
160
172
 
161
173
  **Where the file lives, by layout:**
162
174
 
@@ -563,12 +575,12 @@ skips that step rather than failing.
563
575
  | `spec-setup` | 0 · configure | 117 | 1,068 | 1 |
564
576
  | `spec-investigate` | 1 · understand | 330 | 2,794 | 1 |
565
577
  | `spec-create` | 2 · plan | 166 | 1,503 | 5 |
566
- | `spec-implement` | 3 · build | 298 | 2,375 | 3 |
578
+ | `spec-implement` | 3 · build | 303 | 2,458 | 3 |
567
579
  | `spec-verify` | 4 · prove | 155 | 1,492 | 1 |
568
580
  | `spec-checkpoint` | 5 · commit | 108 | 795 | 0 |
569
581
  | `spec-ship` | 6 · PR | 220 | 1,268 | 0 |
570
582
  | `generative-seo` | standalone | 255 | 2,209 | 7 |
571
- | **Total** | | **1,649** | **13,504** | **18** |
583
+ | **Total** | | **1,654** | **13,587** | **18** |
572
584
 
573
585
  - **8** skills: **1** setup + **6** workflow stages + **1** standalone
574
586
  - **4** tools supported natively (Claude Code, Codex CLI, Cursor, Antigravity), plus an MCP fallback
package/bin/cli.mjs CHANGED
@@ -235,22 +235,30 @@ function toYaml(c) {
235
235
  out += `tracker:\n type: ${c.tracker.type}\n key: ${y(c.tracker.key)}\n url: ${y(c.tracker.url)}\n`;
236
236
  out += `git:\n${cmds(c.git, " ")}\n`;
237
237
  out += `commands:\n${cmds(c.commands, " ")}\n dev_url: ${y(c.devUrl)}\n`;
238
- out += "models: # model per task tier (light / standard / deep); \"default\" = the session's model\n" + Object.entries(MODEL_DEFAULTS)
239
- .map(([tool, m]) => ` ${tool}:\n` + TIERS.map((t) => ` ${t}: ${m[t]}\n`).join("")).join("");
238
+ out += "models: # model per task tier; \"default\" = the session's model; escalate = last resort for repeat failures\n" + Object.entries(MODEL_DEFAULTS)
239
+ .map(([tool, m]) => ` ${tool}:\n` + MODEL_KEYS.map((t) => ` ${t}: ${m[t]}\n`).join("")).join("");
240
+ out += "effort: # effort / reasoning level per tier (Claude Code, Codex): low | medium | high | xhigh | max | default\n"
241
+ + MODEL_KEYS.map((t) => ` ${t}: ${EFFORT_DEFAULTS[t]}\n`).join("");
240
242
  out += `pipeline:\n after_approval: ${c.afterApproval || "stop"} # stop | run-through (implement → verify → checkpoint; ship always asks)\n`;
241
243
  return out + `specs_dir: ${y(c.specsDir)}\n`;
242
244
  }
243
245
 
244
246
  const LAYOUTS = ["single", "monorepo", "multi-repo"];
245
247
  const TIERS = ["light", "standard", "deep"];
246
- // Aliases, not dated model IDs, so they keep pointing at the current models. Other tools default to
247
- // the session's own model; spec-implement then tells you when to switch.
248
+ const MODEL_KEYS = [...TIERS, "escalate"]; // escalate: optional last resort when a deep task keeps failing
249
+ const EFFORTS = ["low", "medium", "high", "xhigh", "max", "default"];
250
+ // Checked against the vendors' docs on 2026-11-06 (Claude Code model-config, OpenAI Codex config,
251
+ // Cursor models page). Claude Code aliases track the newest model per family on your provider.
252
+ // Cursor's models depend on your plan, so it defaults to the session's model.
253
+ // shortcut: model names go stale; refresh these defaults (and the README table) when vendors ship new lines.
248
254
  const MODEL_DEFAULTS = {
249
- claude: { light: "haiku", standard: "sonnet", deep: "opus" },
250
- cursor: { light: "default", standard: "default", deep: "default" },
251
- codex: { light: "default", standard: "default", deep: "default" },
252
- antigravity: { light: "default", standard: "default", deep: "default" },
255
+ claude: { light: "haiku", standard: "sonnet", deep: "opus", escalate: "fable" },
256
+ codex: { light: "gpt-6-luna", standard: "gpt-6.1-sol", deep: "gpt-6.1-sol", escalate: "default" },
257
+ cursor: { light: "default", standard: "default", deep: "default", escalate: "default" },
258
+ antigravity: { light: "default", standard: "default", deep: "default", escalate: "default" },
253
259
  };
260
+ // Effort / reasoning level per tier, for tools that support it (Claude Code, Codex).
261
+ const EFFORT_DEFAULTS = { light: "low", standard: "medium", deep: "high", escalate: "xhigh" };
254
262
  const splitList = (v) => (v || "").split(",").map((x) => x.trim()).filter(Boolean);
255
263
  // Paths are stored relative to the config's folder when inside it, absolute otherwise.
256
264
  const real = (p) => { try { return fs.realpathSync(p); } catch { return p; } }; // /var vs /private/var etc.
@@ -514,7 +522,11 @@ function doctor() {
514
522
  for (const [tool, m] of Object.entries(c.models || {})) {
515
523
  if (typeof m !== "object") { problems.push(`models.${tool} must list light / standard / deep`); continue; }
516
524
  for (const t of TIERS) if (!m[t]) problems.push(`models.${tool}.${t} is missing (use "default" for the session's model)`);
517
- for (const k of Object.keys(m)) if (!TIERS.includes(k)) problems.push(`models.${tool}.${k}: unknown tier (use light, standard, deep)`);
525
+ for (const k of Object.keys(m)) if (!MODEL_KEYS.includes(k)) problems.push(`models.${tool}.${k}: unknown tier (use light, standard, deep, escalate)`);
526
+ }
527
+ for (const [k, v] of Object.entries(c.effort || {})) {
528
+ if (!MODEL_KEYS.includes(k)) problems.push(`effort.${k}: unknown tier (use light, standard, deep, escalate)`);
529
+ else if (!EFFORTS.includes(v)) problems.push(`effort.${k} "${v}" must be one of ${EFFORTS.join(", ")}`);
518
530
  }
519
531
  if (c.pipeline?.after_approval && !["stop", "run-through"].includes(c.pipeline.after_approval)) problems.push(`pipeline.after_approval "${c.pipeline.after_approval}" must be stop or run-through`);
520
532
  if (c.git?.branch_name && !/\{(ticket|slug)\}/.test(c.git.branch_name)) problems.push(`git.branch_name "${c.git.branch_name}" needs {ticket} or {slug}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benjaminthomas/spec-driven-dev",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Spec-driven AI development workflow (investigate → spec → implement → verify → ship) as Agent Skills for Claude Code, Cursor, Codex CLI and Antigravity.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -108,14 +108,17 @@ Read `references/coder-prompt-template.md` and construct each agent's prompt by
108
108
 
109
109
  The coder agents should NOT commit their changes — the orchestrator handles commits after review.
110
110
 
111
- **Pick each coder's model from the task's tier.** Read the task's `## Complexity` tier (treat a
112
- missing tier as `standard`) and look up the model in `.spec-driven.yml` → `models.<tool>.<tier>`,
113
- where `<tool>` is the host you're running in (`claude`, `codex`, `cursor`, `antigravity`). Without a
114
- `models` section, use `models.claude` defaults: `light → haiku`, `standard → sonnet`,
115
- `deep → opus`.
116
-
117
- - **Host can set a model per agent** (e.g. Claude Code's Agent tool `model` parameter): dispatch
118
- each coder with its tier's model.
111
+ **Pick each coder's model and effort from the task's tier.** Read the task's `## Complexity` tier
112
+ (treat a missing tier as `standard`), then look up `.spec-driven.yml` → `models.<tool>.<tier>` and
113
+ `effort.<tier>`, where `<tool>` is the host you're running in (`claude`, `codex`, `cursor`,
114
+ `antigravity`). Without those sections, use these defaults: Claude Code `light → haiku/low`,
115
+ `standard → sonnet/medium`, `deep → opus/high`; other hosts use the session's model.
116
+
117
+ - **Host can set a model per agent** (e.g. Claude Code's Agent tool `model` and `effort`
118
+ parameters): dispatch each coder with its tier's model and effort.
119
+ - **Model not available** (not on your plan or provider, or rejected by the host): fall back to the
120
+ session's model, say which task fell back and why, and suggest fixing `models:`. Don't stop the
121
+ batch for this.
119
122
  - **Host can't** (one model per session, as in Cursor or Codex): don't silently run deep tasks on a
120
123
  light model. Before dispatching a batch, compare its highest tier with the model you're running
121
124
  on. If the batch needs a stronger one, stop and say:
@@ -183,8 +186,10 @@ If the review returns **FAIL**:
183
186
  - **{task_content}**: the original task file for context
184
187
  4. After fix agents complete, re-run the review (Step 6)
185
188
  5. **Escalate on repeat failure.** If a task's issues survive a fix cycle, run its next fix one tier
186
- higher (`light → standard → deep`). Note the escalation in the batch report. When a task needed
187
- escalating, its tier was probably wrong, which is useful feedback for future specs.
189
+ higher (`light → standard → deep`). A `deep` task that still fails goes to `models.<tool>.escalate`
190
+ (e.g. `fable`) at `effort.escalate`, if it's set and not `default`. Ask first if that model can
191
+ bill to usage credits, as Fable can on some plans. Note every escalation in the batch report:
192
+ a task that needed escalating was probably under-rated, which is useful feedback for future specs.
188
193
 
189
194
  **Cap at 3 review cycles per batch.** If the third review still fails, stop and report to the user:
190
195
 
@@ -51,7 +51,7 @@ Copy this structure into `specs/{feature-slug}/investigation.md`.
51
51
  ## Complexity Estimate
52
52
  - Overall tier: (light / standard / deep): the tier of the hardest part of the work
53
53
  - Signals: (which of spread, new design, data, concurrency, security, public contract, ambiguity, hard to verify apply, each with its evidence)
54
- - Suggested model for planning this: (the `deep` model if the tier is deep; otherwise the session's model is fine)
54
+ - Suggested model for planning this: (`models.<tool>.deep` at `effort.deep` if the tier is deep, or the `escalate` model for very ambiguous, long-horizon work; otherwise the session's model is fine)
55
55
 
56
56
  ## Recommended Implementation Direction
57
57
  ## References
@@ -44,25 +44,36 @@ commands:
44
44
 
45
45
  # Which model runs each task tier (spec-create rates every task light / standard / deep).
46
46
  # Values are whatever your tool accepts; "default" means "whatever model the session is using".
47
- # Hosts that can pick a model per agent (Claude Code) switch automatically; others (Cursor, Codex)
48
- # tell you which model to switch to before a heavier batch.
47
+ # escalate = optional last resort when a deep task still fails review after a fix round.
48
+ # Defaults checked against vendor docs on 2026-11-06 — refresh when vendors ship new models.
49
49
  models:
50
- claude:
50
+ claude: # Claude Code aliases follow the newest model per family on your provider
51
51
  light: haiku
52
52
  standard: sonnet
53
53
  deep: opus
54
- cursor:
55
- light: default
56
- standard: default
57
- deep: default
54
+ escalate: fable # Fable: hardest/long-running work; may bill to usage credits on some plans
58
55
  codex:
56
+ light: gpt-6-luna
57
+ standard: gpt-6.1-sol
58
+ deep: gpt-6.1-sol # same model, higher reasoning effort (see effort:)
59
+ escalate: default
60
+ cursor: # depends on your Cursor plan; set models you can see in the model picker
59
61
  light: default
60
62
  standard: default
61
63
  deep: default
64
+ escalate: default
62
65
  antigravity:
63
66
  light: default
64
67
  standard: default
65
68
  deep: default
69
+ escalate: default
70
+
71
+ # Effort / reasoning level per tier, for tools that support it (Claude Code, Codex).
72
+ effort:
73
+ light: low
74
+ standard: medium
75
+ deep: high
76
+ escalate: xhigh
66
77
 
67
78
  pipeline:
68
79
  # stop — every stage waits for you (default)