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.
7.5 KiB
Skill Surface Budget Module owns install-time profile staging and runtime surface control
- Status: Accepted
- Date: 2026-05-12
- Decision date: 2026-05-12
- Supersedes: ADR-0010 (Skill Surface Budget Module — earlier draft, install-time skill listing curation)
- Subsumed by: ADR-857 (Capability system) — generalizes this module; this seam remains live at
src/surface.cts:348(applySurface) - Implementation: feat/3408-skills-description-dropped-due-to-size, PR
Every installed msd-* skill costs eager system-prompt tokens: runtimes (Claude Code, opencode, and others) enumerate all skill descriptions in <available_skills> on every turn. With 66 skills and 33 agents, MSD alone consumes roughly 60% of the default 1%-of-context skill-listing budget, causing descriptions to drop when users stack multiple plugins (#3408).
The root problem is an absence of a profile/surface seam: the installer wrote every skill unconditionally, and no runtime-side control existed for enabling or disabling a cohesive group of skills without a full reinstall.
Decision
- Add a Skill Surface Budget Module under
msd-core/bin/lib/install-profiles.cjsas the single owner for which skills and agents are written to runtime config directories. - Define three named profiles:
core(six skills covering the main loop),standard(core + phase management and workspace skills), andfull(all skills — the previous default). - Compute each profile's effective skill set as the transitive closure over the
requires:dependency graph extracted from skill frontmatter, so partial installs never break cross-skill dependencies. - Persist the chosen profile in a
.msd-profilemarker file in each runtime config directory;msd updatereads the marker to honor the profile on re-install. - When multiple runtimes are configured, resolve disagreement to the most-restrictive profile (smallest effective skill set).
- Allow profile composition:
--profile=core,auditresolves tounion(closure(core), closure(audit)). - Preserve back-compat aliases:
--minimaland--core-onlymap to--profile=core;MINIMAL_SKILL_ALLOWLIST,isMinimalMode,shouldInstallSkill, andstageSkillsForModeremain exported for existing callers. - Add a CI gate (
scripts/lint-skill-deps.cjs, wired intopretest) that verifies every skill'srequires:entries resolve against real skill stems — prevents the profile closure from silently over-installing or breaking.
Phase 2 — Runtime Surface Module
The Phase 2 decision, previously listed as an open question, is recorded here as an amendment to this ADR.
Decision
- Add a
/msd:surfaceslash command with the following sub-commands:list— show all clusters and their enabled/disabled status for the active runtimestatus— show the active profile, effective skill count, and any dropped-description warningsprofile <name>— switch the active profile and re-stage skills/agents for the current runtimedisable <cluster>— mark a cluster disabled; re-stage to remove its skills from the runtime config direnable <cluster>— mark a cluster enabled; re-stage to add its skills backreset— clear surface state and re-apply the active profile from.msd-profile
- Implement the runtime surface engine in
msd-core/bin/lib/surface.cjs, consumingstageSkillsForProfileandstageAgentsForProfilefrom the Phase 1 module without duplicating staging logic. - Persist per-runtime surface state in
<runtimeConfigDir>/.msd-surface.json, independent from.msd-profile. The profile marker owns install-time identity; the surface JSON owns session-scope cluster toggles. - Source cluster taxonomy from the research memo §3.2 (2026-05-12-skill-surface-budget.md). Define clusters in
msd-core/bin/lib/clusters.cjs— a separate module so the surface engine and future SDK callers can import cluster definitions without loading the full profile module. - Cluster taxonomy:
core_loop,audit_review,milestone,research_ideate,workspace_state,docs,ui,ai_eval,ns_meta,utility. Membership may overlap; every installed skill stem must appear in at least one cluster (enforced bytests/surface-clusters.test.cjs). - Relationship to Anthropic platform asks: Asks D (native per-skill toggle API) and E (budget-fraction negotiation) remain filed separately. The
/msd:surfacecommand is a unilateral MSD-side workaround that does not depend on those platform changes.
Status — Phase 1 shipped
Phase 1 artifacts landed on feat/3408-skills-description-dropped-due-to-size:
msd-core/bin/lib/install-profiles.cjs—PROFILESmap,resolveProfile,loadSkillsManifest,stageSkillsForProfile,stageAgentsForProfile,readActiveProfile,writeActiveProfile,mostRestrictiveProfile,resolveEffectiveProfilerequires:frontmatter added to 64 skills incommands/msd/*.mdscripts/lint-skill-deps.cjs— CI gate forrequires:integrity, wired intopretestbin/install.js—--profile=<name>flag (composable);--minimal/--core-onlyas aliases;.msd-profilemarker write on install;msd updatere-reads marker- Tests:
tests/install-profiles-manifest.test.cjs,tests/install-profiles-marker.test.cjs,tests/install-profiles-resolve.test.cjs,tests/install-profiles-stage.test.cjs,tests/lint-skill-deps.test.cjs
Phase 2 shipped on the same branch:
commands/msd/surface.md—/msd:surfaceslash command runbook (sub-commands:list,status,profile <name>,disable <cluster>,enable <cluster>,reset)msd-core/bin/lib/surface.cjs— runtime engine (readSurface,writeSurface,resolveSurface,applySurface,listSurface); reusesstageSkillsForProfile/stageAgentsForProfilefrom Phase 1msd-core/bin/lib/clusters.cjs— 10-cluster taxonomy covering all installed skill stems- Tests:
tests/surface-state.test.cjs,tests/surface-clusters.test.cjs,tests/surface-resolve.test.cjs,tests/surface-apply.test.cjs,tests/surface-list.test.cjs - Persistent surface state:
<runtimeConfigDir>/.msd-surface.json(independent from.msd-profile)
Open questions
- Whether the
requires:field should also be consumed by/msd:helpto annotate dependency chains in help output (follow-up). - Whether telemetry (per-profile install counts, cluster-disable events) should be added to the surface engine or deferred.
- Whether Anthropic platform asks D and E (native skill toggle API, budget-fraction negotiation) should block any future work in this module.
Consequences
- Users with constrained context budgets can install
--profile=coreand expand incrementally via/msd:surface enable <cluster>without a full reinstall. - The
requires:closure ensures partial installs never silently break skill cross-references. - Future skills must declare
requires:dependencies to participate in profile resolution; the lint gate enforces this at CI time. CONTEXT.mdgains a canonical Skill Surface Budget Module entry; future architecture reviews should treat out-of-seam skill staging as drift.- Cluster definitions in
clusters.cjsare the authoritative taxonomy for runtime surface control; additions must be reflected there and in tests.
References
- Feature issue:
#3408 - Research memo:
docs/research/2026-05-12-skill-surface-budget.md(§3.2 cluster taxonomy) - See
0008-installer-migration-module.md - See
0009-shell-command-projection-module.md - See
0010-file-operation-engine-module.md