Files
msd-core/commands/msd/surface.md
Jakub Zych a9a7a328e6 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.
2026-10-06 01:47:40 +02:00

173 lines
5.9 KiB
Markdown

---
name: msd:surface
description: Toggle which skills are surfaced — apply a profile, list, or disable a cluster without reinstall
argument-hint: "[list|status|profile <name>|disable <cluster>|enable <cluster>|reset]"
allowed-tools:
- Read
- Write
- Bash
requires: [config, update]
---
<objective>
Manage the runtime skill surface without reinstall. Reads/writes `~/.claude/.msd-surface.json`
(sibling to `~/.claude/.msd-profile`) and re-stages the active skills directory in place.
Skill dirs live at `~/.claude/skills/msd-*/`.
Sub-commands: list · status · profile · disable · enable · reset
</objective>
## Sub-command routing
Parse the first token of $ARGUMENTS:
| Token | Action |
|---|---|
| `list` | Show enabled + disabled clusters and skills |
| `status` | Alias for `list` plus token cost summary |
| `profile <name>` | Write `baseProfile` and re-stage |
| `profile <n1>,<n2>` | Composed profiles (comma-separated, no spaces) |
| `disable <cluster>` | Add cluster to `disabledClusters`, re-stage |
| `enable <cluster>` | Remove cluster from `disabledClusters`, re-stage |
| `reset` | Delete `.msd-surface.json`, return to install-time profile |
| *(none)* | Treat as `list` |
---
## list / status
Load the capability registry and call `listSurface(runtimeConfigDir, manifest, CLUSTERS, registry)` from
the engine module at `${runtimeConfigDir}/msd-core/bin/lib/surface.cjs`. The registry is loaded via:
```js
const registry = require(runtimeConfigDir + '/msd-core/bin/lib/capability-registry.cjs');
```
Display:
```
Enabled (N skills, ~T tokens):
core_loop: new-project discuss-phase plan-phase execute-phase help update
audit_review: …
…
Disabled:
utility: health stats settings …
Token cost: ~T (budget cap ~500 tokens for 200k context @ 1%)
```
For `status` also append:
```
Base profile: standard (from .msd-surface.json)
Install profile: standard (from .msd-profile)
```
---
## Mutation protocol
Derive the next `surfaceState` in memory and pass it to `applySurface` as
`opts.surfaceState`. Do not call `writeSurface` first: `applySurface` stages all
artifact kinds before mutation and publishes the candidate state only after
materialization succeeds. Pass `null` to reset to the install-time profile.
---
## profile \<name\>
1. Read current surface: `readSurface(runtimeConfigDir)` → if null, seed from `readActiveProfile(runtimeConfigDir)`.
2. Set `surfaceState.baseProfile = name`.
3. Keep the new state in memory; do not write it directly.
4. Resolve and re-apply:
```js
const registry = require(runtimeConfigDir + '/msd-core/bin/lib/capability-registry.cjs');
const layout = resolveRuntimeArtifactLayout(runtime, runtimeConfigDir, scope);
applySurface(runtimeConfigDir, layout, manifest, CLUSTERS, registry, { surfaceState });
```
5. Confirm: "Surface updated to profile `<name>`. N skills enabled."
---
## disable \<cluster\>
Valid cluster names: `core_loop`, `audit_review`, `milestone`, `research_ideate`,
`workspace_state`, `docs`, `ui`, `ai_eval`, `ns_meta`, `utility`.
1. Validate cluster name against `Object.keys(CLUSTERS)`.
2. Read or initialize surface state.
3. Add cluster to `surfaceState.disabledClusters` (deduplicate).
4. Resolve layout and apply the in-memory candidate:
```js
const registry = require(runtimeConfigDir + '/msd-core/bin/lib/capability-registry.cjs');
const layout = resolveRuntimeArtifactLayout(runtime, runtimeConfigDir, scope);
applySurface(runtimeConfigDir, layout, manifest, CLUSTERS, registry, { surfaceState });
```
5. Confirm: "Disabled cluster `<cluster>`. N skills removed from surface."
---
## enable \<cluster\>
1. Read surface state; if null, nothing to enable — print "No surface delta active."
2. Remove cluster from `surfaceState.disabledClusters`.
3. Resolve layout and apply the in-memory candidate:
```js
const registry = require(runtimeConfigDir + '/msd-core/bin/lib/capability-registry.cjs');
const layout = resolveRuntimeArtifactLayout(runtime, runtimeConfigDir, scope);
applySurface(runtimeConfigDir, layout, manifest, CLUSTERS, registry, { surfaceState });
```
4. Confirm: "Enabled cluster `<cluster>`. N skills added back to surface."
---
## reset
1. Check if `.msd-surface.json` exists.
2. Do not delete it directly.
3. Re-apply with `{ surfaceState: null }`; the state file is removed only after
the install-time profile materializes successfully.
4. Confirm: "Surface reset to install-time profile `<name>`."
---
## runtimeConfigDir resolution
The `runtimeConfigDir` for `applySurface` is the **base Claude config directory**
(`~/.claude`), NOT the skills sub-directory (`~/.claude/skills`).
This matches `installRuntimeArtifacts` and `uninstallRuntimeArtifacts`, which also
receive `~/.claude` as `configDir`. The skill dirs themselves live at
`~/.claude/skills/msd-*/` because the `claude global` layout has `destSubpath =
'skills'` — they are derived from `configDir`, not the root for it.
```bash
# Claude Code — global install
RUNTIME_CONFIG_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
SCOPE="global"
# Artifact destinations are derived from runtime layout
# via resolveRuntimeArtifactLayout(runtime, RUNTIME_CONFIG_DIR, SCOPE)
# then applySurface(RUNTIME_CONFIG_DIR, layout, manifest, CLUSTERS)
```
Surface state is stored at `${RUNTIME_CONFIG_DIR}/.msd-surface.json`
(i.e. `~/.claude/.msd-surface.json`).
All paths can be overridden by reading the `CLAUDE_CONFIG_DIR` env var if set.
---
## Error handling
- Unknown cluster name → list valid cluster names, exit without writing.
- Unknown profile name → list known profiles (`core`, `standard`, `full`), exit.
- Missing `surface.cjs` → prompt: "Run `npm i -g @golem15/msd-core` to reinstall MSD."
<execution_context>
Surface state file: `~/.claude/.msd-surface.json`
Install profile marker: `~/.claude/.msd-profile`
Skill dirs: `~/.claude/skills/msd-*/`
Engine module: `~/.claude/msd-core/bin/lib/surface.cjs`
Cluster definitions: `~/.claude/msd-core/bin/lib/clusters.cjs`
</execution_context>