@hegemonart/get-design-done 1.27.6 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +6 -3
- package/CHANGELOG.md +113 -0
- package/agents/design-verifier.md +17 -0
- package/package.json +5 -4
- package/reference/accessibility.md +4 -0
- package/reference/audit-scoring.md +14 -0
- package/reference/color-theory.md +279 -0
- package/reference/composition.md +349 -0
- package/reference/contrast-advanced.md +205 -0
- package/reference/design-system-guidance.md +2 -0
- package/reference/form-patterns.md +2 -0
- package/reference/i18n.md +554 -0
- package/reference/iconography.md +2 -0
- package/reference/motion-interpolate.md +1 -0
- package/reference/palette-catalog.md +2 -0
- package/reference/proportion-systems.md +267 -0
- package/reference/registry.json +42 -0
- package/reference/rtl-cjk-cultural.md +2 -0
- package/reference/schemas/mcp-gdd-tools.schema.json +381 -0
- package/reference/style-vocabulary.md +2 -0
- package/reference/typography.md +4 -0
- package/reference/visual-hierarchy-layout.md +4 -0
- package/scripts/install.cjs +42 -0
- package/scripts/lib/gsd-health-mirror/index.cjs +105 -0
- package/scripts/lib/gsd-health-mirror/index.d.cts +14 -0
- package/scripts/lib/install/mcp-register.cjs +235 -0
- package/scripts/lib/install/mcp-register.d.cts +64 -0
- package/scripts/lib/intel-store/index.cjs +55 -0
- package/scripts/lib/intel-store/index.d.cts +11 -0
- package/scripts/lib/mcp-tools-lint/index.cjs +216 -0
- package/scripts/lib/mcp-tools-lint/index.d.cts +74 -0
- package/scripts/lib/reflections-reader/index.cjs +107 -0
- package/scripts/lib/reflections-reader/index.d.cts +18 -0
- package/scripts/lib/roadmap-reader/index.cjs +81 -0
- package/scripts/lib/roadmap-reader/index.d.cts +13 -0
- package/scripts/lib/snapshot-reader/index.cjs +70 -0
- package/scripts/lib/snapshot-reader/index.d.cts +28 -0
- package/scripts/mcp-servers/gdd-mcp/README.md +66 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_cycle_recap.schema.json +30 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_decisions_list.schema.json +32 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_events_tail.schema.json +22 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_health.schema.json +30 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_intel_get.schema.json +24 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_learnings_digest.schema.json +22 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_phase_current.schema.json +22 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_phases_list.schema.json +31 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_plans_list.schema.json +33 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_reflections_latest.schema.json +21 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_status.schema.json +23 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_telemetry_query.schema.json +23 -0
- package/scripts/mcp-servers/gdd-mcp/server.ts +317 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_cycle_recap.ts +37 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_decisions_list.ts +33 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_events_tail.ts +26 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_health.ts +19 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_intel_get.ts +32 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_learnings_digest.ts +23 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_phase_current.ts +29 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_phases_list.ts +26 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_plans_list.ts +39 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_reflections_latest.ts +25 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_status.ts +31 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_telemetry_query.ts +27 -0
- package/scripts/mcp-servers/gdd-mcp/tools/index.ts +75 -0
- package/scripts/mcp-servers/gdd-mcp/tools/shared.ts +134 -0
- package/skills/explore/SKILL.md +31 -0
- package/skills/health/SKILL.md +36 -0
- package/skills/next/SKILL.md +28 -3
- package/skills/progress/SKILL.md +21 -6
- package/skills/resume/SKILL.md +26 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// scripts/lib/reflections-reader/index.cjs — Plan 27.7-02
|
|
3
|
+
//
|
|
4
|
+
// Read post-cycle reflections from <rootDir>/.design/reflections/.
|
|
5
|
+
//
|
|
6
|
+
// Surface:
|
|
7
|
+
// class ReflectionsNotFoundError extends Error — code='directory_not_found'
|
|
8
|
+
// async readLatestReflection(rootDir) — { cycle, path, content } | null
|
|
9
|
+
// async readNReflections(rootDir, n) — same shape, sorted desc by mtime
|
|
10
|
+
// digestReflections(reflections) — string, <= 5120 chars
|
|
11
|
+
|
|
12
|
+
const fs = require('node:fs');
|
|
13
|
+
const path = require('node:path');
|
|
14
|
+
|
|
15
|
+
const DIGEST_CAP_BYTES = 5120;
|
|
16
|
+
|
|
17
|
+
class ReflectionsNotFoundError extends Error {
|
|
18
|
+
constructor(dir) {
|
|
19
|
+
super('source directory not found: ' + dir);
|
|
20
|
+
this.name = 'ReflectionsNotFoundError';
|
|
21
|
+
this.code = 'directory_not_found';
|
|
22
|
+
this.dir = dir;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function listReflectionFiles(dir) {
|
|
27
|
+
const entries = await fs.promises.readdir(dir);
|
|
28
|
+
const candidates = [];
|
|
29
|
+
for (const name of entries) {
|
|
30
|
+
if (!name.endsWith('.md')) continue;
|
|
31
|
+
const full = path.join(dir, name);
|
|
32
|
+
try {
|
|
33
|
+
const stat = await fs.promises.stat(full);
|
|
34
|
+
candidates.push({ name, full, mtime: stat.mtimeMs });
|
|
35
|
+
} catch {
|
|
36
|
+
// ignore — race with concurrent write
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
candidates.sort((a, b) => b.mtime - a.mtime);
|
|
40
|
+
return candidates;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Extract a cycle id from a reflection filename. Convention: filenames
|
|
44
|
+
* like `2026-05-17-cycle27.7.md` or `cycle-NN.md`; we pick the first
|
|
45
|
+
* `cycle*` token, falling back to the basename. */
|
|
46
|
+
function extractCycle(name) {
|
|
47
|
+
const m = name.match(/cycle[-_]?[\w.]+/i);
|
|
48
|
+
if (m) return m[0];
|
|
49
|
+
return name.replace(/\.md$/, '');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function readLatestReflection(rootDir) {
|
|
53
|
+
const dir = path.join(rootDir, '.design', 'reflections');
|
|
54
|
+
if (!fs.existsSync(dir)) {
|
|
55
|
+
throw new ReflectionsNotFoundError(dir);
|
|
56
|
+
}
|
|
57
|
+
const files = await listReflectionFiles(dir);
|
|
58
|
+
if (files.length === 0) return null;
|
|
59
|
+
const f = files[0];
|
|
60
|
+
const content = await fs.promises.readFile(f.full, 'utf8');
|
|
61
|
+
return { cycle: extractCycle(f.name), path: f.full, content };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function readNReflections(rootDir, n) {
|
|
65
|
+
const dir = path.join(rootDir, '.design', 'reflections');
|
|
66
|
+
if (!fs.existsSync(dir)) {
|
|
67
|
+
throw new ReflectionsNotFoundError(dir);
|
|
68
|
+
}
|
|
69
|
+
const files = await listReflectionFiles(dir);
|
|
70
|
+
const take = Math.max(0, Math.min(n, files.length));
|
|
71
|
+
const out = [];
|
|
72
|
+
for (let i = 0; i < take; i++) {
|
|
73
|
+
const f = files[i];
|
|
74
|
+
const content = await fs.promises.readFile(f.full, 'utf8');
|
|
75
|
+
out.push({ cycle: extractCycle(f.name), path: f.full, content });
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Aggregate reflections into a compact digest <= 5 KB. Strategy: take
|
|
81
|
+
* the first 300 chars of each reflection's body (skipping any leading
|
|
82
|
+
* frontmatter `---` block); join with `\n---\n`; truncate at the cap. */
|
|
83
|
+
function digestReflections(reflections) {
|
|
84
|
+
const parts = [];
|
|
85
|
+
for (const r of reflections) {
|
|
86
|
+
let body = r.content;
|
|
87
|
+
// Strip leading YAML frontmatter if present
|
|
88
|
+
if (body.startsWith('---')) {
|
|
89
|
+
const closing = body.indexOf('\n---', 3);
|
|
90
|
+
if (closing !== -1) body = body.slice(closing + 4).trim();
|
|
91
|
+
}
|
|
92
|
+
const excerpt = body.slice(0, 300).trim();
|
|
93
|
+
parts.push('[' + r.cycle + '] ' + excerpt);
|
|
94
|
+
}
|
|
95
|
+
let joined = parts.join('\n---\n');
|
|
96
|
+
if (joined.length > DIGEST_CAP_BYTES) {
|
|
97
|
+
joined = joined.slice(0, DIGEST_CAP_BYTES);
|
|
98
|
+
}
|
|
99
|
+
return joined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
readLatestReflection,
|
|
104
|
+
readNReflections,
|
|
105
|
+
digestReflections,
|
|
106
|
+
ReflectionsNotFoundError,
|
|
107
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// scripts/lib/reflections-reader/index.d.cts — TypeScript ambient declarations
|
|
2
|
+
// for the reflections-reader CJS module. Plan 27.7-02.
|
|
3
|
+
|
|
4
|
+
export class ReflectionsNotFoundError extends Error {
|
|
5
|
+
code: 'directory_not_found';
|
|
6
|
+
dir: string;
|
|
7
|
+
constructor(dir: string);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Reflection {
|
|
11
|
+
cycle: string;
|
|
12
|
+
path: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function readLatestReflection(rootDir: string): Promise<Reflection | null>;
|
|
17
|
+
export function readNReflections(rootDir: string, n: number): Promise<Reflection[]>;
|
|
18
|
+
export function digestReflections(reflections: Reflection[]): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// scripts/lib/roadmap-reader/index.cjs — Plan 27.7-02
|
|
3
|
+
//
|
|
4
|
+
// Read + parse .planning/ROADMAP.md into a flat list of phase entries
|
|
5
|
+
// consumed by the gdd_phases_list MCP tool. Pure read; no I/O outside
|
|
6
|
+
// readRoadmapMd().
|
|
7
|
+
//
|
|
8
|
+
// Output shape per phase:
|
|
9
|
+
// { number: '27.7', name: 'GDD MCP Server', version: 'v1.27.7',
|
|
10
|
+
// checkbox_status: 'shipped' | 'planned' | 'unknown' }
|
|
11
|
+
//
|
|
12
|
+
// `checkbox_status` is sourced from the overview list at the top of
|
|
13
|
+
// ROADMAP.md (lines shaped `- [x] [Phase 27]...` or `- [ ] [Phase 27.7]...`).
|
|
14
|
+
// When no overview line matches the heading, we emit `'unknown'`.
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
|
|
19
|
+
/** Read .planning/ROADMAP.md from rootDir; returns full markdown string. */
|
|
20
|
+
async function readRoadmapMd(rootDir) {
|
|
21
|
+
const p = path.join(rootDir, '.planning', 'ROADMAP.md');
|
|
22
|
+
return fs.promises.readFile(p, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse the body of ROADMAP.md into phase entries. Two passes:
|
|
27
|
+
* 1. Scan `- [x|space] [Phase <num>](...)` overview lines → status map
|
|
28
|
+
* 2. Scan `### Phase <num>: <name>` headings → main list
|
|
29
|
+
*
|
|
30
|
+
* The version is pulled from the FIRST line after the heading that
|
|
31
|
+
* matches `**Target version**:` or `— v\S+`. We tolerate trailing
|
|
32
|
+
* parenthetical commentary on the heading by trimming everything after
|
|
33
|
+
* a trailing ` (…)` chunk.
|
|
34
|
+
*/
|
|
35
|
+
function parsePhases(md) {
|
|
36
|
+
// Pass 1 — overview checkbox map. Pattern matches both `Phase 27` and
|
|
37
|
+
// `Phase 27.7`; ignores the descriptive name + version that may follow.
|
|
38
|
+
const statusMap = new Map();
|
|
39
|
+
const overviewRe = /^-\s+\[([x\s])\]\s+\[Phase\s+(\S+?)\]/gm;
|
|
40
|
+
let mm;
|
|
41
|
+
while ((mm = overviewRe.exec(md)) !== null) {
|
|
42
|
+
const checked = mm[1] === 'x';
|
|
43
|
+
statusMap.set(mm[2], checked ? 'shipped' : 'planned');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Pass 2 — Phase heading scan. We capture the number + name, then
|
|
47
|
+
// look ahead in the heading's section for a version marker. The
|
|
48
|
+
// heading may have an embedded version (` — v1.X.Y`) or rely on
|
|
49
|
+
// a `**Target version**:` block below.
|
|
50
|
+
const headingRe = /^###\s+Phase\s+(\S+?):\s+([^\n]+?)$/gm;
|
|
51
|
+
const phases = [];
|
|
52
|
+
let h;
|
|
53
|
+
while ((h = headingRe.exec(md)) !== null) {
|
|
54
|
+
const number = h[1];
|
|
55
|
+
let name = h[2].trim();
|
|
56
|
+
// Strip trailing parenthetical commentary (e.g. `(INSERTED)`).
|
|
57
|
+
name = name.replace(/\s+\([^)]*\)\s*$/g, '').trim();
|
|
58
|
+
// Strip trailing version chunk from the heading itself.
|
|
59
|
+
const inlineVer = name.match(/\s+—\s+(v\d+\.\d+(?:\.\d+)?)/);
|
|
60
|
+
let version = inlineVer ? inlineVer[1] : '';
|
|
61
|
+
if (inlineVer) {
|
|
62
|
+
name = name.slice(0, inlineVer.index).trim();
|
|
63
|
+
}
|
|
64
|
+
// If no inline version, look forward in the next ~30 lines for a
|
|
65
|
+
// `**Target version**:` block.
|
|
66
|
+
if (version === '') {
|
|
67
|
+
const after = md.slice(h.index, h.index + 2000);
|
|
68
|
+
const v = after.match(/\*\*Target version\*\*:\s*(v\d+\.\d+(?:\.\d+)?)/);
|
|
69
|
+
if (v) version = v[1];
|
|
70
|
+
}
|
|
71
|
+
phases.push({
|
|
72
|
+
number,
|
|
73
|
+
name,
|
|
74
|
+
version,
|
|
75
|
+
checkbox_status: statusMap.get(number) ?? 'unknown',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return phases;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { readRoadmapMd, parsePhases };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// scripts/lib/roadmap-reader/index.d.cts — TypeScript ambient declarations
|
|
2
|
+
// for the roadmap-reader CJS module. Plan 27.7-02 — TS imports of CJS
|
|
3
|
+
// need .d.cts siblings (Phase 27.6 lesson).
|
|
4
|
+
|
|
5
|
+
export interface ParsedPhase {
|
|
6
|
+
number: string;
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
checkbox_status: 'shipped' | 'planned' | 'unknown';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function readRoadmapMd(rootDir: string): Promise<string>;
|
|
13
|
+
export function parsePhases(md: string): ParsedPhase[];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// scripts/lib/snapshot-reader/index.cjs — Plan 27.7-02
|
|
3
|
+
//
|
|
4
|
+
// Read latest snapshot under .design/snapshots/ (written by
|
|
5
|
+
// hooks/gdd-precompact-snapshot.js; see Phase 27.6 Plan 05).
|
|
6
|
+
//
|
|
7
|
+
// Surface:
|
|
8
|
+
// class SnapshotNotFoundError extends Error — code='directory_not_found'
|
|
9
|
+
// async readLatestSnapshot(rootDir) — { since, snapshot } | null
|
|
10
|
+
//
|
|
11
|
+
// `since` is the snapshot's embedded `timestamp` (ISO 8601), falling
|
|
12
|
+
// back to the file's mtime if absent.
|
|
13
|
+
|
|
14
|
+
const fs = require('node:fs');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
|
|
17
|
+
class SnapshotNotFoundError extends Error {
|
|
18
|
+
constructor(dir) {
|
|
19
|
+
super('source directory not found: ' + dir);
|
|
20
|
+
this.name = 'SnapshotNotFoundError';
|
|
21
|
+
this.code = 'directory_not_found';
|
|
22
|
+
this.dir = dir;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Read the newest *.json file under <rootDir>/.design/snapshots/.
|
|
28
|
+
* Returns `{ since, snapshot }` or `null` when the directory exists
|
|
29
|
+
* but contains no snapshot files. Throws SnapshotNotFoundError when
|
|
30
|
+
* the directory itself is missing.
|
|
31
|
+
*/
|
|
32
|
+
async function readLatestSnapshot(rootDir) {
|
|
33
|
+
const dir = path.join(rootDir, '.design', 'snapshots');
|
|
34
|
+
if (!fs.existsSync(dir)) {
|
|
35
|
+
throw new SnapshotNotFoundError(dir);
|
|
36
|
+
}
|
|
37
|
+
const entries = await fs.promises.readdir(dir);
|
|
38
|
+
const candidates = [];
|
|
39
|
+
for (const name of entries) {
|
|
40
|
+
if (!name.endsWith('.json')) continue;
|
|
41
|
+
if (name === 'last-recap.json') continue;
|
|
42
|
+
const full = path.join(dir, name);
|
|
43
|
+
try {
|
|
44
|
+
const stat = await fs.promises.stat(full);
|
|
45
|
+
candidates.push({ full, mtime: stat.mtimeMs });
|
|
46
|
+
} catch {
|
|
47
|
+
// ignore — race with retention prune
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (candidates.length === 0) return null;
|
|
51
|
+
candidates.sort((a, b) => b.mtime - a.mtime);
|
|
52
|
+
const winner = candidates[0];
|
|
53
|
+
const body = await fs.promises.readFile(winner.full, 'utf8');
|
|
54
|
+
let snapshot;
|
|
55
|
+
try {
|
|
56
|
+
snapshot = JSON.parse(body);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// Malformed snapshot — surface a parseable error
|
|
59
|
+
throw new Error(
|
|
60
|
+
'snapshot parse failed: ' + winner.full + ': ' + (err && err.message ? err.message : String(err)),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const since =
|
|
64
|
+
typeof snapshot.timestamp === 'string' && snapshot.timestamp.length > 0
|
|
65
|
+
? snapshot.timestamp
|
|
66
|
+
: new Date(winner.mtime).toISOString();
|
|
67
|
+
return { since, snapshot };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { readLatestSnapshot, SnapshotNotFoundError };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// scripts/lib/snapshot-reader/index.d.cts — TypeScript ambient declarations
|
|
2
|
+
// for the snapshot-reader CJS module. Plan 27.7-02.
|
|
3
|
+
|
|
4
|
+
export class SnapshotNotFoundError extends Error {
|
|
5
|
+
code: 'directory_not_found';
|
|
6
|
+
dir: string;
|
|
7
|
+
constructor(dir: string);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SnapshotPayload {
|
|
11
|
+
/** Snapshot body — shape is JSON-loose; consumers project keys. */
|
|
12
|
+
schema_version?: string;
|
|
13
|
+
timestamp?: string;
|
|
14
|
+
cycle_id?: string;
|
|
15
|
+
state_md_sections?: unknown;
|
|
16
|
+
last_n_events?: unknown[];
|
|
17
|
+
last_n_decisions?: unknown[];
|
|
18
|
+
decisions_count?: number;
|
|
19
|
+
completed_plans_count?: number;
|
|
20
|
+
[k: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ReadSnapshotResult {
|
|
24
|
+
since: string;
|
|
25
|
+
snapshot: SnapshotPayload;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function readLatestSnapshot(rootDir: string): Promise<ReadSnapshotResult | null>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# gdd-mcp
|
|
2
|
+
|
|
3
|
+
Read-only MCP server exposing GDD project state — STATE.md sections, phases, decisions, plans, telemetry, intel slices, latest reflections — as 12 typed MCP tools. Sessions prime in 3 MCP calls instead of 100+ file reads, on the same project a per-session reduction of −30% tokens and ~34× wall-clock speedup (see benchmark below).
|
|
4
|
+
|
|
5
|
+
Phase 27.7. Mirror of the `scripts/mcp-servers/gdd-state/` Phase 20 pattern. v1 is read-only — mutation belongs to slash-skills and the lockfile-safe `gdd-state-mcp` writers (Phase 20 surface).
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Name | Input | Output (one-line summary) |
|
|
10
|
+
|------|-------|---------------------------|
|
|
11
|
+
| `gdd_status` | `{}` | Current cycle phase, branch, last-3 decisions, last-3 completed plans, blocker count |
|
|
12
|
+
| `gdd_phase_current` | `{}` | Current phase + stage + task_progress + status from STATE.md `<position>` |
|
|
13
|
+
| `gdd_phases_list` | `{}` | Phases from ROADMAP.md overview parse |
|
|
14
|
+
| `gdd_plans_list` | `{phase?}` | Plans for the current (or specified) phase from STATE.md `<plans>` |
|
|
15
|
+
| `gdd_decisions_list` | `{status?}` | D-XX decisions from STATE.md `<decisions>`, optionally filtered |
|
|
16
|
+
| `gdd_intel_get` | `{slice_id, shape?}` | Slice query against `.design/intel/` with optional key projection |
|
|
17
|
+
| `gdd_telemetry_query` | `{type?, since?, limit?}` | Typed reader over `.design/telemetry/*.jsonl` |
|
|
18
|
+
| `gdd_cycle_recap` | `{since_snapshot?}` | Diff vs the last Phase 27.6 snapshot (STATE sections + decisions + plans) |
|
|
19
|
+
| `gdd_reflections_latest` | `{}` | Latest cycle reflection excerpt from `.design/reflections/` (≤4 KB) |
|
|
20
|
+
| `gdd_learnings_digest` | `{cycles?}` | Compact lessons digest of recent reflections (≤5 KB) |
|
|
21
|
+
| `gdd_events_tail` | `{type?, limit?}` | Last N events from event-chain with optional type filter |
|
|
22
|
+
| `gdd_health` | `{}` | Read-only mirror of `skills/health/SKILL.md` checks payload |
|
|
23
|
+
|
|
24
|
+
All tools are thin wrappers (≤30 LOC) over `scripts/lib/*` helpers. The lint rule at `scripts/lib/mcp-tools-lint/` enforces no direct `fs.*`/`path.*` imports and zero write-tool names (`_create`, `_update`, `_delete`, `_append`, `_clear`, `_write`, `_set`). The 12-tool cap is hard (D-03) — adding a 13th requires a new plan.
|
|
25
|
+
|
|
26
|
+
Schemas live under `reference/schemas/mcp-gdd-tools.schema.json` (Draft-07). Tool sources are under `scripts/mcp-servers/gdd-mcp/tools/*.ts`.
|
|
27
|
+
|
|
28
|
+
## Manual registration
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Opt-in via installer (idempotent, detects Claude Code + Codex CLIs):
|
|
32
|
+
npx @hegemonart/get-design-done --register-mcp
|
|
33
|
+
|
|
34
|
+
# Or manual (Claude Code):
|
|
35
|
+
claude mcp add gdd-mcp -s user -- gdd-mcp
|
|
36
|
+
|
|
37
|
+
# Or manual (Codex):
|
|
38
|
+
codex mcp add gdd-mcp -- gdd-mcp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Dismiss the gdd-health MCP-registration nudge by setting `.design/config.json` to `{"mcp_nudge": false}`.
|
|
42
|
+
|
|
43
|
+
## When to prefer MCP vs file reads
|
|
44
|
+
|
|
45
|
+
| Scenario | Use MCP | Use file reads |
|
|
46
|
+
|----------|---------|----------------|
|
|
47
|
+
| Cold-boot priming (`/gdd:progress`, `/gdd:resume`, `/gdd:next`) | Yes — 3 calls, ~3 s, ~32k tokens | Fallback only when MCP unavailable |
|
|
48
|
+
| Mid-cycle context refresh in stage skills | Yes — 1–2 targeted calls | Fallback only |
|
|
49
|
+
| Editing STATE.md sections | No — use `mcp__gdd_state__*` (Phase 20) | N/A |
|
|
50
|
+
| Listing all skills | No — slash-skills + `scripts/list-skills.cjs` | N/A |
|
|
51
|
+
| Reading arbitrary untracked files | No | Yes — Read tool |
|
|
52
|
+
|
|
53
|
+
**Benchmark** (synthetic fixture at `test-fixture/baselines/phase-27-7/priming-benchmark.json`, modeled on Storybloq v1.2.0 measured numbers):
|
|
54
|
+
|
|
55
|
+
- MCP path: 3 calls, ~3 s, ~32k tokens
|
|
56
|
+
- File-read path: 5–10 reads, ~101 s, ~46.5k tokens
|
|
57
|
+
- Reduction: −31% tokens, ~34× wall-clock speedup
|
|
58
|
+
|
|
59
|
+
Per CONTEXT.md D-09 the benchmark is informational — failure to hit the −30% target surfaces as a Phase 27.7 success-criterion regression in closeout (Plan 27.7-07), NOT a CI hard-fail. After 5–10 real cycles, the synthetic fixture is replaced with measured GDD numbers (research-tail item).
|
|
60
|
+
|
|
61
|
+
## See also
|
|
62
|
+
|
|
63
|
+
- `scripts/mcp-servers/gdd-state/` — Phase 20 STATE.md mutation MCP (write surface)
|
|
64
|
+
- `scripts/lib/mcp-tools-lint/` — Static analysis enforcing thin-wrapper discipline
|
|
65
|
+
- `reference/schemas/mcp-gdd-tools.schema.json` — Tool input/output schemas (Draft-07)
|
|
66
|
+
- `.planning/phases/27.7-gdd-mcp-server/CONTEXT.md` — Phase 27.7 decisions and rationale
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_cycle_recap",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"since_snapshot": { "type": "string" }
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"output": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["since", "diff"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"since": { "type": ["string", "null"] },
|
|
18
|
+
"diff": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"required": ["state_sections", "decisions_delta", "completed_plans_delta"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"state_sections": { "type": "array", "items": { "type": "string" } },
|
|
23
|
+
"decisions_delta": { "type": "integer" },
|
|
24
|
+
"completed_plans_delta": { "type": "integer" }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_decisions_list",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"status": { "type": "string", "enum": ["locked", "tentative"] }
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"output": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["decisions"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"decisions": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"required": ["id", "text", "status"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"id": { "type": "string" },
|
|
24
|
+
"text": { "type": "string" },
|
|
25
|
+
"status": { "type": "string" }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_events_tail",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"type": { "type": "string" },
|
|
11
|
+
"limit": { "type": "integer", "minimum": 1, "maximum": 10000 }
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"output": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["events"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"events": { "type": "array", "items": { "type": "object" } }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_health",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {}
|
|
10
|
+
},
|
|
11
|
+
"output": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["checks"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"checks": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"required": ["name", "status", "detail"],
|
|
20
|
+
"properties": {
|
|
21
|
+
"name": { "type": "string" },
|
|
22
|
+
"status": { "type": "string", "enum": ["ok", "warn", "fail"] },
|
|
23
|
+
"detail": { "type": "string" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_intel_get",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"required": ["slice_id"],
|
|
10
|
+
"properties": {
|
|
11
|
+
"slice_id": { "type": "string", "minLength": 1 },
|
|
12
|
+
"shape": { "type": "array", "items": { "type": "string" } }
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"output": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"required": ["slice_id", "data"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"slice_id": { "type": "string" },
|
|
20
|
+
"data": { "type": "object" }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_learnings_digest",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"cycles": { "type": "integer", "minimum": 1, "maximum": 50 }
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"output": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["digest", "cycles_included"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"digest": { "type": "string", "maxLength": 5120 },
|
|
18
|
+
"cycles_included": { "type": "integer", "minimum": 0 }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_phase_current",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {}
|
|
10
|
+
},
|
|
11
|
+
"output": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["phase", "stage", "task_progress", "status"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"phase": { "type": ["string", "null"] },
|
|
16
|
+
"stage": { "type": ["string", "null"] },
|
|
17
|
+
"task_progress": { "type": ["string", "null"] },
|
|
18
|
+
"status": { "type": ["string", "null"] }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_phases_list",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {}
|
|
10
|
+
},
|
|
11
|
+
"output": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["phases"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"phases": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"required": ["number", "name", "version", "checkbox_status"],
|
|
20
|
+
"properties": {
|
|
21
|
+
"number": { "type": "string" },
|
|
22
|
+
"name": { "type": "string" },
|
|
23
|
+
"version": { "type": "string" },
|
|
24
|
+
"checkbox_status": { "type": "string", "enum": ["shipped", "planned", "unknown"] }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_plans_list",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"phase": { "type": "string" }
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"output": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["phase", "plans"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"phase": { "type": ["string", "null"] },
|
|
18
|
+
"plans": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": ["id", "name", "status"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"id": { "type": "string" },
|
|
25
|
+
"name": { "type": "string" },
|
|
26
|
+
"status": { "type": "string" }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gdd_reflections_latest",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {}
|
|
10
|
+
},
|
|
11
|
+
"output": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["cycle", "path", "content_excerpt"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"cycle": { "type": ["string", "null"] },
|
|
16
|
+
"path": { "type": ["string", "null"] },
|
|
17
|
+
"content_excerpt": { "type": "string", "maxLength": 4096 }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|