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,6 +1,6 @@
# How overlay capabilities compose
> **Explanation** — This document describes *why* GSD composes first-party and
> **Explanation** — This document describes *why* MSD composes first-party and
> third-party capabilities the way it does, and *what the precedence and conflict
> rules are*. It is not a step-by-step guide; for the consumer lifecycle see
> [Install your first capability](../tutorials/install-your-first-capability.md),
@@ -15,9 +15,9 @@
## The central idea: the registry is a module, not a data file
GSD's capabilities — first-party and third-party alike — are described by a single
MSD's capabilities — first-party and third-party alike — are described by a single
**capability registry**: a composed object that every consumer (the loop resolver,
the config loader, the surface command, `gsd capability list`) reads to learn which
the config loader, the surface command, `msd capability list`) reads to learn which
skills, agents, config keys, and loop hooks exist.
The first-party registry is *frozen and generated*: it is built at release time from
@@ -41,7 +41,7 @@ second-class citizen: once it composes cleanly, it participates in the loop exac
as a shipped one does.
The interesting question is everything that can go wrong while composing two sources
that were authored independently — and what GSD does about each case. That is the rest
that were authored independently — and what MSD does about each case. That is the rest
of this document.
---
@@ -58,28 +58,28 @@ before surface and config**, not after them.
The capability now exists *on disk*.
2. **Load / compose (with the project-scope consent gate)** is what `loadRegistry`
does. As it composes each overlay it applies the composition gates — id/skill/agent/
config/family collisions, the `engines.gsd` re-check, and, for a *project-scoped*
config/family collisions, the `engines.msd` re-check, and, for a *project-scoped*
overlay, **the project-scope consent gate**. That gate runs *inside* `loadRegistry`,
before any of the overlay's fragments are even materialised: a project overlay is
inert (discovered-but-inactive) until a matching record exists in your user-owned
consent store. This is the security gate described in
[the trust model](capability-trust-model.md#the-project-scope-trust-boundary). A
capability that fails any composition gate — consent included — never enters the
registry the rest of GSD reads, so it cannot reach the later stages at all.
registry the rest of MSD reads, so it cannot reach the later stages at all.
3. **Surface** decides which of the *composed* registry's skills are projected into the
host runtime. This is the install-profile and `/gsd-surface` layer — a capability's
host runtime. This is the install-profile and `/msd-surface` layer — a capability's
skills can be on the surface or held back without uninstalling it. It only ever sees
capabilities that already cleared composition.
4. **Config activation** decides, per loop hook, whether it fires. A hook's `when`
key (a dotted config key) gates it: a `step` or `gate` whose key is falsy does not
run. This is the `gsd capability set <id> --gate <key>=<bool>` and `/gsd-settings`
run. This is the `msd capability set <id> --gate <key>=<bool>` and `/msd-settings`
layer — again, only for capabilities that survived composition.
This document is about what `loadRegistry` does at the moment of composition — stage 2,
which sits between install and the later surface/config stages and contains the consent
gate. A capability that is installed but skipped at composition (including for missing
consent) never reaches the surface or config stages, because it is not in the registry
the rest of GSD reads.
the rest of MSD reads.
---
@@ -87,20 +87,20 @@ the rest of GSD reads.
`loadRegistry` scans two install roots, in this order:
- **Global** — `$GSD_HOME/.gsd/capabilities/<id>/` (where `GSD_HOME` defaults to your
- **Global** — `$MSD_HOME/.msd/capabilities/<id>/` (where `MSD_HOME` defaults to your
home directory). This is under your own control and is trusted without a per-project
record.
- **Project** — `<projectRoot>/.gsd/capabilities/<id>/`. This lives inside a repository
- **Project** — `<projectRoot>/.msd/capabilities/<id>/`. This lives inside a repository
and is therefore only as trustworthy as the repository; it is gated by the consent
store.
The roots are deduplicated by their *canonical* (symlink-resolved) physical path, so a
single directory is never scanned twice — and, crucially, so a symlinked `GSD_HOME`
single directory is never scanned twice — and, crucially, so a symlinked `MSD_HOME`
that physically *is* the project root cannot smuggle an in-repo bundle into the trusted
global slot. When the global and project roots resolve to the same physical directory
(or distinctness cannot be proven), the surviving scope escalates to the more
restrictive `project` — consent-required. This is a deliberately conservative choice:
when GSD cannot prove a global root is distinct from your project tree, it treats it as
when MSD cannot prove a global root is distinct from your project tree, it treats it as
project-scoped rather than risk granting trusted-global activation to repo-plantable
content.
@@ -129,9 +129,9 @@ overlay is rejected if it collides on any of:
Two further rules protect the first-party namespace directly:
- **Reserved prefixes.** The `gsd-`, `gsd-core-`, and `anthropic-` id prefixes are
- **Reserved prefixes.** The `msd-`, `msd-core-`, and `anthropic-` id prefixes are
reserved. An overlay whose id begins with one is rejected outright — a third party
cannot publish `gsd-security` and borrow the implicit trust of the GSD namespace.
cannot publish `msd-security` and borrow the implicit trust of the MSD namespace.
- **Cross-capability invariants.** Each candidate overlay is added to the merged
capability map and the *full* cross-capability validation suite (contract roles,
`consumes`-satisfiability, owner uniqueness, config-key exclusivity, `requires`
@@ -142,12 +142,12 @@ Two further rules protect the first-party namespace directly:
The asymmetry is intentional and follows directly from the trust model's central
thesis — *artifact parity is not trust parity*. A third-party capability is allowed to
ship the same kinds of artifacts as GSD Core, but first-party capabilities carry an
authority third-party ones do not: their provenance is the GSD release process itself.
ship the same kinds of artifacts as MSD Core, but first-party capabilities carry an
authority third-party ones do not: their provenance is the MSD release process itself.
If a collision could let an overlay shadow a first-party skill, agent, or command, then
installing a capability could silently *replace* a shipped behaviour — the install would
be the attack. By making first-party unconditionally win every collision, GSD
guarantees that no installed capability can ever redefine what GSD Core does. An overlay
be the attack. By making first-party unconditionally win every collision, MSD
guarantees that no installed capability can ever redefine what MSD Core does. An overlay
can only *add*; it can never *override*.
---
@@ -167,8 +167,8 @@ for any of these reasons:
- it fails structural or cross-capability validation;
- it collides with first-party or an already-accepted overlay (the precedence rule
above);
- its `engines.gsd` range does not satisfy the running GSD version (the load-time
re-gate, which mirrors the install-time gate so an upgrade of GSD itself can retire an
- its `engines.msd` range does not satisfy the running MSD version (the load-time
re-gate, which mirrors the install-time gate so an upgrade of MSD itself can retire an
incompatible overlay);
- it carries an in-flight `_pending` install/upgrade marker (deferred until
reconciliation completes);
@@ -204,14 +204,14 @@ to the operator at all.
So, per the maintainer decision on [#2009](https://github.com/open-gsd/gsd-core/issues/2009),
composition treats gates like steps and contributions for control flow — the loop always
proceeds — but never silently. When a capability that declares a gate is skipped, GSD
proceeds — but never silently. When a capability that declares a gate is skipped, MSD
records its gate points in `_overlay.incompatibleGateCapIds` and `_overlay.blockedGates`,
and the loop resolver **injects no gate** at each of those extension points. The loop
**fails open**, but loudly: it emits a warning through two channels — stderr (the channel
host workflows/agents see when they run `gsd_run loop render-hooks <point>`) and the
host workflows/agents see when they run `msd_run loop render-hooks <point>`) and the
`loop render-hooks` JSON envelope's top-level `warnings` array. The warning names the
skipped capability, why it could not be loaded (for example, an incompatible
`engines.gsd` range), and the exact remediation — `gsd capability remove <id>` — so the
`engines.msd` range), and the exact remediation — `msd capability remove <id>` — so the
operator sees the missing control on every pass through the loop until they act on it,
instead of the loop halting project-wide over a single incompatible overlay.
@@ -229,7 +229,7 @@ canonical builder (`buildRegistry`) materialises the merged registry — a topol
cycle that only appears across the combined set, a config-slice shape problem, a format
mismatch. An unguarded failure there would crash every consumer of the registry.
The fallback is uncompromising: if the whole-set build fails, GSD **discards every
The fallback is uncompromising: if the whole-set build fails, MSD **discards every
overlay** and returns the frozen first-party registry, plus a warning recording why. The
loop keeps running with exactly the shipped capabilities and none of the overlays. Two
details make this safe rather than merely convenient:
@@ -241,7 +241,7 @@ details make this safe rather than merely convenient:
still **surfaces a loud warning** (stderr + envelope `warnings`) at its gate points
rather than vanishing silently (#2009).
The principle is the same at every layer: when GSD cannot compose an overlay, it removes
The principle is the same at every layer: when MSD cannot compose an overlay, it removes
the overlay's *additions* but never silences a *control* — a missing gate always
surfaces, even though, per #2009, it no longer blocks the loop.
@@ -251,14 +251,14 @@ surfaces, even though, per #2009, it no longer blocks the loop.
A subtle but important design choice: the merged registry is materialised by the **same**
`buildRegistry` function that produces the first-party registry, run over a map of
first-party capabilities *plus* the accepted overlays. GSD does not have one code path
first-party capabilities *plus* the accepted overlays. MSD does not have one code path
that builds the first-party views and a separate path that bolts overlay views on.
The reason is drift. Every derived view — `bySkill`, `byLoopPoint`, the config schema,
the cluster map, profile membership — is a projection of the capability set. If overlays
were projected by a different builder, those projections could diverge from the
first-party ones in subtle ways, and an overlay capability might behave *almost* like a
first-party one but not quite. By forcing both through the single canonical builder, GSD
first-party one but not quite. By forcing both through the single canonical builder, MSD
guarantees that an accepted overlay is indistinguishable from a first-party capability in
every derived view — which is exactly the artifact-parity promise the platform makes.
@@ -276,7 +276,7 @@ The overlay model rests on a few rules applied consistently:
per [#2009](https://github.com/open-gsd/gsd-core/issues/2009), **fails open** for gates
too (a missing control, no gate injected) — but loudly, via a warning (stderr + the
envelope's `warnings` array) that names the load failure and its
`gsd capability remove <id>` remediation.
`msd capability remove <id>` remediation.
- A whole-set compose failure **falls back to first-party**, clearing command roots and
still surfacing dropped gates as loud warnings.
- One canonical builder materialises both first-party and overlay views, so an accepted
@@ -295,5 +295,5 @@ single incompatible overlay.
- [The capability trust model](capability-trust-model.md) — the security side of the same boundary
- [Capability Overlay (Configuration)](../CONFIGURATION.md#capability-overlay-installed-third-party-capabilities) — the operator-facing view of the same rules
- [Capability manifest reference](../reference/capability-manifest.md) — the field-level conformance invariants
- [`gsd capability` command reference](../reference/gsd-capability-command.md)
- [`msd capability` command reference](../reference/msd-capability-command.md)
- [Install your first capability](../tutorials/install-your-first-capability.md)