its-magic 0.1.2 → 0.1.3-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/bin/postinstall.js +72 -0
  2. package/installer.py +55 -0
  3. package/package.json +1 -1
  4. package/scripts/check_intake_template_parity.py +90 -0
  5. package/template/.cursor/agents/curator.mdc +1 -0
  6. package/template/.cursor/agents/po.mdc +1 -0
  7. package/template/.cursor/agents/release.mdc +1 -0
  8. package/template/.cursor/commands/release.md +18 -0
  9. package/template/.cursor/model-catalog.local.example.cursor-only.json +9 -0
  10. package/template/.cursor/model-catalog.local.example.json +9 -0
  11. package/template/.cursor/model-catalog.local.example.level-1-easy.json +9 -0
  12. package/template/.cursor/model-catalog.local.example.level-2-complex.json +9 -0
  13. package/template/.cursor/model-catalog.local.example.level-3-mega.json +9 -0
  14. package/template/.cursor/model-catalog.local.example.level-4-super.json +9 -0
  15. package/template/.cursor/model-catalog.local.example.role-based-balanced.json +18 -0
  16. package/template/.cursor/model-catalog.local.example.role-based-highend.json +18 -0
  17. package/template/.cursor/scratchpad.local.example.md +55 -0
  18. package/template/.cursor/scratchpad.md +62 -0
  19. package/template/CHANGELOG.md +11 -0
  20. package/template/docs/engineering/runbook.md +274 -6
  21. package/template/handoffs/releases/vX.Y.Z-release-notes.md.example +21 -0
  22. package/template/scripts/check_intake_template_parity.py +90 -0
  23. package/template/scripts/dev_environment_lib.py +138 -0
  24. package/template/scripts/model_tier_lib.py +680 -0
  25. package/template/scripts/model_tier_validate.py +368 -0
  26. package/template/scripts/release-all.sh +249 -0
  27. package/template/scripts/release_changelog_backfill.py +153 -0
  28. package/template/scripts/release_changelog_lib.py +544 -0
  29. package/template/scripts/release_changelog_validate.py +134 -0
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const { spawnSync } = require("child_process");
5
+
2
6
  const M = "\x1b[1;35m";
3
7
  const C = "\x1b[1;36m";
4
8
  const Y = "\x1b[1;33m";
@@ -19,3 +23,71 @@ console.log(`${G} Installation complete!${R}`);
19
23
  console.log("");
20
24
  console.log(`${W} Run: its-magic --help${R}`);
21
25
  console.log("");
26
+
27
+ const pkgRoot = path.resolve(__dirname, "..");
28
+ const templateRoot = path.join(pkgRoot, "template");
29
+ const bootstrapScript = path.join(pkgRoot, "scripts", "dev_environment_lib.py");
30
+
31
+ function detectConsumerRepoRoot() {
32
+ let dir = process.cwd();
33
+ for (let depth = 0; depth <= 6; depth += 1) {
34
+ const scratchpad = path.join(dir, ".cursor", "scratchpad.md");
35
+ const versionSentinel = path.join(dir, "its_magic", ".its-magic-version");
36
+ if (fs.existsSync(scratchpad) || fs.existsSync(versionSentinel)) {
37
+ return dir;
38
+ }
39
+ const parent = path.dirname(dir);
40
+ if (parent === dir) {
41
+ break;
42
+ }
43
+ dir = parent;
44
+ }
45
+ return null;
46
+ }
47
+
48
+ function resolvePythonCommand() {
49
+ if (process.platform === "win32") {
50
+ return "python";
51
+ }
52
+ return "python3";
53
+ }
54
+
55
+ function runDevEnvBootstrap() {
56
+ const repoRoot = detectConsumerRepoRoot();
57
+ if (!repoRoot) {
58
+ console.log("[DEV_ENV_BOOTSTRAP_SKIP] no consumer repository detected");
59
+ return;
60
+ }
61
+ if (!fs.existsSync(bootstrapScript)) {
62
+ console.log(
63
+ "[DEV_ENV_BOOTSTRAP_ERROR] bootstrap helper missing; copy template/.cursor/dev-environment.json.example manually"
64
+ );
65
+ return;
66
+ }
67
+ const py = resolvePythonCommand();
68
+ const res = spawnSync(
69
+ py,
70
+ [
71
+ bootstrapScript,
72
+ "--bootstrap",
73
+ "--target",
74
+ repoRoot,
75
+ "--source-root",
76
+ templateRoot,
77
+ ],
78
+ { encoding: "utf-8" }
79
+ );
80
+ if (res.stdout) {
81
+ process.stdout.write(res.stdout);
82
+ }
83
+ if (res.stderr) {
84
+ process.stderr.write(res.stderr);
85
+ }
86
+ if (res.status === 1) {
87
+ console.log(
88
+ "[DEV_ENV_BOOTSTRAP_ERROR] bootstrap failed; copy template/.cursor/dev-environment.json.example to .cursor/dev-environment.json"
89
+ );
90
+ }
91
+ }
92
+
93
+ runDevEnvBootstrap();
package/installer.py CHANGED
@@ -345,6 +345,57 @@ def _load_doc_profile_lib():
345
345
  return mod
346
346
 
347
347
 
348
+ def _load_dev_environment_lib():
349
+ """Load dev_environment_lib from scripts/ adjacent to this installer."""
350
+ here = os.path.dirname(os.path.abspath(__file__))
351
+ path = os.path.join(here, "scripts", "dev_environment_lib.py")
352
+ if not os.path.isfile(path):
353
+ raise RuntimeError(
354
+ "[DEV_ENVIRONMENT_LIB_MISSING] Expected dev environment library at "
355
+ f"{path} (same directory as installer.py). "
356
+ f"Reinstall or upgrade its-magic ({REPO_URL})."
357
+ )
358
+ spec = importlib.util.spec_from_file_location("dev_environment_lib", path)
359
+ if spec is None or spec.loader is None:
360
+ raise RuntimeError(
361
+ "[DEV_ENVIRONMENT_LIB_LOAD_ERROR] Could not create import spec for "
362
+ f"{path}. Reinstall its-magic ({REPO_URL})."
363
+ )
364
+ mod = importlib.util.module_from_spec(spec)
365
+ sys.modules["dev_environment_lib"] = mod
366
+ try:
367
+ spec.loader.exec_module(mod)
368
+ except Exception as e:
369
+ sys.modules.pop("dev_environment_lib", None)
370
+ raise RuntimeError(
371
+ "[DEV_ENVIRONMENT_LIB_LOAD_ERROR] dev_environment_lib failed to load "
372
+ f"({e!r}). Reinstall its-magic ({REPO_URL})."
373
+ ) from e
374
+ return mod
375
+
376
+
377
+ def bootstrap_dev_environment_profile_installer_hook(target_root, source_root):
378
+ """
379
+ Non-destructive dev-environment profile bootstrap.
380
+ Fail-closed only on PATH_INVALID / SOURCE_MISSING.
381
+ """
382
+ try:
383
+ lib = _load_dev_environment_lib()
384
+ except RuntimeError as exc:
385
+ print(str(exc))
386
+ return False
387
+ merged, _paths = merge_scratchpad_layers(target_root)
388
+ reason, _channel = lib.bootstrap_dev_environment_profile(
389
+ target_root, source_root, merged
390
+ )
391
+ if reason in (
392
+ lib.DEV_ENV_BOOTSTRAP_PATH_INVALID,
393
+ lib.DEV_ENV_BOOTSTRAP_SOURCE_MISSING,
394
+ ):
395
+ return False
396
+ return True
397
+
398
+
348
399
  def _doc_profile_sync(target_root, merged, print_ok=True):
349
400
  """Append missing normative README/developer doc sections from merged profile (non-destructive)."""
350
401
  doc_profile_lib = _load_doc_profile_lib()
@@ -878,6 +929,8 @@ def main():
878
929
 
879
930
  if not run_scratchpad_postinstall(target_root, source_root, "upgrade", print_ok=True):
880
931
  return 1
932
+ if not bootstrap_dev_environment_profile_installer_hook(target_root, source_root):
933
+ return 1
881
934
  if not validate_install_completeness(target_root, source_root, required_script_paths, manifest_path):
882
935
  return 1
883
936
 
@@ -958,6 +1011,8 @@ def main():
958
1011
 
959
1012
  if not run_scratchpad_postinstall(target_root, source_root, mode, print_ok=True):
960
1013
  return 1
1014
+ if not bootstrap_dev_environment_profile_installer_hook(target_root, source_root):
1015
+ return 1
961
1016
  if not validate_install_completeness(target_root, source_root, required_script_paths, manifest_path):
962
1017
  return 1
963
1018
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "its-magic",
3
- "version": "0.1.2",
3
+ "version": "0.1.3-1",
4
4
  "description": "its-magic - AI dev team workflow for Cursor.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -202,6 +202,90 @@ DEV_ENVIRONMENT_PAIRS: tuple[tuple[str, str], ...] = (
202
202
  ),
203
203
  )
204
204
 
205
+ RELEASE_CHANGELOG_PAIRS: tuple[tuple[str, str], ...] = (
206
+ (
207
+ "scripts/release_changelog_lib.py",
208
+ "template/scripts/release_changelog_lib.py",
209
+ ),
210
+ (
211
+ "scripts/release_changelog_validate.py",
212
+ "template/scripts/release_changelog_validate.py",
213
+ ),
214
+ (
215
+ "scripts/release_changelog_backfill.py",
216
+ "template/scripts/release_changelog_backfill.py",
217
+ ),
218
+ ("CHANGELOG.md", "template/CHANGELOG.md"),
219
+ (".cursor/commands/release.md", "template/.cursor/commands/release.md"),
220
+ ("scripts/release-all.sh", "template/scripts/release-all.sh"),
221
+ (
222
+ "template/handoffs/releases/vX.Y.Z-release-notes.md.example",
223
+ "template/handoffs/releases/vX.Y.Z-release-notes.md.example",
224
+ ),
225
+ (
226
+ "scripts/check_intake_template_parity.py",
227
+ "template/scripts/check_intake_template_parity.py",
228
+ ),
229
+ )
230
+
231
+ MODEL_TIER_PAIRS: tuple[tuple[str, str], ...] = (
232
+ (
233
+ "scripts/model_tier_lib.py",
234
+ "template/scripts/model_tier_lib.py",
235
+ ),
236
+ (
237
+ "scripts/model_tier_validate.py",
238
+ "template/scripts/model_tier_validate.py",
239
+ ),
240
+ (
241
+ "docs/engineering/runbook.md",
242
+ "template/docs/engineering/runbook.md",
243
+ ),
244
+ (
245
+ ".cursor/scratchpad.md",
246
+ "template/.cursor/scratchpad.md",
247
+ ),
248
+ (
249
+ ".cursor/scratchpad.local.example.md",
250
+ "template/.cursor/scratchpad.local.example.md",
251
+ ),
252
+ (
253
+ "scripts/check_intake_template_parity.py",
254
+ "template/scripts/check_intake_template_parity.py",
255
+ ),
256
+ )
257
+
258
+ MODEL_TIER_OVERRIDES_PAIRS: tuple[tuple[str, str], ...] = (
259
+ (
260
+ ".cursor/scratchpad.md",
261
+ "template/.cursor/scratchpad.md",
262
+ ),
263
+ (
264
+ ".cursor/scratchpad.local.example.md",
265
+ "template/.cursor/scratchpad.local.example.md",
266
+ ),
267
+ (
268
+ ".cursor/model-catalog.local.example.role-based-balanced.json",
269
+ "template/.cursor/model-catalog.local.example.role-based-balanced.json",
270
+ ),
271
+ (
272
+ ".cursor/model-catalog.local.example.role-based-highend.json",
273
+ "template/.cursor/model-catalog.local.example.role-based-highend.json",
274
+ ),
275
+ (
276
+ "scripts/model_tier_lib.py",
277
+ "template/scripts/model_tier_lib.py",
278
+ ),
279
+ (
280
+ "scripts/model_tier_validate.py",
281
+ "template/scripts/model_tier_validate.py",
282
+ ),
283
+ (
284
+ "docs/engineering/runbook.md",
285
+ "template/docs/engineering/runbook.md",
286
+ ),
287
+ )
288
+
205
289
  DOWNSTREAM_CI_GUARD_PAIRS: tuple[tuple[str, str], ...] = (
206
290
  (
207
291
  "scripts/check_downstream_ci_guard.py",
@@ -225,6 +309,9 @@ SCOPES: dict[str, tuple[tuple[str, str], ...]] = {
225
309
  "us-0096": US0096_PAIRS,
226
310
  "project-readme": PROJECT_README_PAIRS,
227
311
  "dev-environment": DEV_ENVIRONMENT_PAIRS,
312
+ "release-changelog": RELEASE_CHANGELOG_PAIRS,
313
+ "model-tier": MODEL_TIER_PAIRS,
314
+ "model-tier-overrides": MODEL_TIER_OVERRIDES_PAIRS,
228
315
  "all": (
229
316
  INTAKE_TEMPLATE_PAIRS
230
317
  + CAVEMAN_COMPRESS_PAIRS
@@ -237,6 +324,9 @@ SCOPES: dict[str, tuple[tuple[str, str], ...]] = {
237
324
  + US0096_PAIRS
238
325
  + PROJECT_README_PAIRS
239
326
  + DEV_ENVIRONMENT_PAIRS
327
+ + RELEASE_CHANGELOG_PAIRS
328
+ + MODEL_TIER_PAIRS
329
+ + MODEL_TIER_OVERRIDES_PAIRS
240
330
  ),
241
331
  }
242
332
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Curator agent"
3
+ model: fast
3
4
  ---
4
5
 
5
6
  You are the Curator. Keep context compact and artifacts current.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Product Owner agent"
3
+ model: inherit
3
4
  ---
4
5
 
5
6
  You are the PO. Your job is to clarify requirements and persist them.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Release agent"
3
+ model: inherit
3
4
  ---
4
5
 
5
6
  You are Release. Prepare release notes and runbook commands.
@@ -425,6 +425,24 @@ Guardrails:
425
425
  - `RELEASE_OPERATOR_HINTS_SECRET_EXPOSURE`
426
426
  - Remediation: populate required fields in canonical sprint notes with
427
427
  sanitized env-ref-only credential guidance, then rerun `/release`.
428
+ 19. Version changelog derivation (US-0100 / DEC-0085):
429
+ - Runs **only after** step **9** successful finalization (`unreleased → released`)
430
+ and step **18** operator hints (**US-0067**). Doc writes are **not** publish
431
+ execution — **`RELEASE_PUBLISH_MODE=disabled`** remains valid (**US-0054**).
432
+ - **19a — Resolve semver**: read target queue row **`release_version`**; when
433
+ blank, workflow-only release → **`[Unreleased]`** path only (no per-version file).
434
+ - **19b — Derive work items**: `derive_work_items` for target sprint + coalesce
435
+ peer **`released`** rows sharing normalized semver when semver known
436
+ (`coalesce_sprints_by_semver`).
437
+ - **19c — Write docs**: when semver known → `build_version_doc` +
438
+ `promote_unreleased` + `bind_queue_release_version`; else `append_unreleased`
439
+ only. Per-version SOT = `handoffs/releases/{semver}-release-notes.md` (stem
440
+ without leading **`v`**). Never pass `Sxxxx-release-notes.md` to **`gh -F`**.
441
+ - **19d — Validate (optional enforce)**: when scratchpad
442
+ **`RELEASE_CHANGELOG_ENFORCE=1`** (default **`1`** post-bootstrap), run
443
+ `python scripts/release_changelog_validate.py --repo . --enforce`; record
444
+ outcome in `sprints/Sxxxx/release-findings.md` § version-doc gates. When
445
+ **`0`**, report `skipped` evidence only.
428
446
 
429
447
  ## Fail-safe reason codes and remediation guidance
430
448
 
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "tiers": {
4
+ "cheap": "composer-2.5-fast",
5
+ "balanced": "composer-2.5-standard",
6
+ "strong": "composer-2.5"
7
+ },
8
+ "notes": "Cursor-integrated models only. Uses Cursor's own Composer 2.5 family via stable Cursor model IDs. No external API key is required; everything routes through Cursor-managed infrastructure. Strong maps to the strongest available Composer 2.5 variant (often the default parent model when model: is omitted)."
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "tiers": {
4
+ "cheap": "<your-cheap-model-slug>",
5
+ "balanced": "<your-balanced-model-slug>",
6
+ "strong": "<your-strong-model-slug>"
7
+ },
8
+ "notes": "Copy this file to .cursor/model-catalog.local.json and replace placeholder slugs with vendor-specific model IDs. Enable with MODEL_RESOLVE=local_catalog in .cursor/scratchpad.local.md. All three tier keys are required."
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "tiers": {
4
+ "cheap": "qwen-3.7-plus",
5
+ "balanced": "composer-2.5-standard",
6
+ "strong": "glm-4.7"
7
+ },
8
+ "notes": "Level 1 — small/simple apps (CRUD, dashboard, bot, single-service). Cost-focused: Qwen3.7 Plus handles routine volume, Composer 2.5 Standard is the Cursor default, GLM-4.7 covers occasional architecture/release gates. Based on ai_modell_auslegung_cursor_highend.md 'Kleine unkomplizierte Apps'. Enable with MODEL_RESOLVE=local_catalog."
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "tiers": {
4
+ "cheap": "qwen-3.7-plus",
5
+ "balanced": "composer-2.5-standard",
6
+ "strong": "glm-5.2"
7
+ },
8
+ "notes": "Level 2 — complex apps (multi-service, auth, DB, FE+BE, Docker, API, worker/queue). Balanced: cheap Qwen for mass DEV, Composer 2.5 Standard as Cursor default, strong GLM-5.2 for architecture/QA/release gates. Based on ai_modell_auslegung_cursor_highend.md 'Komplexere Apps'. Enable with MODEL_RESOLVE=local_catalog."
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "tiers": {
4
+ "cheap": "qwen-3.7-plus",
5
+ "balanced": "glm-5.2",
6
+ "strong": "gpt-5.5"
7
+ },
8
+ "notes": "Level 3 — mega-complex software / modular monoliths (trading/finance platforms, multi-team systems, long-lived infrastructure). Strong GPT-5.5 for chief-architect/final-gate work, GLM-5.2 for SA/QA/RELEASE, Qwen for volume DEV. Based on ai_modell_auslegung_cursor_highend.md 'Mega-komplexe Software'. Enable with MODEL_RESOLVE=local_catalog."
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "tiers": {
4
+ "cheap": "qwen-3.7-plus",
5
+ "balanced": "kimi-k2.7-code",
6
+ "strong": "claude-opus-4.8"
7
+ },
8
+ "notes": "Level 4 — super-high-sophisticated / mission-critical (AI operating systems, critical infrastructure, long-horizon agent systems, high-risk security/privacy/finance). Chief-architect quality: Claude Opus 4.8 for critical gates, Kimi K2.7 Code for difficult long-horizon DEV, Qwen for cheap mass work. Based on ai_modell_auslegung_cursor_highend.md 'Super-High-Sophisticated Projects'. Enable with MODEL_RESOLVE=local_catalog."
9
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "schema_version": 2,
3
+ "tiers": {
4
+ "cheap": "<your-cheap-model-slug>",
5
+ "balanced": "<your-balanced-model-slug>",
6
+ "strong": "<your-strong-model-slug>"
7
+ },
8
+ "roles": {
9
+ "po": "<your-po-model-slug>",
10
+ "sa": "<your-sa-model-slug>",
11
+ "dev": "<your-dev-model-slug>",
12
+ "dev_difficult": "<your-dev-difficult-model-slug>",
13
+ "qa": "<your-qa-model-slug>",
14
+ "security": "<your-security-model-slug>",
15
+ "release": "<your-release-model-slug>"
16
+ },
17
+ "notes": "Role-based balanced preset (US-0102 / DEC-0087). Copy to .cursor/model-catalog.local.json and set MODEL_RESOLVE=role_catalog in .cursor/scratchpad.local.md. All tier and role keys required when roles section present."
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "schema_version": 2,
3
+ "tiers": {
4
+ "cheap": "<your-cheap-highend-slug>",
5
+ "balanced": "<your-balanced-highend-slug>",
6
+ "strong": "<your-strong-highend-slug>"
7
+ },
8
+ "roles": {
9
+ "po": "<your-po-highend-slug>",
10
+ "sa": "<your-sa-highend-slug>",
11
+ "dev": "<your-dev-highend-slug>",
12
+ "dev_difficult": "<your-dev-difficult-highend-slug>",
13
+ "qa": "<your-qa-highend-slug>",
14
+ "security": "<your-security-highend-slug>",
15
+ "release": "<your-release-highend-slug>"
16
+ },
17
+ "notes": "Role-based high-end preset (US-0102 / DEC-0087). See ai_modell_auslegung_cursor_highend.md for non-normative role recommendations. Enable with MODEL_RESOLVE=role_catalog."
18
+ }
@@ -321,3 +321,58 @@ CAVEMAN_MODE=0
321
321
  CAVEMAN_LEVEL=
322
322
  CAVEMAN_COMPRESS_INPUT=0
323
323
  CAVEMAN_FILE_SCOPE=
324
+
325
+ #
326
+ # ## Per-phase model tier selection (US-0101 / DEC-0086)
327
+ # MODEL_TIER selects LLM model strength (which model runs).
328
+ # MODEL_TIER ≠ TOKEN_PROFILE ≠ DELIVERY_MODE — these are independent axes;
329
+ # none substitutes for the other (DEC-0062 / US-0080 / US-0096).
330
+ # - MODEL_TIER_DEFAULT: cheap|balanced|strong (default balanced)
331
+ # - MODEL_TIER_<PHASE>: cheap|balanced|strong (per-phase override; PHASE = canonical phase id)
332
+ # Default matrix (architecture-locked):
333
+ # cheap — ask, refresh-context, memory-audit, status-reconcile, pause
334
+ # balanced — intake, discovery, research, release, plan-verify
335
+ # strong — architecture, execute, quick, qa, verify-work, security-review
336
+ # (inherit parent) — auto (orchestrator always inherits parent model)
337
+ # - MODEL_CATALOG: path to local slug catalog (default .cursor/model-catalog.local.json)
338
+ # - MODEL_RESOLVE: alias_only|local_catalog|role_catalog (default alias_only)
339
+ # - MODEL_FALLBACK: fallback when catalog lookup fails (default inherit)
340
+ # - MODEL_PROVIDER_MODE: cursor|api (default cursor)
341
+ # cursor = all subagents route through Cursor-managed infrastructure
342
+ # api = operator uses BYOK via Cursor Settings → Models → API Key
343
+ # Known limitation: subagents do NOT inherit custom API keys/base URLs.
344
+ #
345
+ # ## Direct per-phase model slug override (US-0102 / DEC-0087) — set in this local file only
346
+ # Precedence: MODEL_<PHASE> > MODEL_TIER_<PHASE> > MODEL_TIER_DEFAULT > Cursor alias
347
+ # - MODEL_<PHASE>: direct vendor slug (e.g. MODEL_EXECUTE=<your-vendor-slug>, MODEL_ASK=<your-vendor-slug>)
348
+ # - MODEL_RESOLVE=role_catalog enables phase→role→catalog slug lookup (requires v2 catalog with roles section)
349
+ MODEL_TIER_DEFAULT=balanced
350
+ MODEL_CATALOG=.cursor/model-catalog.local.json
351
+ MODEL_RESOLVE=alias_only
352
+ MODEL_FALLBACK=inherit
353
+ MODEL_PROVIDER_MODE=cursor
354
+
355
+ # Per-phase tier overrides for this project (uncomment and adjust as needed):
356
+ #MODEL_TIER_INTAKE=balanced
357
+ #MODEL_TIER_DISCOVERY=cheap
358
+ #MODEL_TIER_RESEARCH=balanced
359
+ #MODEL_TIER_ARCHITECTURE=strong
360
+ #MODEL_TIER_SPRINT-PLAN=strong
361
+ #MODEL_TIER_PLAN-VERIFY=balanced
362
+ #MODEL_TIER_EXECUTE=cheap
363
+ #MODEL_TIER_QA=strong
364
+ #MODEL_TIER_VERIFY-WORK=strong
365
+ #MODEL_TIER_RELEASE=balanced
366
+ #MODEL_TIER_REFRESH-CONTEXT=cheap
367
+
368
+ # Direct per-phase slug overrides (US-0102 — uncomment and set vendor slugs):
369
+ #MODEL_ASK=<your-vendor-slug>
370
+ #MODEL_EXECUTE=<your-vendor-slug>
371
+ #MODEL_QA=<your-vendor-slug>
372
+
373
+ # Use a vendor catalog instead of Cursor aliases:
374
+ # cp .cursor/model-catalog.local.example.level-2-complex.json .cursor/model-catalog.local.json
375
+ #MODEL_RESOLVE=local_catalog
376
+ # Role-based catalog preset (US-0102):
377
+ # cp .cursor/model-catalog.local.example.role-based-balanced.json .cursor/model-catalog.local.json
378
+ #MODEL_RESOLVE=role_catalog
@@ -322,3 +322,65 @@ CAVEMAN_MODE=1
322
322
  CAVEMAN_LEVEL=full
323
323
  CAVEMAN_COMPRESS_INPUT=0
324
324
  CAVEMAN_FILE_SCOPE=
325
+
326
+ #
327
+ # ## Per-phase model tier selection (US-0101 / DEC-0086)
328
+ # MODEL_TIER selects LLM model strength (which model runs).
329
+ # MODEL_TIER ≠ TOKEN_PROFILE ≠ DELIVERY_MODE — these are independent axes;
330
+ # none substitutes for the other (DEC-0062 / US-0080 / US-0096).
331
+ # - MODEL_TIER_DEFAULT: cheap|balanced|strong (default balanced)
332
+ # - MODEL_TIER_<PHASE>: cheap|balanced|strong (per-phase override; PHASE = canonical phase id)
333
+ # Examples: MODEL_TIER_EXECUTE=cheap, MODEL_TIER_QA=strong, MODEL_TIER_RESEARCH=balanced
334
+ # Set in .cursor/scratchpad.local.md to override per phase without touching committed defaults.
335
+ # Default matrix (architecture-locked):
336
+ # cheap — ask, refresh-context, memory-audit, status-reconcile, pause
337
+ # balanced — intake, discovery, research, release, plan-verify
338
+ # strong — architecture, execute, quick, qa, verify-work, security-review
339
+ # (inherit parent) — auto (orchestrator always inherits parent model)
340
+ # - MODEL_CATALOG: path to local slug catalog (default .cursor/model-catalog.local.json)
341
+ # - MODEL_RESOLVE: alias_only|local_catalog|role_catalog (default alias_only)
342
+ # alias_only = use Cursor-stable aliases (cheap->fast, balanced->inherit, strong->omit model:)
343
+ # local_catalog = look up vendor model slugs from MODEL_CATALOG; requires valid JSON catalog
344
+ # role_catalog = opt-in phase→role→catalog slug lookup (US-0102 / DEC-0087); falls through on miss
345
+ # - MODEL_FALLBACK: fallback when catalog lookup fails (default inherit)
346
+ # - MODEL_PROVIDER_MODE: cursor|api (default cursor)
347
+ # cursor = all subagents route through Cursor-managed infrastructure
348
+ # api = operator uses BYOK via Cursor Settings → Models → API Key
349
+ # Known limitation: subagents do NOT inherit custom API keys/base URLs.
350
+ #
351
+ # Example catalogs for 4 software-complexity levels + a Cursor-only variant:
352
+ # .cursor/model-catalog.local.example.json — minimal placeholder template
353
+ # .cursor/model-catalog.local.example.cursor-only.json — only Cursor-integrated Composer models
354
+ # .cursor/model-catalog.local.example.level-1-easy.json — small/simple apps
355
+ # .cursor/model-catalog.local.example.level-2-complex.json — complex multi-service apps
356
+ # .cursor/model-catalog.local.example.level-3-mega.json — mega-complex / modular monoliths
357
+ # .cursor/model-catalog.local.example.level-4-super.json — super-high-sophisticated / mission-critical
358
+ # .cursor/model-catalog.local.example.role-based-balanced.json — v2 role preset (balanced)
359
+ # .cursor/model-catalog.local.example.role-based-highend.json — v2 role preset (high-end)
360
+ # Copy one to .cursor/model-catalog.local.json and set MODEL_RESOLVE=local_catalog or role_catalog to activate.
361
+ MODEL_TIER_DEFAULT=balanced
362
+ MODEL_CATALOG=.cursor/model-catalog.local.json
363
+ MODEL_RESOLVE=alias_only
364
+ MODEL_FALLBACK=inherit
365
+ MODEL_PROVIDER_MODE=cursor
366
+ #
367
+ # ## Direct per-phase model slug override + role catalog (US-0102 / DEC-0087)
368
+ # Composes on US-0101 / DEC-0086 — tier baseline unchanged; overlays are optional.
369
+ # Precedence chain (deterministic, per canonical phase_id):
370
+ # 1. MODEL_<PHASE> — direct vendor slug override (highest priority)
371
+ # 2. MODEL_TIER_<PHASE> — DEC-0086 tier→alias / local_catalog chain
372
+ # 3. role_catalog lookup — only when MODEL_RESOLVE=role_catalog; miss falls through
373
+ # 4. MODEL_TIER_DEFAULT — DEC-0086 tier chain
374
+ # 5. Cursor stable alias — DEC-0086 built-in mapping (fast / inherit / omit)
375
+ # Scratchpad merge precedence for all MODEL_* keys: MODEL_<PHASE> > MODEL_TIER_<PHASE> > MODEL_TIER_DEFAULT
376
+ # - MODEL_<PHASE>: direct vendor slug; <PHASE> = canonical phase id (same list as MODEL_TIER_<PHASE>)
377
+ # Set in .cursor/scratchpad.local.md only — use <your-vendor-slug> placeholders in committed files.
378
+ # Canonical phase ids: ask, refresh-context, memory-audit, status-reconcile, pause,
379
+ # intake, discovery, research, release, plan-verify, architecture, execute, quick,
380
+ # qa, verify-work, security-review, auto
381
+ # Examples (placeholders — replace in scratchpad.local.md):
382
+ # MODEL_ASK=<your-vendor-slug>
383
+ # MODEL_EXECUTE=<your-vendor-slug>
384
+ # MODEL_QA=<your-vendor-slug>
385
+ # MODEL_REFRESH-CONTEXT=<your-vendor-slug>
386
+ # MODEL_ASK participates in step 1 like any other phase (no special-case bypass).
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ <!-- semver-sections-newest-first -->
9
+
10
+ ## [Unreleased]
11
+