refactor: hard-fork GSD -> MSD (Make Software Done)

Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
Jakub Zych
2026-10-06 01:47:40 +02:00
parent fe069b2a56
commit a9a7a328e6
2763 changed files with 78465 additions and 78434 deletions

View File

@@ -1,4 +1,4 @@
# GSD Core Architecture
# MSD Core Architecture
> System architecture for contributors and advanced users. For user-facing documentation, see [Feature Reference](FEATURES.md) or [User Guide](USER-GUIDE.md).
@@ -21,7 +21,7 @@
## System Overview
GSD Core is a **meta-prompting framework** that sits between the user and AI coding agents (Claude Code, Kimi CLI, OpenCode, Kilo, Codex, Copilot, Antigravity, Trae, Cline, Augment Code). It provides:
MSD Core is a **meta-prompting framework** that sits between the user and AI coding agents (Claude Code, Kimi CLI, OpenCode, Kilo, Codex, Copilot, Antigravity, Trae, Cline, Augment Code). It provides:
1. **Context engineering** — Structured artifacts that give the AI everything it needs per task (see [Context engineering](explanation/context-engineering.md))
2. **Multi-agent orchestration** — Thin orchestrators that spawn specialized agents with fresh context windows (see [Multi-agent orchestration](explanation/multi-agent-orchestration.md))
@@ -31,18 +31,18 @@ GSD Core is a **meta-prompting framework** that sits between the user and AI cod
```
┌──────────────────────────────────────────────────────┐
│ USER │
│ /gsd-command [args] │
│ /msd-command [args] │
└─────────────────────┬────────────────────────────────┘
│
┌─────────────────────▼────────────────────────────────┐
│ COMMAND LAYER │
│ commands/gsd/*.md — Prompt-based command files │
│ commands/msd/*.md — Prompt-based command files │
│ (Claude Code custom commands / Codex skills) │
└─────────────────────┬────────────────────────────────┘
│
┌─────────────────────▼────────────────────────────────┐
│ WORKFLOW LAYER │
│ gsd-core/workflows/*.md — Orchestration logic │
│ msd-core/workflows/*.md — Orchestration logic │
│ (Reads references, spawns agents, manages state) │
└──────┬──────────────┬─────────────────┬──────────────┘
│ │ │
@@ -54,7 +54,7 @@ GSD Core is a **meta-prompting framework** that sits between the user and AI cod
│ │ │
┌──────▼──────────────▼─────────────────▼──────────────┐
│ CLI TOOLS LAYER │
│ gsd-tools.cjs command families + domain modules │
│ msd-tools.cjs command families + domain modules │
│ command-routing-hub + observability seams │
└──────────────────────┬───────────────────────────────┘
│
@@ -75,9 +75,9 @@ Every agent spawned by an orchestrator gets a clean context window (up to 200K t
### 2. Thin Orchestrators
Workflow files (`gsd-core/workflows/*.md`) never do heavy lifting. They:
Workflow files (`msd-core/workflows/*.md`) never do heavy lifting. They:
- Load context via `gsd-tools.cjs init <workflow>`
- Load context via `msd-tools.cjs init <workflow>`
- Spawn specialized agents with focused prompts
- Collect results and route to the next step
- Update state between steps
@@ -107,34 +107,34 @@ Multiple layers prevent common failure modes:
## Component Architecture
### Commands (`commands/gsd/*.md`)
### Commands (`commands/msd/*.md`)
User-facing entry points. Each file contains YAML frontmatter (name, description, allowed-tools) and a prompt body that bootstraps the workflow. Commands are installed as:
- **Claude Code:** Custom slash commands (hyphen form, `/gsd-command-name`)
- **OpenCode / Kilo:** Slash commands (hyphen form, `/gsd-command-name`)
- **Codex:** Skills (`$gsd-command-name`)
- **Copilot:** Slash commands (hyphen form, `/gsd-command-name`)
- **Kimi CLI:** Agent Skills (`/skill:gsd-command-name`) plus an explicit custom agent launch with `kimi --agent-file`
- **Claude Code:** Custom slash commands (hyphen form, `/msd-command-name`)
- **OpenCode / Kilo:** Slash commands (hyphen form, `/msd-command-name`)
- **Codex:** Skills (`$msd-command-name`)
- **Copilot:** Slash commands (hyphen form, `/msd-command-name`)
- **Kimi CLI:** Agent Skills (`/skill:msd-command-name`) plus an explicit custom agent launch with `kimi --agent-file`
- **Antigravity:** Skills
**Total commands:** see [`docs/INVENTORY.md`](INVENTORY.md#commands) for the authoritative count and full roster.
#### Two-stage hierarchical routing (v1.40, [#2792](https://github.com/open-gsd/gsd-core/issues/2792))
To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`gsd-workflow`, `gsd-project`, `gsd-quality`, `gsd-context`, `gsd-manage`, `gsd-ideate` — sourced from `commands/gsd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. On runtimes with non-recursive skill loaders (cline, qwen, hermes, augment, trae) the installer now realizes this fully: it emits only the 6 namespace router bundles as top-level skills and nests the ~61 concrete skills under `<router>/skills/<name>/SKILL.md`, so the eager listing is ≈6 entries instead of ≈67. The model selects a namespace router, which instructs it to read the nested concrete skill file via a routing table embedded in the router body. On these runtimes concrete skills are **not** directly invocable by bare name via the Skill tool; they are reachable through the router. Slash commands (`/gsd-*`, via the separate commands surface) are unaffected where the runtime has one. On runtimes with recursive or unconfirmed skill loaders (claude global, cursor, codex, copilot, windsurf, codebuddy, opencode, kilo, antigravity) the layout remains flat — all skills emitted at the top level as before. Antigravity moved from nested to flat in #1614: `agy` scans only `skills/<name>/SKILL.md`, so nested sub-skills were unreachable. Claude was reverted to flat in #924: the Skill tool hard-errors on unknown names rather than re-routing via the router, so nested concrete skills were uninvokable.
To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`msd-workflow`, `msd-project`, `msd-quality`, `msd-context`, `msd-manage`, `msd-ideate` — sourced from `commands/msd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. On runtimes with non-recursive skill loaders (cline, qwen, hermes, augment, trae) the installer now realizes this fully: it emits only the 6 namespace router bundles as top-level skills and nests the ~61 concrete skills under `<router>/skills/<name>/SKILL.md`, so the eager listing is ≈6 entries instead of ≈67. The model selects a namespace router, which instructs it to read the nested concrete skill file via a routing table embedded in the router body. On these runtimes concrete skills are **not** directly invocable by bare name via the Skill tool; they are reachable through the router. Slash commands (`/msd-*`, via the separate commands surface) are unaffected where the runtime has one. On runtimes with recursive or unconfirmed skill loaders (claude global, cursor, codex, copilot, windsurf, codebuddy, opencode, kilo, antigravity) the layout remains flat — all skills emitted at the top level as before. Antigravity moved from nested to flat in #1614: `agy` scans only `skills/<name>/SKILL.md`, so nested sub-skills were unreachable. Claude was reverted to flat in #924: the Skill tool hard-errors on unknown names rather than re-routing via the router, so nested concrete skills were uninvokable.
The router descriptions use pipe-separated keyword tags (≤ 60 chars) per the Tool Attention research showing keyword-dense tags outperform prose for routing at ~40 % the token cost.
#### MCP token-budget interaction
The eager skill listing is one of two recurring per-turn token costs. The other is the MCP tool schema injected by every enabled MCP server in `.claude/settings.json`. Heavyweight MCP servers (browser/playwright, Mac-tools, Windows-tools) can each cost 20 k+ tokens per turn — often dwarfing what `model_profile` tuning saves. The toggle lives in the Claude Code harness (`enabledMcpjsonServers` / `disabledMcpjsonServers` in `.claude/settings.json`) and is **not** a GSD concern. Together, the two-stage routing layer (#2792) and disciplined MCP enablement are the largest cost levers per turn. See [`docs/USER-GUIDE.md`](USER-GUIDE.md) and `references/context-budget.md` for the audit checklist.
The eager skill listing is one of two recurring per-turn token costs. The other is the MCP tool schema injected by every enabled MCP server in `.claude/settings.json`. Heavyweight MCP servers (browser/playwright, Mac-tools, Windows-tools) can each cost 20 k+ tokens per turn — often dwarfing what `model_profile` tuning saves. The toggle lives in the Claude Code harness (`enabledMcpjsonServers` / `disabledMcpjsonServers` in `.claude/settings.json`) and is **not** a MSD concern. Together, the two-stage routing layer (#2792) and disciplined MCP enablement are the largest cost levers per turn. See [`docs/USER-GUIDE.md`](USER-GUIDE.md) and `references/context-budget.md` for the audit checklist.
### Workflows (`gsd-core/workflows/*.md`)
### Workflows (`msd-core/workflows/*.md`)
Orchestration logic that commands reference. Contains the step-by-step process including:
- Context loading via `gsd-tools.cjs init` handlers
- Context loading via `msd-tools.cjs init` handlers
- Agent spawn instructions with model resolution
- Gate/checkpoint definitions
- State update patterns
@@ -145,7 +145,7 @@ Orchestration logic that commands reference. Contains the step-by-step process i
#### Progressive disclosure for workflows
Workflow files are loaded verbatim into Claude's context every time the
corresponding `/gsd-*` command is invoked. The workflow size budget enforced by
corresponding `/msd-*` command is invoked. The workflow size budget enforced by
`tests/workflow-size-budget.test.cjs` keeps each file bounded, mirroring the
the agent size-budget convention. The budget is measured in **bytes** (#717), not lines:
line count over-penalizes prose and under-catches token-dense tables and code
@@ -183,7 +183,7 @@ the discuss-phase byte budget (#717; the discuss-phase/modes split keeps it ≈3
beyond its tier, extract per-mode bodies into
`workflows/<workflow>/modes/<mode>.md`, templates into
`workflows/<workflow>/templates/`, and shared knowledge into
`gsd-core/references/`. The parent file becomes a thin dispatcher that
`msd-core/references/`. The parent file becomes a thin dispatcher that
Reads only the mode and template files needed for the current invocation.
`workflows/discuss-phase/` is the canonical example of this pattern —
@@ -194,7 +194,7 @@ checkpoint.json schemas that are read only when the corresponding output
file is being written.
`workflows/plan-phase.md`, `workflows/execute-phase.md`, and the
`gsd-planner` / `gsd-executor` agent definitions apply the same discipline
`msd-planner` / `msd-executor` agent definitions apply the same discipline
to their MVP-only reference bodies — `planner-mvp-mode.md`,
`user-story-template.md`, `skeleton-template.md`, and `execute-mvp-tdd.md`
are referenced for the planner/executor to Read only on MVP,
@@ -214,7 +214,7 @@ Specialized agent definitions with frontmatter specifying:
**Total agents:** 33
### References (`gsd-core/references/*.md`)
### References (`msd-core/references/*.md`)
Shared knowledge documents that workflows and agents `@-reference` (see [`docs/INVENTORY.md`](INVENTORY.md#references) for the authoritative full roster):
@@ -252,7 +252,7 @@ Shared knowledge documents that workflows and agents `@-reference` (see [`docs/I
**Thinking model references:**
References for integrating thinking-class models (o3, o4-mini, Gemini 2.5 Pro) into GSD workflows:
References for integrating thinking-class models (o3, o4-mini, Gemini 2.5 Pro) into MSD workflows:
- `thinking-models-debug.md` — Thinking model patterns for debugging workflows
- `thinking-models-execution.md` — Thinking model patterns for execution agents
@@ -262,15 +262,15 @@ References for integrating thinking-class models (o3, o4-mini, Gemini 2.5 Pro) i
**Modular planner decomposition:**
The planner agent (`agents/gsd-planner.md`) was decomposed from a single monolithic file into a core agent plus reference modules to stay under the 50K character limit imposed by some runtimes:
The planner agent (`agents/msd-planner.md`) was decomposed from a single monolithic file into a core agent plus reference modules to stay under the 50K character limit imposed by some runtimes:
- `planner-gap-closure.md` — Gap closure mode behavior (reads VERIFICATION.md, targeted replanning)
- `planner-reviews.md` — Cross-AI review integration (reads REVIEWS.md from `/gsd-review`)
- `planner-reviews.md` — Cross-AI review integration (reads REVIEWS.md from `/msd-review`)
- `planner-revision.md` — Plan revision patterns for iterative refinement
### Templates (`gsd-core/templates/`)
### Templates (`msd-core/templates/`)
Markdown templates for all planning artifacts. Used by `gsd-tools.cjs template fill` / `phase.scaffold` (and top-level `scaffold`) to create pre-structured files:
Markdown templates for all planning artifacts. Used by `msd-tools.cjs template fill` / `phase.scaffold` (and top-level `scaffold`) to create pre-structured files:
- `project.md`, `requirements.md`, `roadmap.md`, `state.md` — Core project files
- `phase-prompt.md` — Phase execution prompt template
- `summary.md` (+ `summary-minimal.md`, `summary-standard.md`, `summary-complex.md`) — Granularity-aware summary templates
@@ -286,19 +286,19 @@ Runtime hooks that integrate with the host AI agent:
| Hook | Event | Purpose |
|------|-------|---------|
| `gsd-statusline.js` | `statusLine` | Displays model (long-context suffixes like `(1M context)` collapse to a compact `(1M)` badge), task, directory, and context usage bar |
| `gsd-context-monitor.js` | `PostToolUse` / `AfterTool` | Injects agent-facing context warnings at 35%/25% remaining by default (configurable — see [CONFIGURATION.md](CONFIGURATION.md)) |
| `gsd-check-update.js` | `SessionStart` | Foreground trigger for the background update check |
| `gsd-ensure-canonical-path.js` | `SessionStart` | For Claude Code plugin installs, symlinks `~/.claude/gsd-core/{bin,contexts,references,templates,workflows}` to the plugin's bundled tree so `@~/.claude/gsd-core/...` includes resolve; runs first in `SessionStart`, no-op in classic installs, self-heals after `claude plugin update` (#997) |
| `gsd-check-update-worker.js` | (helper) | Background worker spawned by `gsd-check-update.js`; no direct event registration |
| `gsd-prompt-guard.js` | `PreToolUse` | Scans `.planning/` writes for prompt injection patterns (advisory) |
| `gsd-read-injection-scanner.js` | `PostToolUse` | Scans Read tool output for injected instructions in untrusted content |
| `gsd-workflow-guard.js` | `PreToolUse` | Detects file edits outside GSD workflow context (advisory, opt-in via `hooks.workflow_guard`) |
| `gsd-secret-read-guard.js` | `PreToolUse` | Hard-blocks Read / Grep / Bash reads of `.env`, `.env.<suffix>` (templates such as `.env.example` exempt) and `.secrets`; replaces the installer-written `Read(.env*)` permission deny rules, which made every `cd DIR && grep …` compound prompt for approval on Claude Code ≥ 2.1.259 (#4221) |
| `gsd-read-guard.js` | `PreToolUse` | Advisory guard preventing Edit/Write on files not yet read in the session |
| `gsd-session-state.sh` | `SessionStart` | Session state tracking for shell-based runtimes |
| `gsd-validate-commit.sh` | `PreToolUse` | Commit validation for conventional commit enforcement |
| `gsd-phase-boundary.sh` | `PostToolUse` | Phase boundary detection for workflow transitions |
| `msd-statusline.js` | `statusLine` | Displays model (long-context suffixes like `(1M context)` collapse to a compact `(1M)` badge), task, directory, and context usage bar |
| `msd-context-monitor.js` | `PostToolUse` / `AfterTool` | Injects agent-facing context warnings at 35%/25% remaining by default (configurable — see [CONFIGURATION.md](CONFIGURATION.md)) |
| `msd-check-update.js` | `SessionStart` | Foreground trigger for the background update check |
| `msd-ensure-canonical-path.js` | `SessionStart` | For Claude Code plugin installs, symlinks `~/.claude/msd-core/{bin,contexts,references,templates,workflows}` to the plugin's bundled tree so `@~/.claude/msd-core/...` includes resolve; runs first in `SessionStart`, no-op in classic installs, self-heals after `claude plugin update` (#997) |
| `msd-check-update-worker.js` | (helper) | Background worker spawned by `msd-check-update.js`; no direct event registration |
| `msd-prompt-guard.js` | `PreToolUse` | Scans `.planning/` writes for prompt injection patterns (advisory) |
| `msd-read-injection-scanner.js` | `PostToolUse` | Scans Read tool output for injected instructions in untrusted content |
| `msd-workflow-guard.js` | `PreToolUse` | Detects file edits outside MSD workflow context (advisory, opt-in via `hooks.workflow_guard`) |
| `msd-secret-read-guard.js` | `PreToolUse` | Hard-blocks Read / Grep / Bash reads of `.env`, `.env.<suffix>` (templates such as `.env.example` exempt) and `.secrets`; replaces the installer-written `Read(.env*)` permission deny rules, which made every `cd DIR && grep …` compound prompt for approval on Claude Code ≥ 2.1.259 (#4221) |
| `msd-read-guard.js` | `PreToolUse` | Advisory guard preventing Edit/Write on files not yet read in the session |
| `msd-session-state.sh` | `SessionStart` | Session state tracking for shell-based runtimes |
| `msd-validate-commit.sh` | `PreToolUse` | Commit validation for conventional commit enforcement |
| `msd-phase-boundary.sh` | `PostToolUse` | Phase boundary detection for workflow transitions |
See [`docs/INVENTORY.md`](INVENTORY.md#hooks) for the authoritative hook roster.
@@ -308,19 +308,19 @@ stderrPayload?)` (exit 2), or `crash(onCrash, payload)` — the last dispatching
per a `HOOK_ON_CRASH` policy the hook must declare explicitly (`ALLOW` or
`DENY`, no default), so a hook's fail-open/fail-closed stance is a visible
declaration rather than an inference from a bare `process.exit(N)`. Two hooks
are deliberate exceptions — `gsd-read-injection-scanner.js` (PostToolUse) and
`gsd-cursor-subagent-start.js` (Cursor) — whose harnesses read the block
are deliberate exceptions — `msd-read-injection-scanner.js` (PostToolUse) and
`msd-cursor-subagent-start.js` (Cursor) — whose harnesses read the block
decision from the JSON response body at exit 0, not from the exit code, so
they never call `deny()`. See
[Declare a hook's crash policy](how-to/declare-a-hook-crash-policy.md).
### Command Routing Hub (`gsd-core/bin/lib/command-routing-hub.cjs`)
### Command Routing Hub (`msd-core/bin/lib/command-routing-hub.cjs`)
CJS command family routers dispatch through `CommandRoutingHub`. The hub owns the no-throw pure-result contract (`hub.dispatch()` catches internal exceptions and returns `{ ok: false, kind, ...typedPayload }`) and the closed runtime error taxonomy (`UnknownCommand`, `InvalidArgs`, `HandlerRefusal`, `HandlerFailure`). Router adapters remain thin CLI translators — they build the hub, call `dispatch`, then map the Result to `output()`/`error()` calls. The runtime is single-path (no dual-runtime mode selection). See `docs/adr/0174-retire-gsd-sdk-package-boundary.md`.
CJS command family routers dispatch through `CommandRoutingHub`. The hub owns the no-throw pure-result contract (`hub.dispatch()` catches internal exceptions and returns `{ ok: false, kind, ...typedPayload }`) and the closed runtime error taxonomy (`UnknownCommand`, `InvalidArgs`, `HandlerRefusal`, `HandlerFailure`). Router adapters remain thin CLI translators — they build the hub, call `dispatch`, then map the Result to `output()`/`error()` calls. The runtime is single-path (no dual-runtime mode selection). See `docs/adr/0174-retire-msd-sdk-package-boundary.md`.
> **Planned (ADR-2346 / epic #2345):** the `runCommand` 73-case switch is being dissolved into a two-layer dispatch — families via the `commandFamilies` registry (ADR-959 mechanism, completed) and single-purpose leaf verbs via a table filling the prepared `_dispatchNonFamily` seam — collapsing `runCommand` to a ~15-line dispatcher. Behavior-preserving; tracked phase-by-phase under epic #2345. The current-state description above holds until each phase lands.
### Capability Command Dispatch (`gsd-core/bin/gsd-tools.cjs`, ADR-1244 D7)
### Capability Command Dispatch (`msd-core/bin/msd-tools.cjs`, ADR-1244 D7)
Command families declared by capabilities (`commands: [{ family, module, router }]`) are dispatched from the registry rather than a hardcoded switch. The `runCommand` default arm tries, in order:
@@ -331,15 +331,15 @@ Both paths share the same guards: prototype-pollution-safe command keys, an own-
### Reviewer-Lane Capability Trait (#4209, ADR-2782)
`/gsd-code-review` optionally corroborates its internal review with external reviewer lanes (`--codex`, `--agy`, ...), gated by the reusable `supportsReviewerLanes` capability-step trait and dispatched through the single `dispatchReviewerLanes` interpreter — see `gsd-core/references/loop-hook-dispatch.md` for the trait and `src/reviewer-step-dispatch.cts` for the interpreter's fail-closed contract. `gsd-code-reviewer` is the sole consolidator: it independently re-verifies every external claim against the actual source before writing anything to `REVIEW.md`, so a lane's evidence is corroborating input, never a second output schema.
`/msd-code-review` optionally corroborates its internal review with external reviewer lanes (`--codex`, `--agy`, ...), gated by the reusable `supportsReviewerLanes` capability-step trait and dispatched through the single `dispatchReviewerLanes` interpreter — see `msd-core/references/loop-hook-dispatch.md` for the trait and `src/reviewer-step-dispatch.cts` for the interpreter's fail-closed contract. `msd-code-reviewer` is the sole consolidator: it independently re-verifies every external claim against the actual source before writing anything to `REVIEW.md`, so a lane's evidence is corroborating input, never a second output schema.
### Research Module (`src/research-{store,provider}.cts`, `src/package-legitimacy.cts`)
The Research Module implements an **L2-hybrid seam**: code owns the cache, provider policy, and package legitimacy verdicts; MCP owns the actual network fetch.
Three compiled modules (generated to `gsd-core/bin/lib/*.cjs` per ADR-457) are reachable via `gsd-tools query research-plan | research-store | package-legitimacy`:
Three compiled modules (generated to `msd-core/bin/lib/*.cjs` per ADR-457) are reachable via `msd-tools query research-plan | research-store | package-legitimacy`:
- **Research Store** — content-addressed cache (`sha256(ecosystem+library+version+query+kind)`) with per-source TTL (curated-doc: 30 d, medium: 7 d, web/synthesis: 1 d) and two storage tiers: `~/.gsd/research-cache` for cross-project curated-doc hits, `.planning/research/.cache` for project-local web/synthesis results.
- **Research Store** — content-addressed cache (`sha256(ecosystem+library+version+query+kind)`) with per-source TTL (curated-doc: 30 d, medium: 7 d, web/synthesis: 1 d) and two storage tiers: `~/.msd/research-cache` for cross-project curated-doc hits, `.planning/research/.cache` for project-local web/synthesis results.
- **Research Provider** — single `PROVIDER_WATERFALL` (`Context7→Ref→Jina→websearch` for docs; `Exa→Tavily→Perplexity→Brave→websearch` for web; `Firecrawl→Jina` for scrape-only). `planResearch()` returns cache hits plus a fetch plan; `classifyConfidence()` stamps `HIGH|MEDIUM|LOW` by provider tier.
- **Package Legitimacy** — registry-API verdicts (npm/PyPI/crates.io injectable adapters) producing `OK|SUS|SLOP` per package. `slopcheck` is an optional escalate-only adapter; absence leaves registry verdicts intact rather than downgrading everything to `[ASSUMED]`.
@@ -349,14 +349,14 @@ Three compiled modules (generated to `gsd-core/bin/lib/*.cjs` per ADR-457) are r
agent
│
▼
gsd-tools query research-plan ← Research Provider: check cache, build fetch plan
msd-tools query research-plan ← Research Provider: check cache, build fetch plan
│
├── [cache hits] ──────────────────► RESEARCH.md (digest only, no raw content)
│
└── [fetch plan] ──────────────────► MCP fetch (agent calls MCP tools with the plan)
│
▼
gsd-tools query research-store (put)
msd-tools query research-store (put)
│
▼
RESEARCH.md path returned to orchestrator
@@ -366,17 +366,17 @@ Agents always return a `RESEARCH.md` path, never raw fetched content. Context di
### Context Predicate Fact-Store (`src/context-predicates.cts`, ADR-1671)
The `CONTEXT.md` predicate fact-store — every backtick-wrapped `CLASS.subkey=value` declaration in the repo-root `CONTEXT.md` — has a compiled parser/selector seam (generated to `gsd-core/bin/lib/context-predicates.cjs` per ADR-457) reachable live via `gsd-tools query context-predicates --class|--prefix|--contains`. Fence-aware line skipping mirrors `markdown-sectionizer.cts`'s exported `scanFencedBlocks` delimiter-matching rule exactly (proven by a fence-skip parity test suite), but is scanned by a LOCAL, interleaved single pass rather than a call into that seam directly: fences and HTML comments must mutually suppress each other's open/close detection while either is active (a fence delimiter inside a real comment, or a comment token inside a real fence, must not falsely toggle the other construct), and that precedence cannot be resolved by two independent passes over `scanFencedBlocks`'s comment-blind output — see `src/context-predicates.cts`'s module doc comment.
The `CONTEXT.md` predicate fact-store — every backtick-wrapped `CLASS.subkey=value` declaration in the repo-root `CONTEXT.md` — has a compiled parser/selector seam (generated to `msd-core/bin/lib/context-predicates.cjs` per ADR-457) reachable live via `msd-tools query context-predicates --class|--prefix|--contains`. Fence-aware line skipping mirrors `markdown-sectionizer.cts`'s exported `scanFencedBlocks` delimiter-matching rule exactly (proven by a fence-skip parity test suite), but is scanned by a LOCAL, interleaved single pass rather than a call into that seam directly: fences and HTML comments must mutually suppress each other's open/close detection while either is active (a fence delimiter inside a real comment, or a comment token inside a real fence, must not falsely toggle the other construct), and that precedence cannot be resolved by two independent passes over `scanFencedBlocks`'s comment-blind output — see `src/context-predicates.cts`'s module doc comment.
`scripts/gen-context-index.cjs --check` is the CI drift-guard for the committed `docs/CONTEXT-INDEX.json` artifact: it fails on staleness between a fresh parse of `CONTEXT.md` and the committed file, and on any duplicate predicate ID. It is wired into `lint:generated-sync` (so `lint:ci`, so CI). `docs/CONTEXT-INDEX.json` is **generated — never hand-edit it**; regenerate with `gen-context-index.cjs --write` (also wired into `build`, after `build:lib`, and into `regen:derived`). The generator `require()`s the compiled `context-predicates.cjs`, so it must run after `build:lib` in any pipeline; `.github/workflows/test.yml` does this.
The committed index intentionally carries **no `line` field** for any predicate (ADR-1671 open question 4, resolved by #2928) — committed-but-uncompared metadata goes silently stale, the same defect class the drift-guard exists to catch, with the alarm removed. The live `gsd-tools query context-predicates` parse still returns `line`/`section` for callers that want to cite a source location. See [ADR-1671](adr/1671-dynamic-context-management-platform.md) and [CLI Tools Reference](CLI-TOOLS.md#query-context-predicates).
The committed index intentionally carries **no `line` field** for any predicate (ADR-1671 open question 4, resolved by #2928) — committed-but-uncompared metadata goes silently stale, the same defect class the drift-guard exists to catch, with the alarm removed. The live `msd-tools query context-predicates` parse still returns `line`/`section` for callers that want to cite a source location. See [ADR-1671](adr/1671-dynamic-context-management-platform.md) and [CLI Tools Reference](CLI-TOOLS.md#query-context-predicates).
### Workflow Fragmentization and Emission (`src/workflow-fragments.cts`, ADR-1671)
Workflow markdown under `gsd-core/workflows/*.md` can mark one or more sections with an
in-file `<!-- gsd:section id="<id>" when="<when>" -->` / `<!-- /gsd:section -->` pair. A
compiled parser/composer seam (generated to `gsd-core/bin/lib/workflow-fragments.cjs` per
Workflow markdown under `msd-core/workflows/*.md` can mark one or more sections with an
in-file `<!-- msd:section id="<id>" when="<when>" -->` / `<!-- /msd:section -->` pair. A
compiled parser/composer seam (generated to `msd-core/bin/lib/workflow-fragments.cjs` per
ADR-457) partitions a marked document into fragments and recomposes them through the shared
`context-composer.cjs` budget seam (ADR-1671, #2929) before any per-runtime converter sees the
text — so a marker attribute can never be corrupted by a `.claude/` → `.windsurf/`-style
@@ -400,10 +400,10 @@ in-file markers were chosen over separate fragment files or a sidecar manifest.
### Section Manifest (`src/section-manifest.cts`, ADR-1671 Phases 5 and 6.1)
Two seams turn a workflow's `gsd:section` markers into per-invocation applicability data.
Two seams turn a workflow's `msd:section` markers into per-invocation applicability data.
`scripts/gen-section-manifest.cjs --write` (wired into `build` after `build:lib`, and into
`lint:generated-sync`) scans `gsd-core/workflows/*.md` and writes the committed
`gsd-core/workflows/section-manifest.json`, keyed **per workflow** —
`lint:generated-sync`) scans `msd-core/workflows/*.md` and writes the committed
`msd-core/workflows/section-manifest.json`, keyed **per workflow** —
`{workflows: {"<name>": [{id, when, read}]}}` — where `read` is the path of the step file the
section's body was extracted to. A workflow with no marked sections contributes **no key at
all**: an absent key means degraded/unknown (the caller reads every section, the safe superset),
@@ -413,7 +413,7 @@ while a key present with an empty array means "computed, nothing applies". The g
references, or a committed artifact still carrying the pre-6.1 flat `{sections: [...]}` shape.
A separate pure evaluator, `src/section-manifest.cts` (compiled to
`gsd-core/bin/lib/section-manifest.cjs` per ADR-457), maps one invocation's facts —
`msd-core/bin/lib/section-manifest.cjs` per ADR-457), maps one invocation's facts —
`{flags, phaseNumber, hasPriorPhases}` plus the optional `needsCodebaseMap`, `phaseMvpMode` and
`worktreesEnabled` booleans — to an included/excluded partition of section ids via
`selectSections`. `flags` is a `ReadonlySet<string>` of flag tokens; because `parseNamedArgs`
@@ -428,12 +428,12 @@ without the latter would evaluate `false` forever and silently disable its own s
`execute-phase.md`'s `partial-wave` and `gap-closure-artifacts` sections — previously inlined
directly per #2930's pilot — now delegate to dedicated step files under
`gsd-core/workflows/execute-phase/steps/`, the same pattern the pre-existing `regression-gate`
`msd-core/workflows/execute-phase/steps/`, the same pattern the pre-existing `regression-gate`
section already used.
### CLI Tools (`gsd-core/bin/`)
### CLI Tools (`msd-core/bin/`)
Node.js CLI utility (`gsd-tools.cjs`) with domain modules split across `gsd-core/bin/lib/` (see [`docs/INVENTORY.md`](INVENTORY.md#cli-modules) for the authoritative roster):
Node.js CLI utility (`msd-tools.cjs`) with domain modules split across `msd-core/bin/lib/` (see [`docs/INVENTORY.md`](INVENTORY.md#cli-modules) for the authoritative roster):
| Module | Responsibility |
@@ -468,14 +468,14 @@ Node.js CLI utility (`gsd-tools.cjs`) with domain modules split across `gsd-core
| `profile-output.cjs` | Profile rendering, USER-PROFILE.md and dev-preferences.md generation |
| `context-predicates.cjs` | `CONTEXT.md` predicate fact-store parser/selector (ADR-1671, #2928); backs `query context-predicates` and `scripts/gen-context-index.cjs`'s `docs/CONTEXT-INDEX.json` drift guard; compiled from `src/context-predicates.cts` |
| `loop-host-contract.cjs` | Generated Loop Host Contract — 12 loop points, per-step agent roles, and core artifacts; emitted by `scripts/gen-loop-host-contract.cjs` from workflow markers (ADR-894 §3); consumed by `gen-capability-registry.cjs` |
| `capability-loader.cjs` | Runtime registry overlay loader (ADR-1244 D2) — `loadRegistry({ includeInstalled })` composes the frozen first-party registry with a validated installed overlay of third-party capability manifests read from global `$GSD_HOME/.gsd/capabilities/` and project `<projectRoot>/.gsd/capabilities/`; first-party always wins; load-time `engines.gsd` re-gate skips incompatible overlays with a warning; gate-kind hooks on skipped capabilities fail OPEN — no gate is injected; a loud warning (stderr + envelope `warnings`) names the load failure and the `gsd capability remove <id>` remediation (#2009) |
| `capability-loader.cjs` | Runtime registry overlay loader (ADR-1244 D2) — `loadRegistry({ includeInstalled })` composes the frozen first-party registry with a validated installed overlay of third-party capability manifests read from global `$MSD_HOME/.msd/capabilities/` and project `<projectRoot>/.msd/capabilities/`; first-party always wins; load-time `engines.msd` re-gate skips incompatible overlays with a warning; gate-kind hooks on skipped capabilities fail OPEN — no gate is injected; a loud warning (stderr + envelope `warnings`) names the load failure and the `msd capability remove <id>` remediation (#2009) |
| `capability-registry.cjs` | Generated central Capability Registry — role-partitioned index of all co-located capability declarations; emitted by `scripts/gen-capability-registry.cjs` (ADR-894 §5) |
| `loop-resolver.cjs` | Loop Extension Point resolver — ADR-857 phase 3c registry-consuming query; consumes resolved Capability State, filters `byLoopPoint` by capability enablement plus config activation, renders active hooks as markdown, emits `{ point, activeHooks, rendered }` envelope; `gsd-tools loop render-hooks <point> [--config-dir <path>]` |
| `capability-state.cjs` | Unified capability-state resolver — ADR-857 phase 4b/6; composes install profile, runtime surface, and config activation into one per-capability view consumed by workflow hook rendering; pure `resolveCapabilityState`, reusable `resolveCapabilityRuntimeState`, I/O `cmdCapabilityState`, and convenience predicate `isCapabilityActive(capId, cwd)`; `gsd-tools capability state [--config-dir <path>]` emits `{ runtimeConfigDir, capabilities[] }` where each entry carries `enabled` (installed && surfaced) and `active` (enabled && configActivation via the capability's `activationKey`; absent key → active===enabled) |
| `loop-resolver.cjs` | Loop Extension Point resolver — ADR-857 phase 3c registry-consuming query; consumes resolved Capability State, filters `byLoopPoint` by capability enablement plus config activation, renders active hooks as markdown, emits `{ point, activeHooks, rendered }` envelope; `msd-tools loop render-hooks <point> [--config-dir <path>]` |
| `capability-state.cjs` | Unified capability-state resolver — ADR-857 phase 4b/6; composes install profile, runtime surface, and config activation into one per-capability view consumed by workflow hook rendering; pure `resolveCapabilityState`, reusable `resolveCapabilityRuntimeState`, I/O `cmdCapabilityState`, and convenience predicate `isCapabilityActive(capId, cwd)`; `msd-tools capability state [--config-dir <path>]` emits `{ runtimeConfigDir, capabilities[] }` where each entry carries `enabled` (installed && surfaced) and `active` (enabled && configActivation via the capability's `activationKey`; absent key → active===enabled) |
| `capability-validator.cjs` | Shared capability conformance validator (ADR-1244 D2) — extracted from `scripts/gen-capability-registry.cjs` so the build-time generator and the runtime overlay loader share one `validateCapability(manifest)` implementation; generative-parity is CI-guarded |
| `graphify-command-router.cjs` | ADR-959 capability command router — first real capability command cutover (phase 4d-impl-2); extracted from the `case 'graphify':` arm in `gsd-tools.cjs`; dispatches build/query/status/diff subcommands; discovered via `commandFamilies` in the capability registry |
| `audit-command-router.cjs` | ADR-959 capability command router (phase 4d-impl-3); extracted from the `case 'audit-uat':` and `case 'audit-open':` arms in `gsd-tools.cjs`; `routeAuditUat` → `uat.cjs:cmdAuditUat`, `routeAuditOpen` → `audit.cjs:{auditOpenArtifacts,formatAuditReport}`; discovered via `commandFamilies` in the capability registry |
| `intel-command-router.cjs` | ADR-959 capability command router (phase 4d-impl-4, last first-party cutover); extracted from the `case 'intel':` arm in `gsd-tools.cjs`; `routeIntelCommand` → all 9 intel subcommands via lazy `require('./intel.cjs')`; preserves non-raw `timeAgo` transform on `status.files[*].updated_at`; discovered via `commandFamilies` in the capability registry |
| `graphify-command-router.cjs` | ADR-959 capability command router — first real capability command cutover (phase 4d-impl-2); extracted from the `case 'graphify':` arm in `msd-tools.cjs`; dispatches build/query/status/diff subcommands; discovered via `commandFamilies` in the capability registry |
| `audit-command-router.cjs` | ADR-959 capability command router (phase 4d-impl-3); extracted from the `case 'audit-uat':` and `case 'audit-open':` arms in `msd-tools.cjs`; `routeAuditUat` → `uat.cjs:cmdAuditUat`, `routeAuditOpen` → `audit.cjs:{auditOpenArtifacts,formatAuditReport}`; discovered via `commandFamilies` in the capability registry |
| `intel-command-router.cjs` | ADR-959 capability command router (phase 4d-impl-4, last first-party cutover); extracted from the `case 'intel':` arm in `msd-tools.cjs`; `routeIntelCommand` → all 9 intel subcommands via lazy `require('./intel.cjs')`; preserves non-raw `timeAgo` transform on `status.files[*].updated_at`; discovered via `commandFamilies` in the capability registry |
| `runtime-hooks-surface.cjs` | Hook-surface writer and configured-entrypoint validation module (ADR-857 phase 5f-1); owns Cline rules/agents-md/pre-tool-use hook generation, Cursor/Windsurf `hooks.json`, Kimi hook TOML, Copilot session-hook config, Codex hook-block management, and construction-time records for paths emitted into runtime configuration. Installer success requires those records to pass non-executing file-type and interpreter-resolution checks. |
@@ -488,10 +488,10 @@ Node.js CLI utility (`gsd-tools.cjs`) with domain modules split across `gsd-core
```
Orchestrator (workflow .md)
│
├── Load context: gsd-tools.cjs init <workflow> <phase>
├── Load context: msd-tools.cjs init <workflow> <phase>
│ Returns JSON with: project info, config, state, phase details
│
├── Resolve model: gsd-tools.cjs resolve-model <agent-name>
├── Resolve model: msd-tools.cjs resolve-model <agent-name>
│ Returns: opus | sonnet | haiku | inherit
│
├── Spawn Agent (Task/SubAgent call)
@@ -502,28 +502,28 @@ Orchestrator (workflow .md)
│
├── Collect result
│
└── Update state: gsd-tools.cjs state update / state patch / state advance-plan
└── Update state: msd-tools.cjs state update / state patch / state advance-plan
```
### Primary Agent Spawn Categories
Conceptual spawn-pattern taxonomy for the primary agents. For the authoritative agent roster (including the advanced/specialized agents such as `gsd-pattern-mapper`, `gsd-code-reviewer`, `gsd-code-fixer`, `gsd-ai-researcher`, `gsd-domain-researcher`, `gsd-eval-planner`, `gsd-eval-auditor`, `gsd-framework-selector`, `gsd-debug-session-manager`, `gsd-intel-updater`), see [`docs/INVENTORY.md`](INVENTORY.md#agents).
Conceptual spawn-pattern taxonomy for the primary agents. For the authoritative agent roster (including the advanced/specialized agents such as `msd-pattern-mapper`, `msd-code-reviewer`, `msd-code-fixer`, `msd-ai-researcher`, `msd-domain-researcher`, `msd-eval-planner`, `msd-eval-auditor`, `msd-framework-selector`, `msd-debug-session-manager`, `msd-intel-updater`), see [`docs/INVENTORY.md`](INVENTORY.md#agents).
| Category | Agents | Parallelism |
| ---------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **Researchers** | gsd-project-researcher, gsd-phase-researcher, gsd-ui-researcher, gsd-advisor-researcher | 4 parallel (stack, features, architecture, pitfalls); advisor spawns during discuss-phase |
| **Synthesizers** | gsd-research-synthesizer | Sequential (after researchers complete) |
| **Planners** | gsd-planner, gsd-roadmapper | Sequential |
| **Checkers** | gsd-plan-checker, gsd-integration-checker, gsd-ui-checker, gsd-nyquist-auditor | Sequential (verification loop, max 3 iterations) |
| **Executors** | gsd-executor | Parallel within waves, sequential across waves |
| **Verifiers** | gsd-verifier | Sequential (after all executors complete) |
| **Mappers** | gsd-codebase-mapper | 4 parallel (tech, arch, quality, concerns) |
| **Debuggers** | gsd-debugger | Sequential (interactive) |
| **Auditors** | gsd-ui-auditor, gsd-security-auditor | Sequential |
| **Doc Writers** | gsd-doc-writer, gsd-doc-verifier | Sequential (writer then verifier) |
| **Profilers** | gsd-user-profiler | Sequential |
| **Analyzers** | gsd-assumptions-analyzer | Sequential (during discuss-phase) |
| **Researchers** | msd-project-researcher, msd-phase-researcher, msd-ui-researcher, msd-advisor-researcher | 4 parallel (stack, features, architecture, pitfalls); advisor spawns during discuss-phase |
| **Synthesizers** | msd-research-synthesizer | Sequential (after researchers complete) |
| **Planners** | msd-planner, msd-roadmapper | Sequential |
| **Checkers** | msd-plan-checker, msd-integration-checker, msd-ui-checker, msd-nyquist-auditor | Sequential (verification loop, max 3 iterations) |
| **Executors** | msd-executor | Parallel within waves, sequential across waves |
| **Verifiers** | msd-verifier | Sequential (after all executors complete) |
| **Mappers** | msd-codebase-mapper | 4 parallel (tech, arch, quality, concerns) |
| **Debuggers** | msd-debugger | Sequential (interactive) |
| **Auditors** | msd-ui-auditor, msd-security-auditor | Sequential |
| **Doc Writers** | msd-doc-writer, msd-doc-verifier | Sequential (writer then verifier) |
| **Profilers** | msd-user-profiler | Sequential |
| **Analyzers** | msd-assumptions-analyzer | Sequential (during discuss-phase) |
### Wave Execution Model
@@ -553,7 +553,7 @@ When the context window is 500K+ tokens (1M-class models like Opus 4.6, Sonnet 4
- **Executor agents** receive prior wave SUMMARY.md files and the phase CONTEXT.md/RESEARCH.md, enabling cross-plan awareness within a phase
- **Verifier agents** receive all PLAN.md, SUMMARY.md, CONTEXT.md files plus REQUIREMENTS.md, enabling history-aware verification
The orchestrator reads `context_window` from config (`gsd-tools.cjs config-get context_window`) and conditionally includes richer context when the value is >= 500,000. For standard 200K windows, prompts use truncated versions with cache-friendly ordering to maximize context efficiency.
The orchestrator reads `context_window` from config (`msd-tools.cjs config-get context_window`) and conditionally includes richer context when the value is >= 500,000. For standard 200K windows, prompts use truncated versions with cache-friendly ordering to maximize context efficiency.
#### Parallel Commit Safety
@@ -572,7 +572,7 @@ STATE.md carries the same fact in two places — YAML frontmatter and the docume
**The pipeline's precondition is a type, not a convention (ADR-3473 §8.6).** A policy row can only be honored if the pre-write frontmatter snapshot it compares against is actually present. That snapshot now travels as a `StateTransaction`, built by `openStateTransaction()` — preservation applies — or `rebuildStateTransaction()` — it does not. Both carry the snapshot, and a transaction cannot be constructed without one: an absent snapshot is a *construction failure*, not a runtime skip. That distinction is the whole point. Previously the snapshot was nulled to signal "re-derive from disk", so a declared `preserve-always` row and a silently-skipped one were indistinguishable at runtime, which is how a curated `progress:` block was erased by verbs that had nothing to do with progress.
`rebuildStateTransaction()` is the typed form of ADR-3408 §8.3's closed exception list: `state sync`, which exists to let the body win, and `/gsd-health --repair`'s factory reset. Both are deliberate and permanent, not debt — and because the type names them, the write-path drift guard no longer has to track them as strings in a ratcheted baseline.
`rebuildStateTransaction()` is the typed form of ADR-3408 §8.3's closed exception list: `state sync`, which exists to let the body win, and `/msd-health --repair`'s factory reset. Both are deliberate and permanent, not debt — and because the type names them, the write-path drift guard no longer has to track them as strings in a ratcheted baseline.
**What a command reports it wrote is the same snapshot, read back (ADR-3473 §8.7).** Every `state.*` command returns an `updated` array. That array is now derived by comparing what was actually persisted against the transaction's pre-write snapshot: **a field appears if, and only if, its persisted value changed.** One comparison answers both of the questions that used to need separate machinery — a field the caller asked for that the pipeline then discarded is persisted-equals-snapshot and drops out, and a field nobody asked for that the write moved anyway is different and appears. Nothing is filtered by its preservation policy.
@@ -681,12 +681,12 @@ UI-SPEC.md (per phase) ───────────────────
```
~/.claude/ # Claude Code (global install)
├── skills/gsd-ns-*/SKILL.md # Global skills — nesting runtimes: 6 namespace routers (authoritative roster: docs/INVENTORY.md)
├── skills/msd-ns-*/SKILL.md # Global skills — nesting runtimes: 6 namespace routers (authoritative roster: docs/INVENTORY.md)
│ └── skills/<name>/SKILL.md # concrete skills nested under each router
│ (flat runtimes: skills/gsd-*/SKILL.md — all ~67 skills at top level)
├── commands/gsd/*.md # Local Claude installs use slash commands instead of global skills
├── gsd-core/
│ ├── bin/gsd-tools.cjs # CLI utility
│ (flat runtimes: skills/msd-*/SKILL.md — all ~67 skills at top level)
├── commands/msd/*.md # Local Claude installs use slash commands instead of global skills
├── msd-core/
│ ├── bin/msd-tools.cjs # CLI utility
│ ├── bin/lib/*.cjs # Domain modules (authoritative roster: docs/INVENTORY.md)
│ ├── workflows/*.md # Workflow definitions (authoritative roster: docs/INVENTORY.md)
│ ├── references/*.md # Shared reference docs (authoritative roster: docs/INVENTORY.md)
@@ -725,14 +725,14 @@ Equivalent paths for other runtimes:
├── STATE.md # Living memory: position, decisions, blockers, metrics
├── config.json # Workflow configuration
├── MILESTONES.md # Completed milestone archive
├── research/ # Domain research from /gsd-new-project
├── research/ # Domain research from /msd-new-project
│ ├── SUMMARY.md
│ ├── STACK.md
│ ├── FEATURES.md
│ ├── ARCHITECTURE.md
│ └── PITFALLS.md
├── codebase/ # Brownfield mapping (from /gsd-map-codebase or /gsd-onboard)
├── onboarding/ # Brownfield onboarding summary (from /gsd-onboard)
├── codebase/ # Brownfield mapping (from /msd-map-codebase or /msd-onboard)
├── onboarding/ # Brownfield onboarding summary (from /msd-onboard)
│ ├── STACK.md # YAML frontmatter carries `last_mapped_commit`
│ ├── ARCHITECTURE.md # for the post-execute drift gate (#2003)
│ ├── CONVENTIONS.md
@@ -758,19 +758,19 @@ Equivalent paths for other runtimes:
├── todos/
│ ├── pending/ # Captured ideas
│ └── completed/ # Completed todos
├── threads/ # Persistent context threads (from /gsd-thread)
├── seeds/ # Forward-looking ideas (from /gsd-capture --seed)
├── threads/ # Persistent context threads (from /msd-thread)
├── seeds/ # Forward-looking ideas (from /msd-capture --seed)
├── debug/ # Active debug sessions
│ ├── *.md # Active sessions
│ ├── resolved/ # Archived sessions
│ └── knowledge-base.md # Persistent debug learnings
├── ui-reviews/ # Screenshots from /gsd-ui-review (gitignored)
├── ui-reviews/ # Screenshots from /msd-ui-review (gitignored)
└── continue-here.md # Context handoff (from pause-work)
```
### Post-Execute Codebase Drift Gate (#2003)
After the last wave of `/gsd-execute-phase` commits, the workflow runs a
After the last wave of `/msd-execute-phase` commits, the workflow runs a
non-blocking `codebase_drift_gate` step (between `schema_drift_gate` and
`verify_phase_goal`). It compares the diff `last_mapped_commit..HEAD`
against `.planning/codebase/STRUCTURE.md` and counts four kinds of
@@ -782,9 +782,9 @@ structural elements:
4. New route modules under `routes/` or `api/`
If the count meets `workflow.drift_threshold` (default 3), the gate either
**warns** (default) with the suggested `/gsd-map-codebase --paths …` command,
**warns** (default) with the suggested `/msd-map-codebase --paths …` command,
or **auto-remaps** (`workflow.drift_action = auto-remap`) by spawning
`gsd-codebase-mapper` scoped to the affected paths. Any error in detection
`msd-codebase-mapper` scoped to the affected paths. Any error in detection
or remap is logged and the phase continues — drift detection cannot fail
verification.
@@ -792,7 +792,7 @@ verification.
`.planning/codebase/*.md` file; `bin/lib/drift.cjs` provides
`readMappedCommit` and `writeMappedCommit` round-trip helpers.
The baseline is written by `gsd-tools stamp-codebase-map`, a shell step in the
The baseline is written by `msd-tools stamp-codebase-map`, a shell step in the
map-codebase workflow, not by the mapper agent. The mapper's own freshness
markers (`**Analysis Date:**`, `<!-- refreshed: ... -->`) are restamped
unconditionally on an Update run, so an agent that rewrites only the dates still
@@ -822,22 +822,22 @@ The installer (`bin/install.js`, ~10,700 lines) handles:
- OpenCode: Converts commands/agents to OpenCode-compatible flat command + subagent format
- Kilo: Reuses the OpenCode conversion pipeline with Kilo config paths
- Codex: Generates TOML config + skills from commands
- Kimi CLI: Generates Agent Skills under `skills/gsd-*/SKILL.md`, custom agent YAML/prompt files, and explicit `kimi_cli.tools.*` module paths
- Kimi CLI: Generates Agent Skills under `skills/msd-*/SKILL.md`, custom agent YAML/prompt files, and explicit `kimi_cli.tools.*` module paths
- Copilot: Maps tool names (Read→read, Bash→execute, etc.)
- Antigravity: Skills-first with Google model equivalents; adjusts hook event names (`AfterTool` instead of `PostToolUse`)
- Cursor: Skills-first with Cursor rule references
- Windsurf: Skills-first with Windsurf rule references
- Trae: Skills-first install to `~/.trae` / `./.trae` with no `settings.json` or hook integration
- Qwen Code: Skills-first with Qwen-branded path and prompt rewrites
- Hermes Agent: Category-based skills under `skills/gsd/`
- Hermes Agent: Category-based skills under `skills/msd/`
- CodeBuddy: Skills-first with CodeBuddy path and prompt rewrites
- Cline: Writes `.clinerules` for rule-based integration
- Augment Code: Skills-first with full skill conversion and config management
5. **Path normalization** — Replaces `~/.claude/` paths with runtime-specific paths
6. **Settings integration** — Registers hooks in runtime's `settings.json`
7. **Patch backup** — Since v1.17, backs up locally modified files to `gsd-local-patches/` for `/gsd-update --reapply`
8. **Manifest tracking** — Writes `gsd-file-manifest.json` for clean uninstall. The manifest also records which `runtime` and which `scope` (`global`/`local`) wrote it, under a `manifestVersion` schema field, so a reader can answer "which surfaces are installed, at which scopes" without inferring it from the directory the file sits in ([ADR 2866](adr/2866-install-surface-resolution.md), #2872). Manifests written before that carry no such fields and are read without error — no reinstall is required. See [Installer Migrations → File Manifest](installer-migrations.md#file-manifest)
9. **Uninstall mode** — `--uninstall` removes all GSD files, hooks, and settings
7. **Patch backup** — Since v1.17, backs up locally modified files to `msd-local-patches/` for `/msd-update --reapply`
8. **Manifest tracking** — Writes `msd-file-manifest.json` for clean uninstall. The manifest also records which `runtime` and which `scope` (`global`/`local`) wrote it, under a `manifestVersion` schema field, so a reader can answer "which surfaces are installed, at which scopes" without inferring it from the directory the file sits in ([ADR 2866](adr/2866-install-surface-resolution.md), #2872). Manifests written before that carry no such fields and are read without error — no reinstall is required. See [Installer Migrations → File Manifest](installer-migrations.md#file-manifest)
9. **Uninstall mode** — `--uninstall` removes all MSD files, hooks, and settings
`installRuntimeArtifacts` (`install-engine.cjs`) returns the executed plan it ran — per kind, per
scope, including on the combined OpenCode/Kilo family path, which previously early-returned `void` —
@@ -877,22 +877,22 @@ The same switch gates a second, cross-artifact axis: a fact-drift pass that comp
```
Runtime Engine (Claude Code / Antigravity CLI)
│
├── statusLine event ──► gsd-statusline.js
├── statusLine event ──► msd-statusline.js
│ Reads: stdin (session JSON)
│ Writes: stdout (formatted status), /tmp/claude-ctx-{session}.json (bridge)
│
├── PostToolUse/AfterTool event ──► gsd-context-monitor.js
├── PostToolUse/AfterTool event ──► msd-context-monitor.js
│ Reads: stdin (tool event JSON), /tmp/claude-ctx-{session}.json (bridge)
│ Writes: stdout (hookSpecificOutput with additionalContext warning)
│
└── SessionStart event
├──► gsd-ensure-canonical-path.js (runs first)
│ Reads: ${CLAUDE_PLUGIN_ROOT}/gsd-core/ (plugin installs only)
│ Writes: ~/.claude/gsd-core/{bin,contexts,references,templates,workflows} symlinks
├──► msd-ensure-canonical-path.js (runs first)
│ Reads: ${CLAUDE_PLUGIN_ROOT}/msd-core/ (plugin installs only)
│ Writes: ~/.claude/msd-core/{bin,contexts,references,templates,workflows} symlinks
│ (no-op in classic installs; preserves user files; self-heals)
└──► gsd-check-update.js
└──► msd-check-update.js
Reads: VERSION file
Writes: ~/.claude/cache/gsd-update-check.json (spawns background process)
Writes: ~/.claude/cache/msd-update-check.json (spawns background process)
```
### Context Monitor Thresholds
@@ -924,15 +924,15 @@ Debounce: 5 tool uses between repeated warnings. Severity escalation (WARNING→
The researcher → planner → executor pipeline includes a supply-chain gate against slopsquatting (AI-hallucinated package names pre-registered with malicious post-install scripts).
**Threat model:** GSD automates the full path from "researcher names a package" to "executor runs `npm install`". A hallucinated name that passes `npm view` (proving only registration, not legitimacy) would previously flow through undetected. ~20% of AI-generated package references are hallucinated; ~43% of those names recur consistently across prompts, making pre-registration economically viable for attackers.
**Threat model:** MSD automates the full path from "researcher names a package" to "executor runs `npm install`". A hallucinated name that passes `npm view` (proving only registration, not legitimacy) would previously flow through undetected. ~20% of AI-generated package references are hallucinated; ~43% of those names recur consistently across prompts, making pre-registration economically viable for attackers.
**Gate layers:**
| Layer | Component | Action |
|-------|-----------|--------|
| Research | `gsd-phase-researcher` | Runs `gsd-tools query package-legitimacy check --ecosystem <npm\|pypi\|crates> <pkgs>`; writes `## Package Legitimacy Audit` table to RESEARCH.md; strips `[SLOP]` packages before RESEARCH.md is written |
| Planning | `gsd-planner` | Reads Audit table; inserts `checkpoint:human-verify` before any `[ASSUMED]` or `[SUS]` install task; adds `T-{phase}-SC` STRIDE supply-chain row to `<threat_model>` |
| Execution | `gsd-executor` | RULE 3 excludes package installation from auto-fix scope; failed installs surface as checkpoints, never silent substitutions |
| Research | `msd-phase-researcher` | Runs `msd-tools query package-legitimacy check --ecosystem <npm\|pypi\|crates> <pkgs>`; writes `## Package Legitimacy Audit` table to RESEARCH.md; strips `[SLOP]` packages before RESEARCH.md is written |
| Planning | `msd-planner` | Reads Audit table; inserts `checkpoint:human-verify` before any `[ASSUMED]` or `[SUS]` install task; adds `T-{phase}-SC` STRIDE supply-chain row to `<threat_model>` |
| Execution | `msd-executor` | RULE 3 excludes package installation from auto-fix scope; failed installs surface as checkpoints, never silent substitutions |
**Claim provenance integration:** Package names discovered via WebSearch are tagged `[ASSUMED]` (not `[VERIFIED]`) regardless of the registry-API verdict. This extends the existing `[ASSUMED]` / `[VERIFIED]` / `[CITED]` provenance system by enforcing the provenance tag as a hard gate at the install boundary — `[ASSUMED]` always generates a `checkpoint:human-verify` in PLAN.md.
@@ -946,29 +946,29 @@ The researcher → planner → executor pipeline includes a supply-chain gate ag
For a conceptual overview of how the hook and guard layers fit into the broader security approach, see [Security model](explanation/security-model.md).
**Prompt Guard** (`gsd-prompt-guard.js`):
**Prompt Guard** (`msd-prompt-guard.js`):
- Triggers on Write/Edit to `.planning/` files
- Scans content for prompt injection patterns (role override, instruction bypass, system tag injection)
- Advisory-only — logs detection, does not block
- Patterns are inlined (subset of `security.cjs`) for hook independence
- **Output contract:** `hookSpecificOutput` carries both `additionalContext` and `findings` — an array of `{ ruleId, match }` records (`INJECTION-PATTERN` or `INVISIBLE-UNICODE`), module-local to this hook (not shared with `gsd-read-injection-scanner.js`'s own `RULE_IDS`). The advisory is rendered from `findings` via a single mapper, so the two cannot disagree. Consumers should read `findings` rather than parsing the advisory text.
- **Output contract:** `hookSpecificOutput` carries both `additionalContext` and `findings` — an array of `{ ruleId, match }` records (`INJECTION-PATTERN` or `INVISIBLE-UNICODE`), module-local to this hook (not shared with `msd-read-injection-scanner.js`'s own `RULE_IDS`). The advisory is rendered from `findings` via a single mapper, so the two cannot disagree. Consumers should read `findings` rather than parsing the advisory text.
**Read Injection Scanner** (`gsd-read-injection-scanner.js`):
**Read Injection Scanner** (`msd-read-injection-scanner.js`):
- Triggers on `Read` / `WebFetch` / `WebSearch` PostToolUse events
- Advisory by default; blocks only `HIGH` severity, and only when `security.injection_blocking` is `true`
- Severity is `LOW` for 1-2 matched patterns, `HIGH` for 3 or more
- Skips content shorter than 20 characters, and skips excluded paths (`.planning/`, `REVIEW.md`, `CHECKPOINT*`, security/injection docs, and GSD's own staged hook bundle)
- Skips content shorter than 20 characters, and skips excluded paths (`.planning/`, `REVIEW.md`, `CHECKPOINT*`, security/injection docs, and MSD's own staged hook bundle)
- Rule ids: the `MD-LINK-*` markdown-link rules mirrored from `security.cjs`'s `MARKDOWN_LINK_PATTERNS`, plus `INJECTION-PATTERN`, `INVISIBLE-UNICODE`, and `UNICODE-TAG-BLOCK`
- Patterns are shared with `gsd-prompt-guard.js` via `hooks/lib/injection-patterns.js` (#3504); the markdown-link list is inlined for hook independence
- Patterns are shared with `msd-prompt-guard.js` via `hooks/lib/injection-patterns.js` (#3504); the markdown-link list is inlined for hook independence
- **Output contract:** `hookSpecificOutput` carries `additionalContext` (the human-readable advisory sentence), `findings` — an array of `{ ruleId, match }` records naming each rule that fired — plus `severity` (`LOW` for 1-2 matches, `HIGH` for 3+) and `source` (the scanned file path, URL, or `search: <query>` string). `findings` and `severity` are the structured surface; the advisory is rendered from them, so the three cannot disagree. `match` is `null` for rules with no captured text (`INVISIBLE-UNICODE`, `UNICODE-TAG-BLOCK`). Consumers should read `findings`/`severity`/`source` rather than parsing the advisory text.
**Workflow Guard** (`gsd-workflow-guard.js`):
**Workflow Guard** (`msd-workflow-guard.js`):
- Triggers on Write/Edit to non-`.planning/` files
- Detects edits outside GSD workflow context (no active `/gsd-` command or Task subagent)
- Advises using `/gsd-quick` or `/gsd-fast` for state-tracked changes
- Detects edits outside MSD workflow context (no active `/msd-` command or Task subagent)
- Advises using `/msd-quick` or `/msd-fast` for state-tracked changes
- Opt-in via `hooks.workflow_guard: true` (default: false)
- **Output contract:** the advisory leg's `hookSpecificOutput` carries `code: 'WORKFLOW_ADVISORY'` alongside `additionalContext`. This is distinct from the hook's separate force-add block leg (`code: 'WORKTREE_AGENT_FORCE_ADD_FORBIDDEN'`, `decision: 'block'`) — the two are disambiguated by `code`, never by presence.
@@ -976,7 +976,7 @@ For a conceptual overview of how the hook and guard layers fit into the broader
## Runtime Abstraction
GSD supports multiple AI coding runtimes through a unified command/workflow architecture:
MSD supports multiple AI coding runtimes through a unified command/workflow architecture:
### Runtime Install Contract Matrix
@@ -986,21 +986,21 @@ The migration-specific ownership and source snapshots live in
| Runtime | Global root | Local root | Invocation surface | Agent surface | Config and hooks |
| --- | --- | --- | --- | --- | --- |
| Claude Code | `~/.claude` | `./.claude` | Global `skills/gsd-*/SKILL.md` (flat, #924); local `commands/gsd/*.md` | `agents/gsd-*.md` | `settings.json` hook and statusLine entries |
| OpenCode | `~/.config/opencode` | `./.opencode` | `commands/gsd-*.md` | `agents/gsd-*.md` | `opencode.json` or `opencode.jsonc`; no GSD hooks |
| Kilo | `~/.config/kilo` | `./.kilo` | `command/gsd-*.md` | `agents/gsd-*.md` | `kilo.json` or `kilo.jsonc`; no GSD hooks |
| Kimi CLI | First-existing generic root: `~/.config/agents` recommended, then `~/.agents` when `~/.agents/skills` exists and `~/.config/agents/skills` does not | Deferred and guarded | `skills/gsd-*/SKILL.md` (flat) invoked as `/skill:gsd-*` | `agents/gsd.yaml`, `agents/gsd.md`, and `agents/subagents/gsd-*` YAML/prompt pairs | Explicit `kimi --agent-file <configRoot>/agents/gsd.yaml`; no GSD hooks or statusline |
| Codex | `~/.codex` | `./.codex` | `skills/gsd-*/SKILL.md` (flat) | `agents/` source markdown plus per-agent TOML (Codex auto-discovers each `agents/gsd-*.toml`; this is the sole canonical role registration, #2406) | `config.toml` bare `[agents]` dispatch-tuning scalar (`max_depth`, no per-role `[agents.gsd-*]` tables), `[features].hooks` (canonical; legacy alias `codex_hooks` is recognized and migrated forward on reinstall, #3566), and hook tables |
| GitHub Copilot | `~/.copilot` | `./.github` | `skills/gsd-*/SKILL.md` (flat), `copilot-instructions.md`, and `AGENTS.md` (repo root, local) | `.agent.md` files | Self-contained `sessionStart` hook (`hooks/gsd-session.json`, inline `command` type); no statusline |
| Antigravity | auto-detected: `~/.gemini/antigravity`, `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `./.agent` | `~/.gemini/config/skills/gsd-*/SKILL.md` (flat, #1614; global home override #3738) | `~/.gemini/config/agents/gsd-*.md` (#3738) | Gemini-style `settings.json` hook entries when installed by GSD |
| Cursor | `~/.cursor` | `./.cursor` | `skills/gsd-*/SKILL.md` (flat) | `agents/gsd-*.md` | Rule references under `rules/`; `hooks.json` with sessionStart context injection and postToolUse STATE.md monitor (#777) |
| Windsurf | `~/.codeium/windsurf` config | `./.windsurf` | `workflows/gsd-*.md` slash-command workflows | No custom-agent artifact surface | No GSD hooks |
| Augment Code | `~/.augment` | `./.augment` | `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/gsd-*.md` | No GSD hooks or statusline |
| Trae | `~/.trae` | `./.trae` | `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/gsd-*.md` | Rule references under `rules/`; no GSD hooks |
| Qwen Code | `~/.qwen` | `./.qwen` | `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/gsd-*.md` | Common GSD settings and hook entries where supported |
| Hermes Agent | `~/.hermes` | `./.hermes` | `skills/gsd/ns-*/SKILL.md` (6 routers, prefix='') + `skills/gsd/ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/gsd-*.md` | Common GSD settings and hook entries where supported |
| CodeBuddy | `~/.codebuddy` | `./.codebuddy` | `skills/gsd-*/SKILL.md` (flat, `user-invocable: false`) | `agents/gsd-*.md` | `/gsd-*` slash commands under `commands/`; common GSD settings and hook entries where supported |
| Cline | `~/.cline` | project root | `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills/<name>/SKILL.md` (nested concretes) + `.clinerules` | Rules only | No GSD hooks or statusline |
| Claude Code | `~/.claude` | `./.claude` | Global `skills/msd-*/SKILL.md` (flat, #924); local `commands/msd/*.md` | `agents/msd-*.md` | `settings.json` hook and statusLine entries |
| OpenCode | `~/.config/opencode` | `./.opencode` | `commands/msd-*.md` | `agents/msd-*.md` | `opencode.json` or `opencode.jsonc`; no MSD hooks |
| Kilo | `~/.config/kilo` | `./.kilo` | `command/msd-*.md` | `agents/msd-*.md` | `kilo.json` or `kilo.jsonc`; no MSD hooks |
| Kimi CLI | First-existing generic root: `~/.config/agents` recommended, then `~/.agents` when `~/.agents/skills` exists and `~/.config/agents/skills` does not | Deferred and guarded | `skills/msd-*/SKILL.md` (flat) invoked as `/skill:msd-*` | `agents/msd.yaml`, `agents/msd.md`, and `agents/subagents/msd-*` YAML/prompt pairs | Explicit `kimi --agent-file <configRoot>/agents/msd.yaml`; no MSD hooks or statusline |
| Codex | `~/.codex` | `./.codex` | `skills/msd-*/SKILL.md` (flat) | `agents/` source markdown plus per-agent TOML (Codex auto-discovers each `agents/msd-*.toml`; this is the sole canonical role registration, #2406) | `config.toml` bare `[agents]` dispatch-tuning scalar (`max_depth`, no per-role `[agents.msd-*]` tables), `[features].hooks` (canonical; legacy alias `codex_hooks` is recognized and migrated forward on reinstall, #3566), and hook tables |
| GitHub Copilot | `~/.copilot` | `./.github` | `skills/msd-*/SKILL.md` (flat), `copilot-instructions.md`, and `AGENTS.md` (repo root, local) | `.agent.md` files | Self-contained `sessionStart` hook (`hooks/msd-session.json`, inline `command` type); no statusline |
| Antigravity | auto-detected: `~/.gemini/antigravity`, `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `./.agent` | `~/.gemini/config/skills/msd-*/SKILL.md` (flat, #1614; global home override #3738) | `~/.gemini/config/agents/msd-*.md` (#3738) | Gemini-style `settings.json` hook entries when installed by MSD |
| Cursor | `~/.cursor` | `./.cursor` | `skills/msd-*/SKILL.md` (flat) | `agents/msd-*.md` | Rule references under `rules/`; `hooks.json` with sessionStart context injection and postToolUse STATE.md monitor (#777) |
| Windsurf | `~/.codeium/windsurf` config | `./.windsurf` | `workflows/msd-*.md` slash-command workflows | No custom-agent artifact surface | No MSD hooks |
| Augment Code | `~/.augment` | `./.augment` | `skills/msd-ns-*/SKILL.md` (6 routers) + `skills/msd-ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/msd-*.md` | No MSD hooks or statusline |
| Trae | `~/.trae` | `./.trae` | `skills/msd-ns-*/SKILL.md` (6 routers) + `skills/msd-ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/msd-*.md` | Rule references under `rules/`; no MSD hooks |
| Qwen Code | `~/.qwen` | `./.qwen` | `skills/msd-ns-*/SKILL.md` (6 routers) + `skills/msd-ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/msd-*.md` | Common MSD settings and hook entries where supported |
| Hermes Agent | `~/.hermes` | `./.hermes` | `skills/msd/ns-*/SKILL.md` (6 routers, prefix='') + `skills/msd/ns-*/skills/<name>/SKILL.md` (nested concretes) | `agents/msd-*.md` | Common MSD settings and hook entries where supported |
| CodeBuddy | `~/.codebuddy` | `./.codebuddy` | `skills/msd-*/SKILL.md` (flat, `user-invocable: false`) | `agents/msd-*.md` | `/msd-*` slash commands under `commands/`; common MSD settings and hook entries where supported |
| Cline | `~/.cline` | project root | `skills/msd-ns-*/SKILL.md` (6 routers) + `skills/msd-ns-*/skills/<name>/SKILL.md` (nested concretes) + `.clinerules` | Rules only | No MSD hooks or statusline |
### Upstream Contract Sources
@@ -1030,7 +1030,7 @@ on 2026-06-07:
2. **Hook event names** — Claude uses `PostToolUse`, Antigravity uses `AfterTool`
3. **Agent frontmatter** — Each runtime has its own agent definition format
4. **Path conventions** — Each runtime stores config in different directories
5. **Model references** — `inherit` profile lets GSD defer to runtime's model selection
5. **Model references** — `inherit` profile lets MSD defer to runtime's model selection
The installer handles all translation at install time. Workflows and agents are written in Claude Code's native format and transformed during deployment.