@hegemonart/get-design-done 1.41.0 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +81 -0
  4. package/README.md +2 -0
  5. package/dist/claude-code/.claude/skills/add-backlog/SKILL.md +48 -0
  6. package/dist/claude-code/.claude/skills/analyze-dependencies/SKILL.md +95 -0
  7. package/dist/claude-code/.claude/skills/apply-reflections/SKILL.md +92 -0
  8. package/dist/claude-code/.claude/skills/apply-reflections/apply-reflections-procedure.md +170 -0
  9. package/dist/claude-code/.claude/skills/audit/SKILL.md +79 -0
  10. package/dist/claude-code/.claude/skills/bandit-status/SKILL.md +94 -0
  11. package/dist/claude-code/.claude/skills/benchmark/SKILL.md +65 -0
  12. package/dist/claude-code/.claude/skills/bootstrap-ds/SKILL.md +43 -0
  13. package/dist/claude-code/.claude/skills/brief/SKILL.md +128 -0
  14. package/dist/claude-code/.claude/skills/budget/SKILL.md +45 -0
  15. package/dist/claude-code/.claude/skills/cache-manager/SKILL.md +66 -0
  16. package/dist/claude-code/.claude/skills/cache-manager/cache-policy.md +126 -0
  17. package/dist/claude-code/.claude/skills/check-update/SKILL.md +98 -0
  18. package/dist/claude-code/.claude/skills/compare/SKILL.md +82 -0
  19. package/dist/claude-code/.claude/skills/compare/compare-rubric.md +171 -0
  20. package/dist/claude-code/.claude/skills/complete-cycle/SKILL.md +81 -0
  21. package/dist/claude-code/.claude/skills/connections/SKILL.md +71 -0
  22. package/dist/claude-code/.claude/skills/connections/connections-onboarding.md +608 -0
  23. package/dist/claude-code/.claude/skills/continue/SKILL.md +24 -0
  24. package/dist/claude-code/.claude/skills/darkmode/SKILL.md +76 -0
  25. package/dist/claude-code/.claude/skills/darkmode/darkmode-audit-procedure.md +258 -0
  26. package/dist/claude-code/.claude/skills/debug/SKILL.md +41 -0
  27. package/dist/claude-code/.claude/skills/debug/debug-feedback-loops.md +119 -0
  28. package/dist/claude-code/.claude/skills/design/SKILL.md +99 -0
  29. package/dist/claude-code/.claude/skills/design/design-procedure.md +304 -0
  30. package/dist/claude-code/.claude/skills/discover/SKILL.md +72 -0
  31. package/dist/claude-code/.claude/skills/discover/discover-procedure.md +222 -0
  32. package/dist/claude-code/.claude/skills/discuss/SKILL.md +96 -0
  33. package/dist/claude-code/.claude/skills/do/SKILL.md +45 -0
  34. package/dist/claude-code/.claude/skills/explore/SKILL.md +105 -0
  35. package/dist/claude-code/.claude/skills/explore/explore-procedure.md +267 -0
  36. package/dist/claude-code/.claude/skills/export/SKILL.md +30 -0
  37. package/dist/claude-code/.claude/skills/extract-learnings/SKILL.md +98 -0
  38. package/dist/claude-code/.claude/skills/fast/SKILL.md +91 -0
  39. package/dist/claude-code/.claude/skills/figma-extract/SKILL.md +64 -0
  40. package/dist/claude-code/.claude/skills/figma-write/SKILL.md +39 -0
  41. package/dist/claude-code/.claude/skills/graphify/SKILL.md +49 -0
  42. package/dist/claude-code/.claude/skills/health/SKILL.md +99 -0
  43. package/dist/claude-code/.claude/skills/health/health-mcp-detection.md +44 -0
  44. package/dist/claude-code/.claude/skills/health/health-skill-length-report.md +69 -0
  45. package/dist/claude-code/.claude/skills/help/SKILL.md +87 -0
  46. package/dist/claude-code/.claude/skills/list-assumptions/SKILL.md +61 -0
  47. package/dist/claude-code/.claude/skills/locale/SKILL.md +51 -0
  48. package/dist/claude-code/.claude/skills/map/SKILL.md +89 -0
  49. package/dist/claude-code/.claude/skills/migrate/SKILL.md +70 -0
  50. package/dist/claude-code/.claude/skills/new-cycle/SKILL.md +37 -0
  51. package/dist/claude-code/.claude/skills/new-cycle/milestone-completeness-rubric.md +87 -0
  52. package/dist/claude-code/.claude/skills/new-project/SKILL.md +53 -0
  53. package/dist/claude-code/.claude/skills/next/SKILL.md +68 -0
  54. package/dist/claude-code/.claude/skills/note/SKILL.md +48 -0
  55. package/dist/claude-code/.claude/skills/openrouter-status/SKILL.md +86 -0
  56. package/dist/claude-code/.claude/skills/optimize/SKILL.md +97 -0
  57. package/dist/claude-code/.claude/skills/pause/SKILL.md +77 -0
  58. package/dist/claude-code/.claude/skills/peer-cli-add/SKILL.md +88 -0
  59. package/dist/claude-code/.claude/skills/peer-cli-add/peer-cli-protocol.md +161 -0
  60. package/dist/claude-code/.claude/skills/peer-cli-customize/SKILL.md +90 -0
  61. package/dist/claude-code/.claude/skills/peers/SKILL.md +96 -0
  62. package/dist/claude-code/.claude/skills/plan/SKILL.md +105 -0
  63. package/dist/claude-code/.claude/skills/plan/plan-procedure.md +278 -0
  64. package/dist/claude-code/.claude/skills/plant-seed/SKILL.md +48 -0
  65. package/dist/claude-code/.claude/skills/pr-branch/SKILL.md +32 -0
  66. package/dist/claude-code/.claude/skills/progress/SKILL.md +95 -0
  67. package/dist/claude-code/.claude/skills/quality-gate/SKILL.md +90 -0
  68. package/dist/claude-code/.claude/skills/quality-gate/threat-modeling.md +101 -0
  69. package/dist/claude-code/.claude/skills/quick/SKILL.md +44 -0
  70. package/dist/claude-code/.claude/skills/reapply-patches/SKILL.md +32 -0
  71. package/dist/claude-code/.claude/skills/recall/SKILL.md +75 -0
  72. package/dist/claude-code/.claude/skills/reflect/SKILL.md +85 -0
  73. package/dist/claude-code/.claude/skills/reflect/procedures/capability-gap-scan.md +120 -0
  74. package/dist/claude-code/.claude/skills/report-issue/SKILL.md +53 -0
  75. package/dist/claude-code/.claude/skills/report-issue/report-issue-procedure.md +120 -0
  76. package/dist/claude-code/.claude/skills/resume/SKILL.md +93 -0
  77. package/dist/claude-code/.claude/skills/review-backlog/SKILL.md +46 -0
  78. package/dist/claude-code/.claude/skills/review-decisions/SKILL.md +42 -0
  79. package/dist/claude-code/.claude/skills/roi/SKILL.md +54 -0
  80. package/dist/claude-code/.claude/skills/rollout-status/SKILL.md +35 -0
  81. package/dist/claude-code/.claude/skills/router/SKILL.md +89 -0
  82. package/dist/claude-code/.claude/skills/router/capability-gap-emitter.md +65 -0
  83. package/dist/claude-code/.claude/skills/router/router-pick-emitter.md +78 -0
  84. package/dist/claude-code/.claude/skills/router/router-rules.md +84 -0
  85. package/dist/claude-code/.claude/skills/scan/SKILL.md +92 -0
  86. package/dist/claude-code/.claude/skills/scan/scan-procedure.md +732 -0
  87. package/dist/claude-code/.claude/skills/settings/SKILL.md +87 -0
  88. package/dist/claude-code/.claude/skills/ship/SKILL.md +48 -0
  89. package/dist/claude-code/.claude/skills/sketch/SKILL.md +78 -0
  90. package/dist/claude-code/.claude/skills/sketch-wrap-up/SKILL.md +92 -0
  91. package/dist/claude-code/.claude/skills/skill-manifest/SKILL.md +79 -0
  92. package/dist/claude-code/.claude/skills/spike/SKILL.md +67 -0
  93. package/dist/claude-code/.claude/skills/spike-wrap-up/SKILL.md +86 -0
  94. package/dist/claude-code/.claude/skills/start/SKILL.md +67 -0
  95. package/dist/claude-code/.claude/skills/start/start-procedure.md +115 -0
  96. package/dist/claude-code/.claude/skills/stats/SKILL.md +51 -0
  97. package/dist/claude-code/.claude/skills/style/SKILL.md +71 -0
  98. package/dist/claude-code/.claude/skills/style/style-doc-procedure.md +150 -0
  99. package/dist/claude-code/.claude/skills/synthesize/SKILL.md +94 -0
  100. package/dist/claude-code/.claude/skills/timeline/SKILL.md +66 -0
  101. package/dist/claude-code/.claude/skills/todo/SKILL.md +64 -0
  102. package/dist/claude-code/.claude/skills/turn-closeout/SKILL.md +95 -0
  103. package/dist/claude-code/.claude/skills/undo/SKILL.md +31 -0
  104. package/dist/claude-code/.claude/skills/unlock-decision/SKILL.md +54 -0
  105. package/dist/claude-code/.claude/skills/update/SKILL.md +56 -0
  106. package/dist/claude-code/.claude/skills/using-gdd/SKILL.md +78 -0
  107. package/dist/claude-code/.claude/skills/verify/SKILL.md +113 -0
  108. package/dist/claude-code/.claude/skills/verify/verify-procedure.md +512 -0
  109. package/dist/claude-code/.claude/skills/warm-cache/SKILL.md +81 -0
  110. package/dist/claude-code/.claude/skills/watch-authorities/SKILL.md +82 -0
  111. package/dist/claude-code/.claude/skills/zoom-out/SKILL.md +26 -0
  112. package/package.json +5 -1
  113. package/reference/DEPRECATIONS.md +14 -0
  114. package/reference/registry.json +7 -0
  115. package/reference/skill-placeholders.md +71 -0
  116. package/scripts/lib/build/factory.cjs +62 -0
  117. package/scripts/lib/build/harness-configs.cjs +64 -0
  118. package/scripts/lib/manifest/README.md +46 -0
  119. package/scripts/lib/manifest/harnesses.cjs +3 -0
  120. package/scripts/lib/manifest/harnesses.json +91 -0
  121. package/scripts/lib/manifest/index.cjs +26 -0
  122. package/scripts/lib/manifest/loader.cjs +51 -0
  123. package/scripts/lib/manifest/prose-denylist.json +126 -0
  124. package/scripts/lib/manifest/schemas/harnesses.schema.json +38 -0
  125. package/scripts/lib/manifest/schemas/prose-denylist.schema.json +41 -0
  126. package/scripts/lib/manifest/schemas/skills.schema.json +33 -0
  127. package/scripts/lib/manifest/skills.json +255 -0
  128. package/sdk/cli/commands/build.ts +106 -0
  129. package/sdk/cli/index.js +84 -2
  130. package/sdk/cli/index.ts +7 -0
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: gdd-watch-authorities
3
+ description: "Fetches the design-authority feed whitelist, diffs against .design/authority-snapshot.json, and writes .design/authority-report.md (consumed by /gdd:reflect). Authority monitoring only — no trend-watching."
4
+ argument-hint: "[--refresh] [--since <date>] [--feed <name>] [--schedule <weekly|daily|monthly>]"
5
+ tools: Read, Write, Task, Bash
6
+ ---
7
+
8
+ # /gdd:watch-authorities
9
+
10
+ Runs `design-authority-watcher` on demand. Fetches the curated design-authority feed whitelist, diffs against the prior snapshot, classifies new entries into five buckets, and writes `.design/authority-report.md`. Phase 11's reflector picks up the report automatically when you next run `/gdd:reflect`.
11
+
12
+ Authority-monitoring only. Not trend-watching. See `reference/authority-feeds.md` §"Rejected kinds" for what this skill will never fetch.
13
+
14
+ ## Steps
15
+
16
+ 1. **Parse args.** Extract optional flags: `--refresh`, `--since <date>`, `--feed <name>`, `--schedule <cadence>`. Anything that doesn't match one of these is an error — print `Unknown flag: <arg>. Valid flags: --refresh --since <date> --feed <name> --schedule <weekly|daily|monthly>.` and STOP.
17
+
18
+ Mutual exclusion rules:
19
+ - `--schedule` is handled entirely by this skill — it does not combine with the other three. If `--schedule` is present alongside any of `--refresh | --since | --feed`, print `--schedule cannot combine with other flags. Schedule registration runs this skill with no flags at the configured cadence.` and STOP.
20
+ - `--refresh` and `--since` are mutually exclusive — print `--refresh and --since are mutually exclusive. --refresh re-seeds the snapshot silently; --since surfaces a backlog from a boundary date. Pick one.` and STOP.
21
+
22
+ 2. **Handle `--schedule <cadence>` branch** (early-return).
23
+
24
+ If `--schedule` is set:
25
+ - Validate cadence ∈ {`weekly`, `daily`, `monthly`}; else print `Unknown cadence: <value>. Use one of: weekly, daily, monthly.` and STOP.
26
+ - Probe for the scheduled-tasks MCP via ToolSearch:
27
+
28
+ ```
29
+ ToolSearch({ query: "scheduled-tasks", max_results: 3 })
30
+ ```
31
+
32
+ - If the probe returns an empty result set: print `scheduled-tasks MCP not connected. Install it with: claude mcp add scheduled-tasks ... then retry with --schedule.` — this is a documented fallback (not an error). Terminate with `## WATCH COMPLETE` and exit 0.
33
+ - If the probe returns one or more `scheduled-tasks` tools: register the cron. Discover the MCP's registration tool name at runtime from the ToolSearch result and follow its schema. Target command: `/gdd:watch-authorities` with NO flags (the cron invokes the default diff-and-report behavior). Cadence → cron expression mapping:
34
+ - `weekly` → `0 9 * * 1` (Mondays 09:00 local)
35
+ - `daily` → `0 9 * * *` (every day 09:00 local)
36
+ - `monthly` → `0 9 1 * *` (1st of each month 09:00 local)
37
+ - After registration: print `Scheduled /gdd:watch-authorities to run <cadence>.` and terminate with `## WATCH COMPLETE`.
38
+
39
+ 3. **Validate `--since <date>`** (if present).
40
+
41
+ Accept ISO8601 (`YYYY-MM-DD` or `YYYY-MM-DDTHH:MM:SSZ`). Sanity-check via Bash `date -d "<value>" +%s` (GNU) or the POSIX equivalent `python3 -c "from datetime import datetime; datetime.fromisoformat('<value>'.replace('Z','+00:00'))"`. On parse failure: print `Invalid --since value: <value>. Use ISO8601 (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ).` and STOP.
42
+
43
+ If the parsed date is earlier than `2020-01-01`, ask: `Very old --since value: <value>. Did you mean something more recent? Proceed? [y/N]`. On anything other than `y`/`Y`, STOP.
44
+
45
+ 4. **Spawn the watcher.**
46
+
47
+ Build the `Task(subagent_type="design-authority-watcher", ...)` prompt. The prompt supplies the agent's required-reading block (watcher step 0), echoes the invocation flags verbatim (watcher Flags section), and instructs the agent to follow its own fetch/diff/classify/write loop:
48
+
49
+ ```
50
+ Task("design-authority-watcher", """
51
+ <required_reading>
52
+ @reference/authority-feeds.md
53
+ @.design/authority-snapshot.json
54
+ @.design/STATE.md
55
+ </required_reading>
56
+
57
+ Invocation flags: <joined flag list or "none">
58
+
59
+ Fetch the feeds listed in reference/authority-feeds.md, diff against .design/authority-snapshot.json,
60
+ classify new entries per the D-17 decision table, write .design/authority-snapshot.json and
61
+ .design/authority-report.md.
62
+
63
+ Terminate with ## WATCH COMPLETE.
64
+ """)
65
+ ```
66
+
67
+ `<joined flag list>` is the subset of `--refresh | --since <date> | --feed <name>` actually passed — e.g., `--refresh`, `--since 2026-03-01`, `--feed wai-aria-apg`, `--refresh --feed radix-ui-releases`, or literally `none` when no flags were supplied.
68
+
69
+ 5. **Print summary.**
70
+
71
+ After the agent returns:
72
+ - If STATE.md gained a `<blocker type="contract-violation">` on this run (snapshot version mismatch, hash-format violation, or over-200 entries per feed), surface the blocker verbatim and stop — do not print the default "review and reflect" line.
73
+ - Otherwise print the agent's one-line stdout summary (normal mode: `Surfaced N entries across M feeds. K skipped. See .design/authority-report.md.`; first-run / refresh mode: `Seeded snapshot for N feeds — next run will surface new entries.`) followed by: `Review and reflect: /gdd:reflect`.
74
+
75
+ 6. **Terminate with `## WATCH COMPLETE`.**
76
+
77
+ ## Do Not
78
+
79
+ - Do not modify `agents/design-authority-watcher.md`.
80
+ - Do not modify `agents/design-reflector.md` — Phase 13.2 does not touch the reflector agent (CONTEXT.md D-25).
81
+ - Do not write to `.design/authority-snapshot.json` or `.design/authority-report.md` directly — those are the agent's writes.
82
+ - Do not fetch URLs outside `reference/authority-feeds.md`. The whitelist is the allow-list.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: zoom-out
3
+ description: "Asks the agent to go up a layer of abstraction and map the relevant modules and callers using the project's CONTEXT.md vocabulary. Use when the user is working in an unfamiliar area of code and needs orientation before deep work."
4
+ disable-model-invocation: true
5
+ argument-hint: "[scope]"
6
+ ---
7
+
8
+ Source: mattpocock/skills (MIT) — adapted with permission. See `../NOTICE` for the full attribution block.
9
+
10
+ # Zoom Out
11
+
12
+ **Role:** Give the user a map, not a fix.
13
+
14
+ I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary (`CONTEXT.md`) vocabulary.
15
+
16
+ When invoked, produce a one-screen map that names:
17
+
18
+ 1. **Modules in scope** — one-line description of each, using terms from `CONTEXT.md` (see `./../reference/context-md-format.md` for the schema). Do not invent terms.
19
+ 2. **Callers** — who calls these modules from elsewhere, with file paths.
20
+ 3. **Seams** — where data crosses module boundaries, named per `./../reference/architecture-vocabulary.md`.
21
+
22
+ Do not propose fixes. Do not write code. The output is a map.
23
+
24
+ If `CONTEXT.md` is absent, suggest `/gdd:discuss` to start one, but still produce the map using basenames and inferred terms.
25
+
26
+ ## ZOOM-OUT COMPLETE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hegemonart/get-design-done",
3
- "version": "1.41.0",
3
+ "version": "1.42.0",
4
4
  "description": "A design-quality pipeline for AI coding agents: brief, plan, implement, and verify UI work against your design system.",
5
5
  "author": "Hegemon",
6
6
  "homepage": "https://github.com/hegemonart/get-design-done",
@@ -23,6 +23,7 @@
23
23
  "sdk/",
24
24
  "recipes/",
25
25
  "docs/i18n/",
26
+ "dist/claude-code/",
26
27
  "scripts/lib/",
27
28
  "scripts/cli/",
28
29
  "scripts/install.cjs",
@@ -47,6 +48,8 @@
47
48
  },
48
49
  "scripts": {
49
50
  "build:bundles": "node scripts/build-distribution-bundles.cjs",
51
+ "build:skills": "node scripts/build-skills.cjs",
52
+ "build:skills:check": "node scripts/build-skills.cjs --check",
50
53
  "build:sdk": "node scripts/build-sdk-bins.cjs",
51
54
  "prepack": "npm run build:sdk",
52
55
  "postpack": "node scripts/build-sdk-bins.cjs --clean",
@@ -60,6 +63,7 @@
60
63
  "lint:changelog": "node scripts/lint-changelog.cjs",
61
64
  "lint:design": "node bin/gdd-detect test/fixtures/detect/negative --json",
62
65
  "sync:rule-catalogue": "node scripts/sync-rule-catalogue.cjs --check",
66
+ "validate:manifest": "node scripts/validate-manifest.cjs --check",
63
67
  "validate:schemas": "node --experimental-strip-types scripts/validate-schemas.ts",
64
68
  "validate:frontmatter": "node --experimental-strip-types scripts/validate-frontmatter.ts agents/",
65
69
  "detect:stale-refs": "node scripts/detect-stale-refs.cjs",
@@ -28,6 +28,20 @@ the scanner pattern list in lockstep.
28
28
  - **`scan`** (stage name) → merged/renamed into `explore` in Phase 3. Migration: references to the `scan` stage in shipped skills and agents were replaced with `explore`.
29
29
  - **`discover`** (stage name) → merged/renamed into `explore` in Phase 3. Migration: references to the `discover` stage in shipped skills and agents were replaced with `explore`.
30
30
 
31
+ ## Authoring surfaces
32
+
33
+ - **`skills/` as the authoring source** → **`source/skills/`** — deprecated in Phase 42 (multi-harness
34
+ source compilation). Skills are now authored once in `source/skills/` with placeholders
35
+ (`{{command_prefix}}` et al.; see `reference/skill-placeholders.md`) and compiled per-harness by
36
+ `scripts/build-skills.cjs`. The committed `skills/` tree is now a **generated artifact** (the Claude-Code
37
+ compile target) — CI's `npm run build:skills:check` drift-gates `committed === generated`.
38
+
39
+ Migration for contributors: **edit `source/skills/`, never `skills/` directly**, then run
40
+ `npm run build:skills` (or `gdd-sdk build skills`) and commit the regenerated `skills/` +
41
+ `dist/claude-code/`. `.claude-plugin/plugin.json`'s `"skills": ["./skills/"]` is unchanged — the plugin
42
+ still loads `skills/`, now produced from `source/skills/`. This is a path/authoring move only; no
43
+ stale-ref token is emitted (both paths are live), so the `detect-stale-refs.cjs` list is not extended.
44
+
31
45
  ## Scanner scope
32
46
 
33
47
  `scripts/detect-stale-refs.cjs` flags these tokens (line-granular match):
@@ -1042,6 +1042,13 @@
1042
1042
  "type": "meta-rules",
1043
1043
  "phase": 40.5,
1044
1044
  "description": "Phase 40.5 CLI-localization contract: locale resolution (config.locale > env LANG > en) + fallback chain locale->base->en + flat-JSON message tables via scripts/lib/i18n/index.cjs; tables at scripts/lib/i18n/messages/{en,ru,uk,de,fr,zh,ja}.json (en source-complete, ru full, 5 placeholders with en fallback); the opt-in description_i18n frontmatter (descriptionFor falls back to English); /gdd:locale skill; warn-only completeness; the add-a-locale contribution path (translate table + NOTICE credit + PR). Distinct from reference/i18n.md (which covers USER-design i18n)."
1045
+ },
1046
+ {
1047
+ "name": "skill-placeholders",
1048
+ "path": "reference/skill-placeholders.md",
1049
+ "type": "meta-rules",
1050
+ "phase": 42,
1051
+ "description": "Phase 42 multi-harness skill-placeholder catalogue: the four placeholders ({{command_prefix}}/{{model}}/{{config_file}}/{{ask_instruction}}) + per-harness substitution table + the \\{{...}} escape + the <!-- harness-only: a,b --> block rule. Skills authored once in source/skills/, compiled per-harness by scripts/build-skills.cjs via scripts/lib/build/factory.cjs reading scripts/lib/manifest/harnesses.json."
1045
1052
  }
1046
1053
  ]
1047
1054
  }
@@ -0,0 +1,71 @@
1
+ # Skill Placeholders — Multi-Harness Source Compilation
2
+
3
+ > Phase 42. Skills are authored once in `source/skills/` with placeholders and compiled per-harness into
4
+ > `dist/<bundle>/<config-dir>/skills/...` by `scripts/build-skills.cjs` (the pure transform lives in
5
+ > `scripts/lib/build/factory.cjs`; the per-harness values in `scripts/lib/build/harness-configs.cjs`,
6
+ > which reads the Phase 41.5 manifest root `scripts/lib/manifest/harnesses.json`). The Claude-Code
7
+ > compile target is the committed `skills/` tree; CI asserts `committed === generated` (the drift gate).
8
+
9
+ ## The four placeholders
10
+
11
+ | Placeholder | Meaning | Claude value (round-trip anchor) |
12
+ |-----------------------|------------------------------------------------------|----------------------------------|
13
+ | `{{command_prefix}}` | The slash-command invocation prefix before a verb. | `/gdd:` (so `{{command_prefix}}audit` -> `/gdd:audit`) |
14
+ | `{{model}}` | How the skill refers to the active model. | `your configured Claude model` |
15
+ | `{{config_file}}` | The harness's settings/config file path. | `.claude/settings.json` |
16
+ | `{{ask_instruction}}` | How the skill tells the user to query the agent. | `ask Claude Code` |
17
+
18
+ Only `{{command_prefix}}` is currently woven through the migrated source (every literal `/gdd:` became
19
+ `{{command_prefix}}`); the other three are documented + factory-supported for authors who need them.
20
+ Because Claude's `command_prefix` is exactly `/gdd:`, `compile(source, claude)` reproduces `skills/`
21
+ byte-for-byte — that pure-inverse property is what makes the drift gate safe.
22
+
23
+ ## Per-harness substitution table
24
+
25
+ | Harness id | `{{command_prefix}}` | `{{config_file}}` |
26
+ |---------------|----------------------|-----------------------------|
27
+ | `claude` | `/gdd:` | `.claude/settings.json` |
28
+ | `codex` | `/gdd-` | `.codex/config.toml` |
29
+ | `gemini` | `/gdd:` | `.gemini/settings.json` |
30
+ | `qwen` | `/gdd:` | `.qwen/settings.json` |
31
+ | `kilo` | `/gdd:` | `.kilo/config.json` |
32
+ | `copilot` | `/gdd:` | `.copilot/config.json` |
33
+ | `cursor` | `/gdd:` | `.cursor/settings.json` |
34
+ | `windsurf` | `/gdd:` | `.windsurf/settings.json` |
35
+ | `antigravity` | `/gdd:` | `.antigravity/config.json` |
36
+ | `augment` | `/gdd:` | `.augment/config.json` |
37
+ | `trae` | `/gdd:` | `.trae/config.json` |
38
+ | `codebuddy` | `/gdd:` | `.codebuddy/config.json` |
39
+ | `cline` | `/gdd:` | `.cline/config.json` |
40
+ | `opencode` | `/gdd:` | `.opencode/config.json` |
41
+
42
+ `codex` is the deliberate outlier: its custom-prompt grammar is flat (`/gdd-audit`), not the namespaced
43
+ `/gdd:audit`. `{{model}}` and `{{ask_instruction}}` follow the pattern `your configured <Name> model` and
44
+ `ask <Name>` respectively (see `harness-configs.cjs` for exact strings). Adding a 15th harness is one new
45
+ entry in `scripts/lib/manifest/harnesses.json` plus an optional row in `harness-configs.cjs`.
46
+
47
+ ## Escaping a literal placeholder
48
+
49
+ To emit a literal `{{command_prefix}}` (or any `{{...}}`) without substitution, backslash-escape the
50
+ opening braces: write `\{{command_prefix}}`. The factory strips the backslash and leaves the braces
51
+ untouched. Use this only when documenting the placeholder syntax itself.
52
+
53
+ ## Harness-only blocks
54
+
55
+ To include a span of content for specific harnesses only, wrap it in an HTML-comment fence (it survives
56
+ Markdown and is easy to grep):
57
+
58
+ ```
59
+ <!-- harness-only: cursor,codex -->
60
+ This sentence ships only in the Cursor and Codex bundles.
61
+ <!-- /harness-only -->
62
+ ```
63
+
64
+ The block body is kept iff the compiling harness's `id` appears in the comma list; otherwise it is removed
65
+ entirely. Full per-harness content forking beyond placeholders and these blocks is intentionally out of
66
+ scope (a maintenance trap) — see the Phase 42 CONTEXT.
67
+
68
+ ## Validation
69
+
70
+ `test/suite/phase-42-placeholders.test.cjs` asserts that every placeholder actually used across
71
+ `source/skills/` is documented in this file, and that `source/skills/` mirrors the `skills/` skill count.
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+ // Phase 42 — pure transformer factory (impeccable-style). compile(text, config) => string.
3
+ // Pure: no filesystem, no I/O, no module imports. The orchestrator (scripts/build-skills.cjs)
4
+ // does all reading/writing; this layer only transforms a single skill body for one harness config.
5
+ //
6
+ // Transform order (deterministic):
7
+ // 1. harness-only blocks <!-- harness-only: a,b -->BODY<!-- /harness-only --> kept iff config.id in {a,b}
8
+ // 2. protect escapes \{{ x }} -> sentinel (emit literal {{ x }}, never substituted)
9
+ // 3. substitute {{command_prefix}} {{model}} {{config_file}} {{ask_instruction}}
10
+ // 4. restore escapes sentinel -> {{ x }}
11
+ //
12
+ // D-01: for the Claude config (command_prefix === '/gdd:') this is the exact inverse of the migration
13
+ // (/gdd: -> {{command_prefix}}), so compile(source, claude) reproduces skills/ byte-for-byte.
14
+
15
+ const PLACEHOLDERS = ['command_prefix', 'model', 'config_file', 'ask_instruction'];
16
+ const ESCAPE_OPEN = '@@GDD_ESC_';
17
+ const ESCAPE_CLOSE = '@@';
18
+
19
+ function stripHarnessOnly(text, id) {
20
+ const re = /<!--\s*harness-only:\s*([^>]*?)\s*-->([\s\S]*?)<!--\s*\/harness-only\s*-->/g;
21
+ return text.replace(re, (_m, list, body) => {
22
+ const ids = String(list).split(',').map((s) => s.trim()).filter(Boolean);
23
+ return ids.includes(id) ? body : '';
24
+ });
25
+ }
26
+
27
+ function compile(text, config) {
28
+ if (typeof text !== 'string') throw new TypeError('compile: text must be a string');
29
+ if (!config || typeof config !== 'object') throw new TypeError('compile: config object is required');
30
+
31
+ let out = stripHarnessOnly(text, config.id);
32
+
33
+ // 2. protect \{{ ... }} escapes
34
+ const escapes = [];
35
+ out = out.replace(/\\\{\{([\s\S]*?)\}\}/g, (_m, inner) => {
36
+ escapes.push('{{' + inner + '}}');
37
+ return ESCAPE_OPEN + (escapes.length - 1) + ESCAPE_CLOSE;
38
+ });
39
+
40
+ // 3. substitute placeholders
41
+ for (const key of PLACEHOLDERS) {
42
+ if (config[key] == null) continue;
43
+ out = out.split('{{' + key + '}}').join(String(config[key]));
44
+ }
45
+
46
+ // 4. restore escapes as literal {{ ... }}
47
+ out = out.replace(/@@GDD_ESC_(\d+)@@/g, (_m, i) => escapes[Number(i)]);
48
+ return out;
49
+ }
50
+
51
+ /** Placeholders genuinely substituted (escaped \{{...}} excluded) — used by the catalogue test. */
52
+ function placeholdersUsed(text) {
53
+ if (typeof text !== 'string') return new Set();
54
+ const scrubbed = String(text).replace(/\\\{\{[\s\S]*?\}\}/g, '');
55
+ const used = new Set();
56
+ const re = /\{\{([a-z_]+)\}\}/g;
57
+ let m;
58
+ while ((m = re.exec(scrubbed)) !== null) used.add(m[1]);
59
+ return used;
60
+ }
61
+
62
+ module.exports = { compile, placeholdersUsed, stripHarnessOnly, PLACEHOLDERS };
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+ // Phase 42 — per-harness build/compile config. The base record (id / name / configDir) comes from the
3
+ // Phase 41.5 manifest SoT (scripts/lib/manifest/harnesses.json); this layer adds the four placeholder
4
+ // substitutions + frontmatter-strip rules + the dist bundle slug. Adding a 15th harness = one manifest
5
+ // entry (+ an optional OVERRIDES row); everything else falls back to DEFAULTS.
6
+ //
7
+ // command_prefix is the ONLY field that affects the byte-identical Claude round-trip: it MUST be '/gdd:'
8
+ // for claude (the migration replaced literal '/gdd:' with {{command_prefix}}; the Claude compile reverses it).
9
+
10
+ const { readHarnesses } = require('../manifest/index.cjs');
11
+
12
+ const DEFAULTS = {
13
+ command_prefix: '/gdd:',
14
+ config_file: 'config.json',
15
+ model: 'your configured model',
16
+ ask_instruction: 'ask your agent',
17
+ stripFrontmatter: [],
18
+ };
19
+
20
+ // Per-harness overrides. Only `codex` diverges on command_prefix (its custom-prompt grammar is flat,
21
+ // `/gdd-audit`, not the namespaced `/gdd:audit`); the rest share Claude's slash-command namespace.
22
+ const OVERRIDES = {
23
+ claude: { bundleSlug: 'claude-code', command_prefix: '/gdd:', config_file: '.claude/settings.json', model: 'your configured Claude model', ask_instruction: 'ask Claude Code' },
24
+ codex: { command_prefix: '/gdd-', config_file: '.codex/config.toml', model: 'your configured Codex model', ask_instruction: 'ask Codex' },
25
+ gemini: { command_prefix: '/gdd:', config_file: '.gemini/settings.json', model: 'your configured Gemini model', ask_instruction: 'ask Gemini' },
26
+ qwen: { command_prefix: '/gdd:', config_file: '.qwen/settings.json', model: 'your configured Qwen model', ask_instruction: 'ask Qwen Code' },
27
+ kilo: { command_prefix: '/gdd:', config_file: '.kilo/config.json', model: 'your configured Kilo model', ask_instruction: 'ask Kilo Code' },
28
+ copilot: { command_prefix: '/gdd:', config_file: '.copilot/config.json', model: 'your configured Copilot model', ask_instruction: 'ask Copilot' },
29
+ cursor: { command_prefix: '/gdd:', config_file: '.cursor/settings.json', model: 'your configured Cursor model', ask_instruction: 'ask Cursor' },
30
+ windsurf: { command_prefix: '/gdd:', config_file: '.windsurf/settings.json', model: 'your configured Windsurf model', ask_instruction: 'ask Cascade' },
31
+ antigravity: { command_prefix: '/gdd:', config_file: '.antigravity/config.json', model: 'your configured Antigravity model', ask_instruction: 'ask Antigravity' },
32
+ augment: { command_prefix: '/gdd:', config_file: '.augment/config.json', model: 'your configured Augment model', ask_instruction: 'ask Augment' },
33
+ trae: { command_prefix: '/gdd:', config_file: '.trae/config.json', model: 'your configured Trae model', ask_instruction: 'ask Trae' },
34
+ codebuddy: { command_prefix: '/gdd:', config_file: '.codebuddy/config.json', model: 'your configured CodeBuddy model', ask_instruction: 'ask CodeBuddy' },
35
+ cline: { command_prefix: '/gdd:', config_file: '.cline/config.json', model: 'your configured Cline model', ask_instruction: 'ask Cline' },
36
+ opencode: { command_prefix: '/gdd:', config_file: '.opencode/config.json', model: 'your configured OpenCode model', ask_instruction: 'ask OpenCode' },
37
+ };
38
+
39
+ function buildConfigs(opts) {
40
+ const { harnesses } = readHarnesses(opts);
41
+ return harnesses.map((h) => {
42
+ const ov = OVERRIDES[h.id] || {};
43
+ return {
44
+ id: h.id,
45
+ name: h.name,
46
+ configDir: h.config_dir,
47
+ bundleSlug: ov.bundleSlug || h.id,
48
+ ...DEFAULTS,
49
+ ...ov,
50
+ };
51
+ });
52
+ }
53
+
54
+ const CONFIGS = buildConfigs();
55
+
56
+ function byId(id) {
57
+ return CONFIGS.find((c) => c.id === id) || null;
58
+ }
59
+
60
+ function claude() {
61
+ return byId('claude');
62
+ }
63
+
64
+ module.exports = { CONFIGS, byId, claude, buildConfigs, DEFAULTS };
@@ -0,0 +1,46 @@
1
+ # `scripts/lib/manifest/` — Cross-Phase Source-of-Truth Root
2
+
3
+ Phase 41.5. This directory is the **single source-of-truth root** for roadmap-wide cross-phase
4
+ metadata. Before it existed, Phase 42 / 44 / 45 / 47 each scoped its own "single source" in a different
5
+ corner (`scripts/lib/build/`, `scripts/lib/prose/`, `reference/harness-matrix.json`,
6
+ `scripts/skill-metadata.json`) — four formats, four schemas, four CI drift gates. This is the one root,
7
+ one schema directory, one validator.
8
+
9
+ ## Files
10
+
11
+ | File | Owner / writer | Read by |
12
+ |---|---|---|
13
+ | `harnesses.json` (+ `harnesses.cjs` view) | Phase 41.5 seed → **42** (build config) + **45** (capability matrix) extend it | the build pipeline, the harness matrix, the multi-harness compiler |
14
+ | `skills.json` | Phase 41.5 seed (live `skills/` names) → **47** enriches (aliases, pin, description budget) | skill-UX tooling |
15
+ | `prose-denylist.json` | Phase 41.5 seed → **43** + **44** | `scripts/lint-prose.cjs` (the editorial gate) |
16
+ | `schemas/*.schema.json` | one JSON Schema per manifest file | `scripts/validate-manifest.cjs` |
17
+ | `loader.cjs` | Phase 41.5 | every consumer |
18
+ | `index.cjs` | Phase 41.5 | every consumer (`readHarnesses` / `readSkills` / `readProseDenylist`) |
19
+
20
+ ## Contract
21
+
22
+ - **One canonical record, multiple views.** `harnesses.json` is the canonical harness record; Phase 42's
23
+ build config and Phase 45's capability matrix are *views* of it, not separate files. Consumers extend
24
+ the records with new fields (every schema sets `additionalProperties: true`) — they do not fork the file.
25
+ - **Read through `index.cjs`.** Never `require` a manifest JSON directly. `readHarnesses()` /
26
+ `readSkills()` / `readProseDenylist()` return a well-shaped object even when the file is absent.
27
+ - **Graceful out-of-order shipping.** `loader.cjs` returns an empty manifest + a one-line warning when a
28
+ file is missing or unparseable — a phase that ships before its data exists never crashes. (D-03)
29
+ - **mtime cache.** A manifest is re-read only when its file mtime changes. (D-02)
30
+ - **One CI gate.** `scripts/validate-manifest.cjs` (`npm run validate:manifest`) ajv-validates every
31
+ manifest against its schema. This is the only drift gate — 43/44/45/47 do NOT add their own.
32
+
33
+ ## Migration note (for Phase 42 / 43 / 44 / 45 / 47 plan-phases)
34
+
35
+ When you plan your phase, **target this root from day one**. Do not create
36
+ `scripts/lib/build/harness-configs.cjs`, `scripts/lib/prose/denylist.json`,
37
+ `reference/harness-matrix.json`, or `scripts/skill-metadata.json` as new SoTs — extend
38
+ `manifest/harnesses.json` / `manifest/prose-denylist.json` / `manifest/skills.json` instead, read them
39
+ via `index.cjs`, and let `validate-manifest.cjs` be your drift gate. (Phase 46's SoT-consolidation
40
+ paragraph delegates here.)
41
+
42
+ ## Boundaries
43
+
44
+ This root holds **structured cross-phase data** (JSON + typed readers). It does not unify with the
45
+ `reference/*.md` prose registries (a different consumer pattern), and it does not auto-generate
46
+ frontmatter (Phase 46 territory).
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+ // Phase 41.5 — typed re-export of harnesses.json (the .cjs view per D-01).
3
+ module.exports = require('./harnesses.json').harnesses;
@@ -0,0 +1,91 @@
1
+ {
2
+ "schema_version": 1,
3
+ "generated_at": null,
4
+ "note": "Canonical cross-phase harness record (Phase 41.5 SoT root). Phase 42 adds build/compile config; Phase 45 adds the capability matrix — both as views of this one record. Model tiers live in reference/runtime-models.md.",
5
+ "harnesses": [
6
+ {
7
+ "id": "claude",
8
+ "name": "Claude Code",
9
+ "config_dir": ".claude",
10
+ "runtime_models_ref": "reference/runtime-models.md#claude"
11
+ },
12
+ {
13
+ "id": "codex",
14
+ "name": "OpenAI Codex CLI",
15
+ "config_dir": ".codex",
16
+ "runtime_models_ref": "reference/runtime-models.md#codex"
17
+ },
18
+ {
19
+ "id": "gemini",
20
+ "name": "Gemini CLI",
21
+ "config_dir": ".gemini",
22
+ "runtime_models_ref": "reference/runtime-models.md#gemini"
23
+ },
24
+ {
25
+ "id": "qwen",
26
+ "name": "Qwen Code",
27
+ "config_dir": ".qwen",
28
+ "runtime_models_ref": "reference/runtime-models.md#qwen"
29
+ },
30
+ {
31
+ "id": "kilo",
32
+ "name": "Kilo Code",
33
+ "config_dir": ".kilo",
34
+ "runtime_models_ref": "reference/runtime-models.md#kilo"
35
+ },
36
+ {
37
+ "id": "copilot",
38
+ "name": "GitHub Copilot CLI",
39
+ "config_dir": ".copilot",
40
+ "runtime_models_ref": "reference/runtime-models.md#copilot"
41
+ },
42
+ {
43
+ "id": "cursor",
44
+ "name": "Cursor",
45
+ "config_dir": ".cursor",
46
+ "runtime_models_ref": "reference/runtime-models.md#cursor"
47
+ },
48
+ {
49
+ "id": "windsurf",
50
+ "name": "Windsurf (Cascade)",
51
+ "config_dir": ".windsurf",
52
+ "runtime_models_ref": "reference/runtime-models.md#windsurf"
53
+ },
54
+ {
55
+ "id": "antigravity",
56
+ "name": "Antigravity",
57
+ "config_dir": ".antigravity",
58
+ "runtime_models_ref": "reference/runtime-models.md#antigravity"
59
+ },
60
+ {
61
+ "id": "augment",
62
+ "name": "Augment",
63
+ "config_dir": ".augment",
64
+ "runtime_models_ref": "reference/runtime-models.md#augment"
65
+ },
66
+ {
67
+ "id": "trae",
68
+ "name": "Trae",
69
+ "config_dir": ".trae",
70
+ "runtime_models_ref": "reference/runtime-models.md#trae"
71
+ },
72
+ {
73
+ "id": "codebuddy",
74
+ "name": "CodeBuddy",
75
+ "config_dir": ".codebuddy",
76
+ "runtime_models_ref": "reference/runtime-models.md#codebuddy"
77
+ },
78
+ {
79
+ "id": "cline",
80
+ "name": "Cline",
81
+ "config_dir": ".cline",
82
+ "runtime_models_ref": "reference/runtime-models.md#cline"
83
+ },
84
+ {
85
+ "id": "opencode",
86
+ "name": "OpenCode",
87
+ "config_dir": ".opencode",
88
+ "runtime_models_ref": "reference/runtime-models.md#opencode"
89
+ }
90
+ ]
91
+ }
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+ // Phase 41.5 — manifest/index.cjs — typed readers over the shared loader. Every cross-phase consumer
3
+ // imports from here: `const { readHarnesses } = require('scripts/lib/manifest')`. Each reader returns
4
+ // a well-shaped object even when the underlying file is absent (graceful empty fallback per loader D-03).
5
+
6
+ const loader = require('./loader.cjs');
7
+
8
+ /** @returns {{ schema_version: number, generated_at: string|null, harnesses: object[] }} */
9
+ function readHarnesses(opts) {
10
+ return loader.load('harnesses', { ...opts, fallback: { schema_version: 1, generated_at: null, harnesses: [] } });
11
+ }
12
+
13
+ /** @returns {{ schema_version: number, skills: object[] }} */
14
+ function readSkills(opts) {
15
+ return loader.load('skills', { ...opts, fallback: { schema_version: 1, skills: [] } });
16
+ }
17
+
18
+ /** @returns {{ schema_version: number, tells: object[] }} */
19
+ function readProseDenylist(opts) {
20
+ return loader.load('prose-denylist', { ...opts, fallback: { schema_version: 1, tells: [] } });
21
+ }
22
+
23
+ module.exports = {
24
+ readHarnesses, readSkills, readProseDenylist,
25
+ reset: loader.reset, MANIFEST_DIR: loader.MANIFEST_DIR,
26
+ };
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+ // Phase 41.5 — manifest/loader.cjs — the ONE shared reader for every cross-phase SoT manifest under
3
+ // scripts/lib/manifest/. Phases 42 (harnesses), 43/44 (prose denylist), 45 (capability matrix), and
4
+ // 47 (skill metadata) all read through here instead of hand-rolling their own loader + drift gate.
5
+ //
6
+ // Graceful (D-03): a missing or unparseable manifest returns the caller's `fallback` (an empty
7
+ // manifest) plus a one-line stderr warning — NEVER a throw — so a phase shipping before its data file
8
+ // exists does not crash. File-mtime cache (D-02): a file is re-read only when its mtime changes.
9
+ //
10
+ // Dep-free (no ajv here — validation lives in scripts/validate-manifest.cjs, the CI gate). No require
11
+ // of any third-party module.
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+
16
+ const MANIFEST_DIR = __dirname;
17
+ const _cache = new Map(); // absPath -> { mtimeMs, data }
18
+
19
+ /** Clear the in-process cache (tests). */
20
+ function reset() { _cache.clear(); }
21
+
22
+ /**
23
+ * Load a manifest JSON by base name (no extension).
24
+ * @param {string} name e.g. 'harnesses' | 'skills' | 'prose-denylist'
25
+ * @param {{ dir?: string, fallback?: any, quiet?: boolean }} [opts]
26
+ * @returns the parsed manifest, or `fallback` (default {}) on missing/parse-error.
27
+ */
28
+ function load(name, opts) {
29
+ const o = opts || {};
30
+ const dir = o.dir || MANIFEST_DIR;
31
+ const fallback = Object.prototype.hasOwnProperty.call(o, 'fallback') ? o.fallback : {};
32
+ const abs = path.join(dir, `${name}.json`);
33
+
34
+ let stat;
35
+ try { stat = fs.statSync(abs); } catch {
36
+ if (!o.quiet) process.stderr.write(`manifest: ${name}.json not found — using empty fallback (a consumer phase may not have shipped its data yet)\n`);
37
+ return fallback;
38
+ }
39
+ const cached = _cache.get(abs);
40
+ if (cached && cached.mtimeMs === stat.mtimeMs) return cached.data;
41
+ try {
42
+ const data = JSON.parse(fs.readFileSync(abs, 'utf8'));
43
+ _cache.set(abs, { mtimeMs: stat.mtimeMs, data });
44
+ return data;
45
+ } catch (e) {
46
+ if (!o.quiet) process.stderr.write(`manifest: ${name}.json parse error (${e.message}) — using empty fallback\n`);
47
+ return fallback;
48
+ }
49
+ }
50
+
51
+ module.exports = { load, reset, MANIFEST_DIR };