@hegemonart/get-design-done 1.28.0 → 1.28.5
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +78 -0
- package/SKILL.md +1 -1
- package/hooks/gdd-decision-injector.js +149 -3
- package/package.json +1 -1
- package/reference/adr-format.md +96 -0
- package/reference/apply-reflections-procedure.md +68 -0
- package/reference/architecture-vocabulary.md +102 -0
- package/reference/cache-policy.md +126 -0
- package/reference/compare-rubric.md +171 -0
- package/reference/connections-onboarding.md +417 -0
- package/reference/context-md-format.md +106 -0
- package/reference/darkmode-audit-procedure.md +258 -0
- package/reference/debug-feedback-loops.md +119 -0
- package/reference/design-procedure.md +304 -0
- package/reference/discover-procedure.md +204 -0
- package/reference/explore-procedure.md +267 -0
- package/reference/health-mcp-detection.md +44 -0
- package/reference/health-skill-length-report.md +69 -0
- package/reference/heuristics.md +84 -0
- package/reference/milestone-completeness-rubric.md +87 -0
- package/reference/peer-cli-protocol.md +161 -0
- package/reference/plan-procedure.md +278 -0
- package/reference/registry.json +169 -1
- package/reference/registry.schema.json +1 -1
- package/reference/router-rules.md +84 -0
- package/reference/scan-procedure.md +731 -0
- package/reference/shared-preamble.md +78 -6
- package/reference/skill-authoring-contract.md +128 -0
- package/reference/start-procedure.md +115 -0
- package/reference/style-doc-procedure.md +150 -0
- package/reference/threat-modeling.md +101 -0
- package/reference/verify-procedure.md +512 -0
- package/scripts/validate-skill-length.cjs +283 -0
- package/skills/add-backlog/SKILL.md +1 -0
- package/skills/analyze-dependencies/SKILL.md +33 -122
- package/skills/apply-reflections/SKILL.md +1 -40
- package/skills/audit/SKILL.md +3 -1
- package/skills/bandit-status/SKILL.md +31 -66
- package/skills/benchmark/SKILL.md +15 -55
- package/skills/brief/SKILL.md +12 -1
- package/skills/cache-manager/SKILL.md +3 -57
- package/skills/check-update/SKILL.md +38 -75
- package/skills/compare/SKILL.md +29 -269
- package/skills/complete-cycle/SKILL.md +1 -1
- package/skills/connections/SKILL.md +21 -427
- package/skills/continue/SKILL.md +1 -0
- package/skills/darkmode/SKILL.md +32 -287
- package/skills/debug/SKILL.md +11 -8
- package/skills/design/SKILL.md +27 -245
- package/skills/discover/SKILL.md +26 -133
- package/skills/discuss/SKILL.md +18 -2
- package/skills/explore/SKILL.md +40 -205
- package/skills/fast/SKILL.md +1 -0
- package/skills/figma-write/SKILL.md +2 -2
- package/skills/health/SKILL.md +11 -33
- package/skills/help/SKILL.md +1 -0
- package/skills/list-assumptions/SKILL.md +1 -0
- package/skills/map/SKILL.md +8 -31
- package/skills/new-cycle/SKILL.md +3 -1
- package/skills/next/SKILL.md +1 -0
- package/skills/note/SKILL.md +1 -0
- package/skills/optimize/SKILL.md +21 -44
- package/skills/pause/SKILL.md +1 -0
- package/skills/peer-cli-add/SKILL.md +26 -108
- package/skills/peer-cli-customize/SKILL.md +22 -42
- package/skills/peers/SKILL.md +33 -57
- package/skills/plan/SKILL.md +33 -220
- package/skills/plant-seed/SKILL.md +1 -0
- package/skills/pr-branch/SKILL.md +1 -0
- package/skills/progress/SKILL.md +1 -7
- package/skills/quality-gate/SKILL.md +34 -166
- package/skills/quick/SKILL.md +1 -0
- package/skills/reapply-patches/SKILL.md +1 -0
- package/skills/recall/SKILL.md +1 -0
- package/skills/resume/SKILL.md +1 -0
- package/skills/review-backlog/SKILL.md +1 -0
- package/skills/router/SKILL.md +3 -59
- package/skills/scan/SKILL.md +36 -675
- package/skills/settings/SKILL.md +1 -0
- package/skills/ship/SKILL.md +1 -0
- package/skills/sketch/SKILL.md +1 -1
- package/skills/sketch-wrap-up/SKILL.md +13 -54
- package/skills/spike/SKILL.md +1 -1
- package/skills/spike-wrap-up/SKILL.md +12 -46
- package/skills/start/SKILL.md +13 -112
- package/skills/stats/SKILL.md +1 -0
- package/skills/style/SKILL.md +18 -140
- package/skills/synthesize/SKILL.md +1 -0
- package/skills/timeline/SKILL.md +1 -0
- package/skills/todo/SKILL.md +1 -0
- package/skills/turn-closeout/SKILL.md +36 -56
- package/skills/undo/SKILL.md +1 -0
- package/skills/update/SKILL.md +1 -0
- package/skills/verify/SKILL.md +42 -457
- package/skills/warm-cache/SKILL.md +3 -35
- package/skills/zoom-out/SKILL.md +26 -0
|
@@ -9,88 +9,69 @@ tools: Read, Bash
|
|
|
9
9
|
|
|
10
10
|
## Role
|
|
11
11
|
|
|
12
|
-
You are a deterministic, read-only diagnostic skill. You do not spawn agents and do not modify the
|
|
13
|
-
|
|
14
|
-
Strictly read-only per Phase 27.5 D-11. To reset the posterior, use `/gdd:bandit-reset` from Phase 23.5.
|
|
12
|
+
You are a deterministic, read-only diagnostic skill. You do not spawn agents and do not modify the posterior. You read `.design/telemetry/posterior.json` (path declared by `scripts/lib/bandit-router.cjs`'s `DEFAULT_POSTERIOR_PATH`), aggregate per-`(agent, bin, delegate, tier)` arm state, and emit a single Markdown table. Read-only per Phase 27.5 D-11 — to reset, use `/gdd:bandit-reset` (Phase 23.5). See `./reference/bandit-integration.md` for setup, interpretation, and convergence guidance.
|
|
15
13
|
|
|
16
14
|
## Invocation Contract
|
|
17
15
|
|
|
18
|
-
- **Input**: none.
|
|
19
|
-
- **Output**: a Markdown bandit-status table to stdout.
|
|
16
|
+
- **Input**: none.
|
|
17
|
+
- **Output**: a Markdown bandit-status table to stdout. The table is the entire output.
|
|
20
18
|
|
|
21
19
|
## Procedure
|
|
22
20
|
|
|
23
21
|
### 1. Locate the posterior file
|
|
24
22
|
|
|
25
|
-
Read `.design/telemetry/posterior.json`.
|
|
26
|
-
|
|
27
|
-
- Emit the empty-state message:
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
## Bandit Posterior Snapshot
|
|
31
|
-
|
|
32
|
-
No posterior data yet — run a few pipeline cycles with `adaptive_mode: full` first.
|
|
33
|
-
|
|
34
|
-
No posterior data found at `.design/telemetry/posterior.json`.
|
|
23
|
+
Read `.design/telemetry/posterior.json`. Missing → emit empty-state message:
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- No spawns have fired since Phase 27.5 wiring landed.
|
|
39
|
-
- Posterior was cleared via `/gdd:bandit-reset`.
|
|
25
|
+
```
|
|
26
|
+
## Bandit Posterior Snapshot
|
|
40
27
|
|
|
41
|
-
|
|
42
|
-
```
|
|
28
|
+
No posterior data yet — run a few pipeline cycles with `adaptive_mode: full` first.
|
|
43
29
|
|
|
44
|
-
|
|
30
|
+
No posterior data found at `.design/telemetry/posterior.json`.
|
|
45
31
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
Possible reasons:
|
|
33
|
+
- `adaptive_mode` is `static` or `hedge` (bandit silent — see `.design/budget.json`).
|
|
34
|
+
- No spawns have fired since Phase 27.5 wiring landed.
|
|
35
|
+
- Posterior was cleared via `/gdd:bandit-reset`.
|
|
49
36
|
|
|
37
|
+
See `reference/bandit-integration.md` for setup guidance.
|
|
50
38
|
```
|
|
51
|
-
## Bandit Posterior Snapshot
|
|
52
39
|
|
|
53
|
-
|
|
40
|
+
Skip to Section 4 (Record). Parse failure (truncated/corrupted) → emit `Posterior file exists but is unparseable. Run /gdd:bandit-reset to start fresh, or restore from a backup.`
|
|
54
41
|
|
|
55
|
-
|
|
56
|
-
```
|
|
42
|
+
### 2. Parse the posterior
|
|
57
43
|
|
|
58
|
-
|
|
44
|
+
Schema:
|
|
59
45
|
|
|
60
46
|
```json
|
|
61
47
|
{
|
|
62
48
|
"schema_version": "1.0.0",
|
|
63
|
-
"generated_at": "<ISO
|
|
64
|
-
"arms": [
|
|
65
|
-
{ "agent": "...", "bin": "...", "tier": "...", "delegate": "...", "alpha": N, "beta": N, "last_used": "...", "count": N }
|
|
66
|
-
]
|
|
49
|
+
"generated_at": "<ISO>",
|
|
50
|
+
"arms": [{ "agent": "...", "bin": "...", "tier": "...", "delegate": "...", "alpha": N, "beta": N, "last_used": "...", "count": N }]
|
|
67
51
|
}
|
|
68
52
|
```
|
|
69
53
|
|
|
70
|
-
The `delegate` field is optional —
|
|
54
|
+
The `delegate` field is optional — absent = Phase 23.5 legacy slice (rendered as `-` in the table).
|
|
71
55
|
|
|
72
56
|
### 3. Render the table
|
|
73
57
|
|
|
74
|
-
Compute per arm:
|
|
75
|
-
|
|
76
|
-
- `mean = alpha / (alpha + beta)` (rounded to 3 decimals)
|
|
77
|
-
- `stddev = sqrt(alpha * beta / ((alpha + beta)^2 * (alpha + beta + 1)))` (rounded to 3 decimals)
|
|
58
|
+
Compute per arm: `mean = alpha / (alpha + beta)` (3 decimals), `stddev = sqrt(alpha*beta / ((alpha+beta)^2 * (alpha+beta+1)))` (3 decimals).
|
|
78
59
|
|
|
79
|
-
Sort
|
|
60
|
+
Sort by `(agent ASC, bin ASC, delegate ASC where '-' first, tier ASC opus<sonnet<haiku, last_used DESC)`. Group by agent for readability.
|
|
80
61
|
|
|
81
62
|
Emit:
|
|
82
63
|
|
|
83
64
|
```
|
|
84
65
|
## Bandit Posterior Snapshot
|
|
85
66
|
|
|
86
|
-
Per-(agent, bin, delegate, tier) posterior state. Read-only — to reset
|
|
67
|
+
Per-(agent, bin, delegate, tier) posterior state. Read-only — to reset use `/gdd:bandit-reset` (Phase 23.5).
|
|
87
68
|
|
|
88
69
|
Posterior file: `.design/telemetry/posterior.json` (last updated: <generated_at>)
|
|
89
70
|
Total arms: <count>
|
|
90
71
|
|
|
91
|
-
| Agent
|
|
92
|
-
|
|
93
|
-
|
|
|
72
|
+
| Agent | Bin | Delegate | Tier | Alpha | Beta | Mean | Stddev | Count | Last Used |
|
|
73
|
+
|-------|-----|----------|------|-------|------|------|--------|-------|-----------|
|
|
74
|
+
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
|
|
94
75
|
|
|
95
76
|
> Mean = alpha / (alpha + beta). Stddev = sqrt(alpha*beta / ((alpha+beta)^2 * (alpha+beta+1))).
|
|
96
77
|
> Delegate '-' = Phase 23.5 legacy slice (equivalent to 'none').
|
|
@@ -98,32 +79,16 @@ Total arms: <count>
|
|
|
98
79
|
> Read-only — use `/gdd:bandit-reset` to clear posterior state.
|
|
99
80
|
```
|
|
100
81
|
|
|
101
|
-
|
|
82
|
+
Precision: alpha/beta 2 decimals; mean/stddev 3 decimals; count integer; `last_used` truncated to minute (`YYYY-MM-DDTHH:MM`); null `last_used` renders `-`.
|
|
102
83
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
After the table, surface a brief best-arm summary per `(agent, bin)` slice — for each unique `(agent, bin)` pair, identify the arm with the highest `mean` (tie-broken by `count` descending) and display it as the "best-arm" recommendation. This helps the operator answer "why did the bandit pick tier X?" at a glance.
|
|
84
|
+
After the table, surface a per-`(agent, bin)` best-arm summary: for each unique pair, identify highest-mean arm (tie-broken by `count` DESC) — answers "why did the bandit pick tier X?" at a glance.
|
|
106
85
|
|
|
107
86
|
### 4. Record
|
|
108
87
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{"skill": "gdd-bandit-status", "ts": "<ISO timestamp>", "arms_seen": <count>, "posterior_present": <bool>}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
The skill writes ONLY to `.design/skill-records.jsonl` for telemetry purposes. It never touches `.design/telemetry/posterior.json`.
|
|
88
|
+
Append one JSONL line to `.design/skill-records.jsonl`: `{"skill":"gdd-bandit-status","ts":"<ISO>","arms_seen":<count>,"posterior_present":<bool>}`. Skill writes ONLY to skill-records.jsonl (telemetry); never touches the posterior.
|
|
116
89
|
|
|
117
90
|
## Cross-references
|
|
118
91
|
|
|
119
|
-
-
|
|
120
|
-
- `scripts/lib/bandit-router
|
|
121
|
-
- `hooks/budget-enforcer.ts` (
|
|
122
|
-
- `scripts/lib/session-runner/index.ts` (Phase 27.5-03) — outcome recording site.
|
|
123
|
-
- `scripts/lib/bandit-arbitrage.cjs` (Phase 27.5-04) — automated stale-frontmatter analysis.
|
|
124
|
-
- `reference/bandit-integration.md` (Phase 27.5-06) — operator guide.
|
|
125
|
-
- `/gdd:bandit-reset` (Phase 23.5) — the ONLY surface that mutates the posterior.
|
|
126
|
-
|
|
127
|
-
## Record
|
|
128
|
-
|
|
129
|
-
See Section 4 above.
|
|
92
|
+
- `./reference/bandit-integration.md` — operator guide; interpretation patterns.
|
|
93
|
+
- `scripts/lib/bandit-router.cjs` (Phase 23.5) — posterior shape, `DEFAULT_POSTERIOR_PATH`, `loadPosterior()`.
|
|
94
|
+
- `scripts/lib/bandit-router/integration.cjs` (27.5-01), `hooks/budget-enforcer.ts` (27.5-02), `scripts/lib/session-runner/index.ts` (27.5-03), `scripts/lib/bandit-arbitrage.cjs` (27.5-04), `/gdd:bandit-reset` (Phase 23.5) — only surface that mutates the posterior.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gdd-benchmark
|
|
3
|
-
description: Harvest and synthesize per-component design benchmarks from 18 design systems
|
|
3
|
+
description: "Harvest and synthesize per-component design benchmarks from 18 design systems and produce canonical component specs at `reference/components/<name>.md`. Use when adding a new component spec, running a benchmark wave, listing corpus coverage, or refreshing a spec after a design-system version bump."
|
|
4
4
|
argument-hint: "<component> | --wave <N> | --list | --refresh <component>"
|
|
5
5
|
tools: Read, Write, Bash, Grep, Glob, Task, WebFetch
|
|
6
6
|
---
|
|
@@ -8,7 +8,9 @@ tools: Read, Write, Bash, Grep, Glob, Task, WebFetch
|
|
|
8
8
|
# /gdd:benchmark
|
|
9
9
|
|
|
10
10
|
Harvest per-component design knowledge from 18 design systems and synthesize canonical
|
|
11
|
-
specs at `reference/components/<name>.md`.
|
|
11
|
+
specs at `reference/components/<name>.md`. The 18-source corpus + fallback chain lives in
|
|
12
|
+
`../../connections/design-corpora.md`. Per-skill output discipline + completion-marker
|
|
13
|
+
conventions are at `../../reference/shared-preamble.md#output-contract-reminders`.
|
|
12
14
|
|
|
13
15
|
## Invocation Modes
|
|
14
16
|
|
|
@@ -21,49 +23,17 @@ specs at `reference/components/<name>.md`.
|
|
|
21
23
|
|
|
22
24
|
## Single-Component Flow (`/gdd:benchmark <component>`)
|
|
23
25
|
|
|
24
|
-
1. **Check if spec exists** — `Glob("reference/components/<component>.md")`.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Task("component-benchmark-harvester", """
|
|
30
|
-
<required_reading>
|
|
31
|
-
@connections/design-corpora.md
|
|
32
|
-
</required_reading>
|
|
33
|
-
|
|
34
|
-
Harvest design-system excerpts for component: <component>
|
|
35
|
-
Emit raw harvest to: .planning/benchmarks/raw/<component>.md
|
|
36
|
-
Consume any relevant content from: .planning/research/impeccable-salvage/
|
|
37
|
-
|
|
38
|
-
Acceptance: .planning/benchmarks/raw/<component>.md exists with ≥4 source sections.
|
|
39
|
-
""")
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
3. **Synthesize** — spawn `component-benchmark-synthesizer` with:
|
|
43
|
-
```
|
|
44
|
-
Task("component-benchmark-synthesizer", """
|
|
45
|
-
<required_reading>
|
|
46
|
-
@.planning/benchmarks/raw/<component>.md
|
|
47
|
-
@reference/components/TEMPLATE.md
|
|
48
|
-
@reference/anti-patterns.md
|
|
49
|
-
</required_reading>
|
|
50
|
-
|
|
51
|
-
Synthesize the raw harvest into a canonical spec.
|
|
52
|
-
Output: reference/components/<component>.md
|
|
53
|
-
Update: reference/components/README.md (add entry in correct category)
|
|
54
|
-
|
|
55
|
-
Acceptance: spec exists, ≤350 lines, cites ≥4 systems, has TEMPLATE.md sections,
|
|
56
|
-
WAI-ARIA keyboard contract present, failing-example block present.
|
|
57
|
-
""")
|
|
58
|
-
```
|
|
26
|
+
1. **Check if spec exists** — `Glob("reference/components/<component>.md")`. If found and `--refresh` was not passed, confirm before overwriting.
|
|
27
|
+
|
|
28
|
+
2. **Harvest** — spawn `component-benchmark-harvester` with required-reading `@connections/design-corpora.md`, target component, raw-output path `.planning/benchmarks/raw/<component>.md`, and a salvage hint to `.planning/research/impeccable-salvage/`. Acceptance: raw harvest exists with ≥4 source sections.
|
|
29
|
+
|
|
30
|
+
3. **Synthesize** — spawn `component-benchmark-synthesizer` with required-reading `@.planning/benchmarks/raw/<component>.md`, `@reference/components/TEMPLATE.md`, `@reference/anti-patterns.md`. Output: `reference/components/<component>.md`. Also update `reference/components/README.md` (add entry in correct category). Acceptance: spec ≤350 lines, cites ≥4 systems, follows `TEMPLATE.md` sections, has a WAI-ARIA keyboard contract + a failing-example block.
|
|
59
31
|
|
|
60
32
|
4. **Report** — print spec path, line count, systems cited.
|
|
61
33
|
|
|
62
34
|
## Wave Mode (`/gdd:benchmark --wave <N>`)
|
|
63
35
|
|
|
64
|
-
Read the wave definition from `reference/components/README.md` and run each component
|
|
65
|
-
in the wave sequentially (not parallel — each harvest is network-bound and the raw files
|
|
66
|
-
are large).
|
|
36
|
+
Read the wave definition from `reference/components/README.md` and run each component sequentially (not parallel — each harvest is network-bound and the raw files are large).
|
|
67
37
|
|
|
68
38
|
| Wave | Components |
|
|
69
39
|
|------|-----------|
|
|
@@ -74,27 +44,15 @@ Print progress per component: `[N/total] harvesting <component>…`
|
|
|
74
44
|
|
|
75
45
|
## List Mode (`/gdd:benchmark --list`)
|
|
76
46
|
|
|
77
|
-
Read `reference/components/README.md` and diff against `reference/components/*.md` files.
|
|
78
|
-
Print a table:
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
Component Status Wave Lines
|
|
82
|
-
button ✓ 1 248
|
|
83
|
-
input ✓ 1 312
|
|
84
|
-
select-combobox ✓ 1 295
|
|
85
|
-
...
|
|
86
|
-
toast pending 3 —
|
|
87
|
-
```
|
|
47
|
+
Read `reference/components/README.md` and diff against `reference/components/*.md` files. Print a table with columns: Component, Status, Wave, Lines.
|
|
88
48
|
|
|
89
49
|
## Refresh Mode (`/gdd:benchmark --refresh <component>`)
|
|
90
50
|
|
|
91
|
-
Same as single-component flow but skips the "already exists" guard. Use when a design
|
|
92
|
-
system ships a breaking update to a component's spec.
|
|
51
|
+
Same as single-component flow but skips the "already exists" guard. Use when a design system ships a breaking update to a component's spec.
|
|
93
52
|
|
|
94
53
|
## Source List
|
|
95
54
|
|
|
96
|
-
|
|
97
|
-
fallback chain (canonical → archive.org → Refero MCP → Pinterest MCP).
|
|
55
|
+
`../../connections/design-corpora.md` — 18 design systems with canonical URLs, licensing, and fallback chain (canonical → archive.org → Refero MCP → Pinterest MCP).
|
|
98
56
|
|
|
99
57
|
## Output Artifacts
|
|
100
58
|
|
|
@@ -103,3 +61,5 @@ fallback chain (canonical → archive.org → Refero MCP → Pinterest MCP).
|
|
|
103
61
|
| `.planning/benchmarks/raw/<component>.md` | Raw multi-source harvest (input only) |
|
|
104
62
|
| `reference/components/<component>.md` | Canonical spec (distributed with plugin) |
|
|
105
63
|
| `reference/components/README.md` | Corpus index (updated by synthesizer) |
|
|
64
|
+
|
|
65
|
+
## BENCHMARK COMPLETE
|
package/skills/brief/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gdd-brief
|
|
3
|
-
description: "
|
|
3
|
+
description: "Stage 1 of 5 design intake that captures problem statement, audience, constraints, success metrics, and scope into .design/BRIEF.md, and bootstraps .design/STATE.md if missing. Use when starting a new design cycle and before /gdd:explore."
|
|
4
4
|
argument-hint: "[--re-brief to redo intake on existing project]"
|
|
5
5
|
tools: Read, Write, AskUserQuestion, mcp__gdd_state__frontmatter_update, mcp__gdd_state__set_status, mcp__gdd_state__update_progress, mcp__gdd_state__get
|
|
6
6
|
---
|
|
@@ -72,6 +72,17 @@ With `.design/STATE.md` seeded from the template:
|
|
|
72
72
|
|
|
73
73
|
Do NOT call `mcp__gdd_state__transition_stage` from brief — explore calls it on entry, keeping the transition atomic with the stage that owns the new state.
|
|
74
74
|
|
|
75
|
+
## Step 6 — Inline glossary (CONTEXT.md) + ADR pointer
|
|
76
|
+
|
|
77
|
+
When a fuzzy phrase is resolved or a new domain concept is named during the briefing
|
|
78
|
+
interview: write to `./CONTEXT.md` IMMEDIATELY per `./../../reference/context-md-format.md`
|
|
79
|
+
(H2 heading + body; lazy-create on first term; no batching). Glossary entries compound
|
|
80
|
+
across cycles — token savings + naming consistency.
|
|
81
|
+
|
|
82
|
+
Project-shaping decisions surfaced in briefing can be promoted to an ADR — see
|
|
83
|
+
`./../../reference/adr-format.md` for the 3-criteria gate (hard-to-reverse AND
|
|
84
|
+
surprising-without-context AND real-tradeoff). Routine choices stay in STATE.md.
|
|
85
|
+
|
|
75
86
|
## After Writing
|
|
76
87
|
|
|
77
88
|
```
|
|
@@ -3,6 +3,7 @@ name: gdd-cache-manager
|
|
|
3
3
|
description: "Maintains .design/cache-manifest.json for Layer B explicit cache per D-08. Computes deterministic SHA-256 input-hash from (agent-path + sorted-input-file-paths + input-content-hashes). On spawn: lookup key → return cached blob if within TTL, else miss. On completion: write result + TTL. Consulted by hooks/budget-enforcer.js before every Agent spawn."
|
|
4
4
|
user-invocable: false
|
|
5
5
|
tools: Read, Bash, Write
|
|
6
|
+
disable-model-invocation: true
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
# gdd-cache-manager
|
|
@@ -37,60 +38,7 @@ You are the deterministic cache-key computer and cache-manifest writer for the o
|
|
|
37
38
|
|
|
38
39
|
## Deterministic Input-Hash Algorithm
|
|
39
40
|
|
|
40
|
-
The canonical reference implementation (
|
|
41
|
-
|
|
42
|
-
```js
|
|
43
|
-
// Deterministic cache-key primitive (reference implementation)
|
|
44
|
-
// hash = SHA-256(
|
|
45
|
-
// agent_path + "\n" +
|
|
46
|
-
// sorted(input_file_paths).join("\n") + "\n" +
|
|
47
|
-
// sorted(input_file_paths)
|
|
48
|
-
// .map(p => sha256(readFileSync(p, "utf8")))
|
|
49
|
-
// .join("\n")
|
|
50
|
-
// )
|
|
51
|
-
const crypto = require('crypto');
|
|
52
|
-
const fs = require('fs');
|
|
53
|
-
|
|
54
|
-
function sha256Hex(s) {
|
|
55
|
-
return crypto.createHash('sha256').update(s, 'utf8').digest('hex');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function computeInputHash(agentPath, inputFilePaths) {
|
|
59
|
-
const sortedPaths = [...inputFilePaths].sort();
|
|
60
|
-
const contentHashes = sortedPaths.map(p => {
|
|
61
|
-
try { return sha256Hex(fs.readFileSync(p, 'utf8')); }
|
|
62
|
-
catch { return 'MISSING'; }
|
|
63
|
-
});
|
|
64
|
-
const canonical = [
|
|
65
|
-
agentPath,
|
|
66
|
-
sortedPaths.join('\n'),
|
|
67
|
-
contentHashes.join('\n')
|
|
68
|
-
].join('\n');
|
|
69
|
-
return sha256Hex(canonical);
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Notes for maintainers:
|
|
74
|
-
|
|
75
|
-
- **Sorted-unique paths** — ordering must be stable; caller is expected to de-duplicate. If the same path appears twice the hash still matches as long as caller pre-dedupes before invoking.
|
|
76
|
-
- **Missing file** — the string `MISSING` is used in place of the content hash so a missing dependency doesn't silently collide with an empty file (empty file's SHA-256 is `e3b0c44...`). Missing-file hashes naturally miss on the next read because the real file has a different content hash.
|
|
77
|
-
- **Agent-path** — agents changing their own body (role, tools, output contract) invalidate all their cache entries automatically because the agent file's content is not hashed; but the `agent_path` string is concatenated. Upgrading agents between versions naturally busts the cache only when the path changes. Plan 10.1-04 (shared preamble extraction) is expected to slightly adjust agent bodies — consumers should treat the first post-10.1 run as a full cache miss, which is the intended behavior.
|
|
78
|
-
|
|
79
|
-
## Manifest Shape
|
|
80
|
-
|
|
81
|
-
See `reference/config-schema.md` §.design/cache-manifest.json Schema (Phase 10.1) for the authoritative schema. Keyed object, flat SHA-256 hex keys. Example:
|
|
82
|
-
|
|
83
|
-
```json
|
|
84
|
-
{
|
|
85
|
-
"a3f1e...": {
|
|
86
|
-
"agent": "design-verifier",
|
|
87
|
-
"result": "<base64-or-path>",
|
|
88
|
-
"written_at": "2026-04-18T12:00:00Z",
|
|
89
|
-
"ttl_seconds": 3600,
|
|
90
|
-
"expires_at": "2026-04-18T13:00:00Z"
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
41
|
+
The canonical reference implementation (single source of truth; `hooks/budget-enforcer.js` imports the same primitive via a shared helper) lives in `./reference/cache-policy.md#deterministic-input-hash-algorithm-layer-b` — it documents the JS implementation, the maintainer notes (sorted-unique paths, MISSING-file sentinel, agent-path bust behavior), the manifest shape, and TTL semantics in one place. Conform to the algorithm exactly so the hook and any orchestrator agree byte-for-byte.
|
|
94
42
|
|
|
95
43
|
## Integration Points
|
|
96
44
|
|
|
@@ -115,6 +63,4 @@ Per D-09:
|
|
|
115
63
|
|
|
116
64
|
## TTL Semantics
|
|
117
65
|
|
|
118
|
-
|
|
119
|
-
- `expires_at` is computed at write time and stored; readers do not recompute.
|
|
120
|
-
- Lazy cleanup: stale entries are not actively deleted on read (overhead for no benefit in normal operation). A separate reaper is optional and out of v1 scope.
|
|
66
|
+
Default `ttl_seconds` = `.design/budget.json.cache_ttl_seconds` = 3600s (1 hour) per D-10. `expires_at` is computed at write time and stored; readers do not recompute. Stale entries are lazily cleaned on read (no eager reaper in v1). Full TTL discussion: `./reference/cache-policy.md#ttl-semantics-layer-b`.
|
|
@@ -7,91 +7,69 @@ tools: Read, Write, Bash, Task
|
|
|
7
7
|
|
|
8
8
|
# /gdd:check-update
|
|
9
9
|
|
|
10
|
-
**Role:** Manual entry point for the plugin-update checker. The SessionStart hook (`hooks/update-check.sh`) already runs on its own 24h cadence and writes `.design/update-cache.json` + `.design/update-available.md`. This command lets the user inspect / force / dismiss / enrich that state on demand.
|
|
10
|
+
**Role:** Manual entry point for the plugin-update checker. The SessionStart hook (`hooks/update-check.sh`) already runs on its own 24h cadence and writes `.design/update-cache.json` + `.design/update-available.md`. This command lets the user inspect / force / dismiss / enrich that state on demand. See `./reference/heuristics.md` §"Version-cadence" for the off-cadence / preview-suffix handling background.
|
|
11
11
|
|
|
12
12
|
## Flags
|
|
13
13
|
|
|
14
14
|
| Flag | Effect |
|
|
15
|
-
|
|
16
|
-
| *(none)* | Print cached state
|
|
15
|
+
|------|--------|
|
|
16
|
+
| *(none)* | Print cached state. If cache is older than 24h, trigger `--refresh` implicitly. |
|
|
17
17
|
| `--refresh` | Invoke `hooks/update-check.sh --refresh` — bypasses the 24h TTL and re-fetches immediately. |
|
|
18
18
|
| `--dismiss` | Write `update_dismissed: "<latest_tag>"` to `.design/config.json` atomically and delete `.design/update-available.md`. Sticky until a newer release ships. |
|
|
19
19
|
| `--prompt` | Spawn `design-update-checker` agent (Haiku) to produce a 3–5-line "what this release changes for you" summary. Does not alter the banner or cache. |
|
|
20
20
|
|
|
21
|
-
Flags
|
|
21
|
+
Flags combine: `--refresh --prompt` is valid (re-fetch, then enrich). `--dismiss` is the only flag that mutates `.design/config.json`.
|
|
22
22
|
|
|
23
23
|
## Steps
|
|
24
24
|
|
|
25
|
-
1. **Parse flags.** Detect `--refresh`, `--dismiss`, `--prompt` in `$ARGUMENTS`.
|
|
25
|
+
1. **Parse flags.** Detect `--refresh`, `--dismiss`, `--prompt` in `$ARGUMENTS`. Unknown flag → `Unknown flag: <flag>` and exit.
|
|
26
|
+
|
|
27
|
+
2. **`--refresh` path** (if set):
|
|
26
28
|
|
|
27
|
-
2. **--refresh path** (if `--refresh` in flags):
|
|
28
|
-
Run the hot-path hook with the refresh flag:
|
|
29
29
|
```bash
|
|
30
30
|
bash "${CLAUDE_PLUGIN_ROOT:-$(pwd)}/hooks/update-check.sh" --refresh
|
|
31
31
|
```
|
|
32
|
-
This re-fetches `/releases/latest`, rewrites `.design/update-cache.json`, and re-renders `.design/update-available.md` subject to the same state/dismissal gates.
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
- Print: `No cache. Network may be unreachable or the hook has not run yet. Try /gdd:check-update --refresh.`
|
|
36
|
-
- Exit.
|
|
33
|
+
This re-fetches `/releases/latest`, rewrites `.design/update-cache.json`, and re-renders `.design/update-available.md` subject to state/dismissal gates.
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
3. **Read cache.** After any optional refresh, read `.design/update-cache.json`. If missing: print `No cache. Network may be unreachable or the hook has not run yet. Try /gdd:check-update --refresh.` and exit.
|
|
39
36
|
|
|
40
|
-
4.
|
|
41
|
-
Compute new config contents and write atomically. The python heredoc receives CONFIG_PATH and LATEST_TAG via the ENVIRONMENT (env-prefix form — `KEY=VALUE python3 <<PY`), NOT via trailing argv. Passing `python3 -c '...' KEY=VALUE` makes Python treat the assignments as `sys.argv`, which the old draft did incorrectly; env-prefix form is the portable fix.
|
|
37
|
+
4. **`--dismiss` path** (if set): Compute new config contents and write atomically via the env-prefix Python heredoc pattern below. The pattern is load-bearing — passing variables as trailing `KEY=VALUE` argv treats them as `sys.argv`, not `os.environ`. Use env-prefix form only.
|
|
42
38
|
|
|
43
39
|
```bash
|
|
44
40
|
CONFIG_PATH=".design/config.json"
|
|
45
41
|
LATEST_TAG="$(grep -E '"latest_tag"' .design/update-cache.json | head -n1 | sed -E 's/.*"latest_tag"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')"
|
|
46
42
|
[ -n "$LATEST_TAG" ] || { echo 'No latest_tag in cache — nothing to dismiss.'; exit 0; }
|
|
47
|
-
|
|
48
43
|
mkdir -p .design
|
|
49
|
-
|
|
50
|
-
# Env-prefix form: CONFIG_PATH and LATEST_TAG are placed into the child process env,
|
|
51
|
-
# then python3 reads them via os.environ. Heredoc body is flat at column 0 (required —
|
|
52
|
-
# any leading indentation breaks Python parsing in a heredoc).
|
|
53
44
|
CONFIG_PATH="$CONFIG_PATH" LATEST_TAG="$LATEST_TAG" python3 <<'PY'
|
|
54
|
-
import json, os, sys, tempfile
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
latest_tag = os.environ['LATEST_TAG']
|
|
58
|
-
|
|
59
|
-
# Load existing config if present; otherwise start fresh. Preserve every unknown key.
|
|
60
|
-
try:
|
|
61
|
-
with open(config_path, 'r', encoding='utf-8') as f:
|
|
62
|
-
data = json.load(f)
|
|
63
|
-
if not isinstance(data, dict):
|
|
64
|
-
data = {}
|
|
65
|
-
except (FileNotFoundError, json.JSONDecodeError):
|
|
66
|
-
data = {}
|
|
67
|
-
|
|
68
|
-
# Set ONLY the dismissal key — every other pre-existing key is preserved verbatim.
|
|
69
|
-
data['update_dismissed'] = latest_tag
|
|
70
|
-
|
|
71
|
-
# Atomic write: write to tmp on the SAME filesystem, then os.replace() (POSIX rename(2)).
|
|
72
|
-
target_dir = os.path.dirname(config_path) or '.'
|
|
73
|
-
fd, tmp_path = tempfile.mkstemp(prefix='config.', suffix='.tmp', dir=target_dir)
|
|
74
|
-
try:
|
|
75
|
-
with os.fdopen(fd, 'w', encoding='utf-8') as f:
|
|
76
|
-
json.dump(data, f, indent=2)
|
|
77
|
-
f.write('\n')
|
|
78
|
-
os.replace(tmp_path, config_path) # atomic on same filesystem
|
|
79
|
-
except Exception as exc:
|
|
45
|
+
import json, os, sys, tempfile
|
|
46
|
+
config_path = os.environ['CONFIG_PATH']
|
|
47
|
+
latest_tag = os.environ['LATEST_TAG']
|
|
80
48
|
try:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
49
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
50
|
+
data = json.load(f)
|
|
51
|
+
if not isinstance(data, dict): data = {}
|
|
52
|
+
except (FileNotFoundError, json.JSONDecodeError): data = {}
|
|
53
|
+
data['update_dismissed'] = latest_tag
|
|
54
|
+
target_dir = os.path.dirname(config_path) or '.'
|
|
55
|
+
fd, tmp_path = tempfile.mkstemp(prefix='config.', suffix='.tmp', dir=target_dir)
|
|
56
|
+
try:
|
|
57
|
+
with os.fdopen(fd, 'w', encoding='utf-8') as f:
|
|
58
|
+
json.dump(data, f, indent=2); f.write('\n')
|
|
59
|
+
os.replace(tmp_path, config_path)
|
|
60
|
+
except Exception:
|
|
61
|
+
try: os.unlink(tmp_path)
|
|
62
|
+
except OSError: pass
|
|
63
|
+
sys.exit(1)
|
|
64
|
+
PY
|
|
88
65
|
rm -f .design/update-available.md
|
|
89
66
|
echo "Dismissed $LATEST_TAG. The nudge will return when a newer release ships."
|
|
90
67
|
```
|
|
91
68
|
|
|
92
|
-
D-14 atomic-write invariant: `os.replace()` (POSIX `rename(2)`) is atomic on the same filesystem
|
|
69
|
+
D-14 atomic-write invariant: `os.replace()` (POSIX `rename(2)`) is atomic on the same filesystem. The `json.load → set single key → json.dump` round-trip preserves every unknown top-level key (e.g. `model_profile`, `parallelism`) verbatim.
|
|
70
|
+
|
|
71
|
+
5. **Print default state** (always, unless exited early):
|
|
93
72
|
|
|
94
|
-
5. **Print default state** (always, unless the skill exited early):
|
|
95
73
|
```
|
|
96
74
|
━━━ /gdd:check-update ━━━
|
|
97
75
|
Current: v<X.Y.Z>
|
|
@@ -101,35 +79,20 @@ PY
|
|
|
101
79
|
Dismissed: <tag or "no">
|
|
102
80
|
━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
103
81
|
```
|
|
104
|
-
Parse these fields from `.design/update-cache.json` using `grep + sed` (no jq dependency). Read dismissal from `.design/config.json` via the same pattern as hooks/update-check.sh:
|
|
105
|
-
```bash
|
|
106
|
-
[ -f .design/config.json ] && grep -E '"update_dismissed"' .design/config.json | sed -E 's/.*"update_dismissed"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/'
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
6. **--prompt path** (if `--prompt` in flags):
|
|
110
|
-
Spawn the `design-update-checker` agent via the Task tool. Pass as context:
|
|
111
|
-
- `current_tag` — from `.design/update-cache.json`
|
|
112
|
-
- `latest_tag` — from `.design/update-cache.json`
|
|
113
|
-
- `delta` — from `.design/update-cache.json`
|
|
114
|
-
- `release_body` — the `changelog_excerpt` from the cache (may be pre-truncated to 500 chars; that's fine — the agent knows)
|
|
115
82
|
|
|
116
|
-
|
|
83
|
+
Parse fields from `.design/update-cache.json` via `grep + sed` (no jq dep). Read dismissal from `.design/config.json` via the same pattern as `hooks/update-check.sh`.
|
|
117
84
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- No flags → behave as: `--refresh (only if cache >24h old) → print state`. Silent no-op if cache is fresh and there is no newer version.
|
|
85
|
+
6. **`--prompt` path** (if set): Spawn `design-update-checker` via Task tool with context `{current_tag, latest_tag, delta, release_body}`. Display response verbatim below the banner. Agent ends with `## UPDATE-CHECKER COMPLETE`.
|
|
121
86
|
|
|
122
87
|
## Do Not
|
|
123
88
|
|
|
124
|
-
- Do not fetch from GitHub
|
|
125
|
-
- Do not modify `.design/update-available.md` except to delete
|
|
126
|
-
- Do not rewrite `.design/config.json` wholesale — the atomic
|
|
127
|
-
- Do not pass variables to the
|
|
89
|
+
- Do not fetch from GitHub directly — always go through `hooks/update-check.sh --refresh` so caching + state-guard + dismissal logic stays in one place.
|
|
90
|
+
- Do not modify `.design/update-available.md` except to delete on `--dismiss`.
|
|
91
|
+
- Do not rewrite `.design/config.json` wholesale — the atomic Python rewrite preserves every unknown key (D-14).
|
|
92
|
+
- Do not pass variables to the Python heredoc via trailing `KEY=VALUE` argv — env-prefix form only.
|
|
128
93
|
|
|
129
94
|
## Completion marker
|
|
130
95
|
|
|
131
|
-
Last line of output:
|
|
132
|
-
|
|
133
96
|
```
|
|
134
97
|
## CHECK-UPDATE COMPLETE
|
|
135
98
|
```
|