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:
@@ -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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The capability trust model
|
||||
|
||||
> **Explanation** — This document describes *why* GSD draws its trust
|
||||
> **Explanation** — This document describes *why* MSD draws its trust
|
||||
> boundaries where it does, and *what the trade-offs are*. It is not a
|
||||
> step-by-step guide to installing capabilities; for that, see the how-to
|
||||
> guides for [importing a capability](../how-to/import-a-capability-from-a-url.md) and
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
## The central thesis: artifact parity is not trust parity
|
||||
|
||||
GSD 1.6.0 opens the capability platform to third-party authors with **full
|
||||
MSD 1.6.0 opens the capability platform to third-party authors with **full
|
||||
artifact parity**: a third-party capability may ship the same executable
|
||||
surfaces that GSD Core ships — hooks, MCP servers, command modules, and
|
||||
surfaces that MSD Core ships — hooks, MCP servers, command modules, and
|
||||
reviewer lanes. This is a deliberate product choice, and it carries real
|
||||
security weight.
|
||||
|
||||
@@ -31,9 +31,9 @@ line between two things that are often conflated:
|
||||
- **Trust posture** — the evidence and consent required before that capability
|
||||
*executes* on your machine.
|
||||
|
||||
GSD grants full artifact parity. It does not grant symmetric trust. First-party
|
||||
MSD grants full artifact parity. It does not grant symmetric trust. First-party
|
||||
capabilities are implicitly trusted because they *are* the shipped package —
|
||||
their provenance is the GSD Core release process itself. Third-party
|
||||
their provenance is the MSD Core release process itself. Third-party
|
||||
capabilities require explicit, informed, revocable consent plus SHA-pinned
|
||||
integrity before any executable surface is activated. These two things are
|
||||
structurally separate, and keeping them separate is what makes full parity
|
||||
@@ -43,7 +43,7 @@ defensible.
|
||||
|
||||
## What the ecosystem learnt the hard way
|
||||
|
||||
GSD's trust model is not designed in isolation. It is informed by failures in
|
||||
MSD's trust model is not designed in isolation. It is informed by failures in
|
||||
four ecosystems that tackled the same problem — and each one paid tuition.
|
||||
|
||||
### VS Code: auto-update + stolen publisher credentials
|
||||
@@ -57,13 +57,13 @@ a liability when credentials can be compromised, because the user's last
|
||||
explicit act of trust was for *version N* — not for whatever version N+1
|
||||
contains.
|
||||
|
||||
GSD's response: auto-update is **off by default** for third-party capabilities.
|
||||
MSD's response: auto-update is **off by default** for third-party capabilities.
|
||||
When it is enabled, a change to the *executable set* (the set of hooks, MCP
|
||||
servers, command modules, or reviewer lanes the capability declares) triggers a
|
||||
re-consent prompt before the update applies. Updating a non-executable
|
||||
capability (documentation, agents, skills) does not require re-consent.
|
||||
|
||||
VS Code also has no signature check on VSIX packages. GSD requires an
|
||||
VS Code also has no signature check on VSIX packages. MSD requires an
|
||||
`integrity` SHA-512 pin in the ledger, verified before extraction.
|
||||
|
||||
### npm: the supply-chain attack surface
|
||||
@@ -74,7 +74,7 @@ attackers have exploited in the s1ngularity attack class (a malicious package
|
||||
is published under a name a legitimate package depends on). npm's own
|
||||
recommendation for sensitive environments is `--ignore-scripts`.
|
||||
|
||||
GSD takes a stronger position: **install never executes capability code**,
|
||||
MSD takes a stronger position: **install never executes capability code**,
|
||||
full stop. Installation is a copy-only staging operation. There is no
|
||||
`postinstall`-equivalent. A capability's hooks, MCP server, command
|
||||
modules, and reviewer lanes are not invoked during install; they are first
|
||||
@@ -85,13 +85,13 @@ has a window between install and first use to verify what they consented to.
|
||||
### The reviewer lane: the one surface that *receives* data
|
||||
|
||||
Three of the four disclosure classes are about code the capability gets to
|
||||
**run**. A reviewer lane — one external CLI or model endpoint that `/gsd-review`
|
||||
**run**. A reviewer lane — one external CLI or model endpoint that `/msd-review`
|
||||
hands a plan to — is different in kind, and the difference is the reason it is
|
||||
disclosed at all.
|
||||
|
||||
A lane is piped the plan text, the requirements, the research findings, and the
|
||||
`CONTEXT.md` decisions, and its output is read back into `REVIEWS.md`. That is an
|
||||
**egress channel for the most sensitive artifacts GSD produces**. Making lanes
|
||||
**egress channel for the most sensitive artifacts MSD produces**. Making lanes
|
||||
pluggable without a disclosure class would have opened a data-exfiltration path
|
||||
behind a manifest field, which is why the trust work gates the feature rather
|
||||
than following it.
|
||||
@@ -130,10 +130,10 @@ destination is detectable rather than silent.
|
||||
|
||||
SLSA provenance (the `provenance` field in `capability.json`) provides a
|
||||
machine-checkable link from a capability bundle back to a specific commit in a
|
||||
specific source repository. GSD emits provenance for first-party capabilities
|
||||
specific source repository. MSD emits provenance for first-party capabilities
|
||||
in CI and recommends it for curated capabilities; whether to require it for
|
||||
community-listed third-party capabilities is an open question tied to whether
|
||||
GSD operates a central registry (see the PRD).
|
||||
MSD operates a central registry (see the PRD).
|
||||
|
||||
### Obsidian: no sandbox, stated honestly
|
||||
|
||||
@@ -144,17 +144,17 @@ on by default — no community plugins run until the user deliberately disables
|
||||
restricted mode — plus a human-curated plugin directory that requires a
|
||||
maintainer review PR for each new plugin.
|
||||
|
||||
GSD borrows two things from Obsidian. First, the honesty: **there is no
|
||||
MSD borrows two things from Obsidian. First, the honesty: **there is no
|
||||
sandbox**, and this document says so directly rather than implying one. Second,
|
||||
the principle that explicit opt-in per capability is better than a blanket "all
|
||||
community plugins are safe" message. GSD does not use restricted mode, but its
|
||||
community plugins are safe" message. MSD does not use restricted mode, but its
|
||||
consent gate at install serves the same function: executable surfaces are
|
||||
disclosed and consented to before they activate, not discovered after the fact.
|
||||
|
||||
GSD does not borrow Obsidian's centralised review model. Requiring a
|
||||
MSD does not borrow Obsidian's centralised review model. Requiring a
|
||||
maintainer-review PR for every third-party capability is the bottleneck that
|
||||
makes the Obsidian system painful for authors and creates a PR-queue burden
|
||||
for maintainers. GSD ships decentralised URL import precisely to avoid that.
|
||||
for maintainers. MSD ships decentralised URL import precisely to avoid that.
|
||||
|
||||
### Claude Code: trust prompt + marketplace
|
||||
|
||||
@@ -163,9 +163,9 @@ elevated trust, lists the permissions the extension requests, and maintains a
|
||||
`strictKnownMarketplaces` allowlist for managed environments where only
|
||||
reviewed sources are permitted. Claude Code's SHA-pinning mechanic (pinning to
|
||||
a specific version hash rather than floating on `latest`) is the direct model
|
||||
for GSD's integrity field.
|
||||
for MSD's integrity field.
|
||||
|
||||
GSD mirrors the allowlist mechanic as `strictKnownRegistries`, and mirrors the
|
||||
MSD mirrors the allowlist mechanic as `strictKnownRegistries`, and mirrors the
|
||||
SHA-pin as the `integrity` field in `capability.json` and the capability
|
||||
ledger.
|
||||
|
||||
@@ -175,7 +175,7 @@ ledger.
|
||||
|
||||
### Install never runs code
|
||||
|
||||
The most powerful thing GSD can say to a user about a third-party capability
|
||||
The most powerful thing MSD can say to a user about a third-party capability
|
||||
is: "downloading and staging this capability will not execute any of its code."
|
||||
That guarantee makes the consent step meaningful. If install could run code, a
|
||||
malicious capability could bypass consent entirely — the install step would be
|
||||
@@ -194,7 +194,7 @@ the point at which a hook would fire for the first time is not a prompt
|
||||
opportunity; it is already inside a running tool invocation. This means the
|
||||
consent window is install, not first use.
|
||||
|
||||
GSD presents a pre-install summary that names every executable surface the
|
||||
MSD presents a pre-install summary that names every executable surface the
|
||||
capability declares (hooks, MCP servers, command modules), their kinds (`step`,
|
||||
`contribution`, `gate`), and the loop extension points they register into. For
|
||||
each MCP server the summary also shows the `env` it would be spawned with (each
|
||||
@@ -285,7 +285,7 @@ Two things worth stating so you do not infer them:
|
||||
### Integrity pinning
|
||||
|
||||
An `integrity` field in `capability.json` carries a `sha512-<base64>` digest
|
||||
of the capability bundle. When present, GSD verifies this digest before
|
||||
of the capability bundle. When present, MSD verifies this digest before
|
||||
extracting any files. A mismatch aborts the install.
|
||||
|
||||
When NO pin is supplied, the consent prompt says so plainly: a
|
||||
@@ -360,11 +360,11 @@ code it does not own — whether by accident or by design.
|
||||
|
||||
### Reserved namespace
|
||||
|
||||
The `gsd-`, `gsd-core-`, and `anthropic-` id prefixes are reserved for
|
||||
The `msd-`, `msd-core-`, and `anthropic-` id prefixes are reserved for
|
||||
first-party use. A third-party capability that claims one of these prefixes is
|
||||
rejected at the conformance gate. This prevents impersonation: a malicious
|
||||
actor cannot publish a capability called `gsd-security` and exploit a user's
|
||||
implicit trust in the GSD namespace.
|
||||
actor cannot publish a capability called `msd-security` and exploit a user's
|
||||
implicit trust in the MSD namespace.
|
||||
|
||||
### `capabilities.strict_known_registries` for managed environments
|
||||
|
||||
@@ -389,7 +389,7 @@ with the consent prompt as the default barrier and lockdown one config key away.
|
||||
### Command dispatch: where third-party code runs (1.6.0)
|
||||
|
||||
A capability may declare a **command family** (`commands: [{ family, module,
|
||||
router }]`); `gsd-tools <family>` dispatches it by `require()`-ing the router.
|
||||
router }]`); `msd-tools <family>` dispatches it by `require()`-ing the router.
|
||||
This is the one place a third-party capability's own code executes, so it is
|
||||
gated twice. **Consent:** a third-party family is dispatchable only if the
|
||||
capability is *active* under the activation gate below — for a project-scoped
|
||||
@@ -403,20 +403,20 @@ command can never be shadowed by a third-party one.
|
||||
|
||||
#### The project-scope trust boundary
|
||||
|
||||
Capabilities install **globally** (`$GSD_HOME/.gsd/capabilities/`) or
|
||||
**project-scoped** (`<projectRoot>/.gsd/capabilities/`). The authoritative
|
||||
Capabilities install **globally** (`$MSD_HOME/.msd/capabilities/`) or
|
||||
**project-scoped** (`<projectRoot>/.msd/capabilities/`). The authoritative
|
||||
consent signal is **not** the in-repo ledger but a **user-owned consent store**
|
||||
that lives **outside any repository**, at
|
||||
`${GSD_HOME||homedir()}/.gsd/consent.json`. Each project-scope consent record is
|
||||
`${MSD_HOME||homedir()}/.msd/consent.json`. Each project-scope consent record is
|
||||
keyed by `(realpath(projectRoot), capability id)` and binds the bundle's
|
||||
`integrity` and its disclosure signature; GSD writes one only when *you* install
|
||||
`integrity` and its disclosure signature; MSD writes one only when *you* install
|
||||
or upgrade that project-scoped capability through the lifecycle on this machine,
|
||||
and removes it when you uninstall.
|
||||
|
||||
Before activating a project-scoped overlay — for **both** its declarative loop
|
||||
surfaces (steps, gates, contributions, federated config) **and** its command
|
||||
dispatch — the loader requires a matching record in this store. With no match the
|
||||
capability is *discovered but inactive*: it shows up in `gsd capability list`
|
||||
capability is *discovered but inactive*: it shows up in `msd capability list`
|
||||
with `status: inactive` and a reason, but contributes nothing and runs nothing.
|
||||
|
||||
This closes the previous bypass: a repo you check out could ship a capability
|
||||
@@ -426,14 +426,14 @@ you consent on this machine — and because the consent binds the integrity and
|
||||
the disclosure signature, tampering with the bundle (including changing an MCP
|
||||
server's `env` or `cwd`) deactivates it until you re-consent. A **global**
|
||||
install (under your own home) is trusted without a per-project record, as before.
|
||||
You can audit and revoke project consents with `gsd capability trust list` and
|
||||
`gsd capability trust revoke <id>`.
|
||||
You can audit and revoke project consents with `msd capability trust list` and
|
||||
`msd capability trust revoke <id>`.
|
||||
|
||||
---
|
||||
|
||||
## The honest limitation: there is no sandbox
|
||||
|
||||
GSD does not sandbox third-party capability code. The honest reason: Node-level
|
||||
MSD does not sandbox third-party capability code. The honest reason: Node-level
|
||||
sandboxing that meaningfully restricts a `require()`'d module — limiting
|
||||
filesystem access, network access, subprocess spawning — would require either
|
||||
a separate process with IPC overhead or a VM context that strips the Node
|
||||
@@ -442,7 +442,7 @@ network for MCP, subprocess for hook shell commands). Full artifact parity and
|
||||
meaningful sandboxing are in tension. The maintainer chose full parity.
|
||||
|
||||
What this means in practice: a third-party capability, once consented to and
|
||||
installed, runs with the same permissions GSD Core itself runs with. It is not
|
||||
installed, runs with the same permissions MSD Core itself runs with. It is not
|
||||
isolated. A capability that wants to exfiltrate data, or modify files outside
|
||||
its declared scope, can — exactly as a malicious npm package can.
|
||||
|
||||
@@ -452,7 +452,7 @@ The barrier is not a technical wall. It is:
|
||||
capability declares before they ran.
|
||||
2. **Integrity** — the bundle you consented to is the bundle that ran (SHA
|
||||
verified).
|
||||
3. **Reversibility** — `gsd capability remove <id>` removes exactly what the
|
||||
3. **Reversibility** — `msd capability remove <id>` removes exactly what the
|
||||
ledger recorded, including entries in shared config files, leaving no
|
||||
orphaned state.
|
||||
|
||||
@@ -475,24 +475,24 @@ instructions from the agent's context. What there is no sandbox for is not only
|
||||
|
||||
The safer alternative considered in ADR-1244 was declarative-only third-party
|
||||
capabilities: skills, agents, and workflow files, but no hooks, MCP servers, or
|
||||
command modules. A third-party author could extend *what GSD describes* but not
|
||||
command modules. A third-party author could extend *what MSD describes* but not
|
||||
*what it executes*.
|
||||
|
||||
The maintainer rejected this. A deploy gate capability, a house-style
|
||||
verification step, a domain-specific planning contribution — all of these
|
||||
require hook registration to have any effect on the loop. Declarative-only
|
||||
third-party capabilities would be second-class citizens, unable to participate
|
||||
in the parts of GSD where participation matters most. Full parity was the
|
||||
in the parts of MSD where participation matters most. Full parity was the
|
||||
explicit scope.
|
||||
|
||||
The cost of that choice is a permanently elevated security responsibility: URL
|
||||
import with executable surfaces is the highest-maintenance, highest-risk part
|
||||
of GSD. The trust model is a forever commitment, not a one-time effort.
|
||||
of MSD. The trust model is a forever commitment, not a one-time effort.
|
||||
|
||||
### Centralised-registry-only distribution
|
||||
|
||||
The alternative to decentralised URL/git import is requiring all third-party
|
||||
capabilities to go through a GSD-operated curated registry — one PR per
|
||||
capabilities to go through a MSD-operated curated registry — one PR per
|
||||
capability, reviewed by the maintainer before listing.
|
||||
|
||||
This would meaningfully reduce supply-chain risk (a human reviews every listed
|
||||
@@ -503,7 +503,7 @@ capabilities, and replicates exactly the bottleneck that makes Obsidian's
|
||||
plugin system painful.
|
||||
|
||||
The compromise: URL/git/npm/tarball import ships in 1.6.0 without a curated
|
||||
registry. Whether GSD later operates or advertises a community registry is an
|
||||
registry. Whether MSD later operates or advertises a community registry is an
|
||||
open question (PRD-1244 §8). If it does, the intent is to separate "official"
|
||||
(curated) from "community" (consented-but-not-reviewed) tiers, mirroring the
|
||||
split Claude Code uses for its marketplace.
|
||||
@@ -514,10 +514,10 @@ split Claude Code uses for its marketplace.
|
||||
|
||||
The capability trust model rests on a single conceptual move: separating
|
||||
artifact parity from trust posture. Because those two things are kept separate,
|
||||
GSD can offer authors the full power of the platform while making users'
|
||||
MSD can offer authors the full power of the platform while making users'
|
||||
security obligations clear and auditable. You consent to executable surfaces
|
||||
before they run, you can verify the bundle's integrity, and you can remove a
|
||||
capability completely. GSD does not pretend this is the same as not running
|
||||
capability completely. MSD does not pretend this is the same as not running
|
||||
the code at all.
|
||||
|
||||
---
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
|
||||
## The problem
|
||||
|
||||
GSD's `execute-phase` is wave-based: plans carry a wave number, waves run
|
||||
MSD's `execute-phase` is wave-based: plans carry a wave number, waves run
|
||||
sequentially, and plans *within* a wave run in parallel when their
|
||||
`files_modified` sets don't overlap. On most runtimes GSD realizes that by
|
||||
fanning out one backgrounded `gsd-executor` agent (in a worktree) per plan.
|
||||
`files_modified` sets don't overlap. On most runtimes MSD realizes that by
|
||||
fanning out one backgrounded `msd-executor` agent (in a worktree) per plan.
|
||||
|
||||
On **Claude Code** that fan-out degrades. Backgrounded agents on Claude Code have
|
||||
no `Agent`/`Task` tool, so they cannot nest subagents ([#853]). The autonomous
|
||||
loop therefore falls back to **inline sequential execution** — and with it
|
||||
silently drops wave parallelism, the plan-checker, and the verifier — on the one
|
||||
runtime most GSD users run.
|
||||
runtime most MSD users run.
|
||||
|
||||
Claude Code ships an orchestration primitive that sidesteps exactly this: the
|
||||
**Workflow tool** (the engine behind `/effort ultracode`, Agent SDK ≥ v0.3.149).
|
||||
@@ -30,7 +30,7 @@ invoking the tool.
|
||||
|
||||
`claude-orchestration` is a **default-off, BETA, claude-only** capability that
|
||||
adopts the Workflow tool as an optional, runtime-gated parallel-execution
|
||||
backend, and folds the existing `gsd-ultraplan-phase` plan-offload under the same
|
||||
backend, and folds the existing `msd-ultraplan-phase` plan-offload under the same
|
||||
gate. It is blocked-on-nothing now that the ADR-857 capability system is released.
|
||||
|
||||
- **`role: feature`**, `runtimeCompat.supported: ["claude"]`, `tier: full`.
|
||||
@@ -70,17 +70,17 @@ Workflow backend activates only when *every* gate passes; any miss degrades to
|
||||
|
||||
`emitWorkflowScript` maps the phase's wave/plan model onto Workflow primitives:
|
||||
|
||||
| GSD concept | Workflow primitive |
|
||||
| MSD concept | Workflow primitive |
|
||||
|---|---|
|
||||
| Wave | `parallel()` stage barrier |
|
||||
| Plan (`use_worktree` not `false`) | `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })` |
|
||||
| Plan (`use_worktree: false`) | `agent(brief, { agentType: 'gsd-executor' })` (no isolation) |
|
||||
| Plan (`use_worktree` not `false`) | `agent(brief, { agentType: 'msd-executor', isolation: 'worktree' })` |
|
||||
| Plan (`use_worktree: false`) | `agent(brief, { agentType: 'msd-executor' })` (no isolation) |
|
||||
| `files_modified` overlap | forces the plans into separate sequential stages |
|
||||
| Wave | a `phase("Wave <id>")` group, matching a `meta.phases` entry |
|
||||
| Phase run id | `summary.resumeRunId` → pass as the Workflow tool's `resumeFromRunId` **input** |
|
||||
| Phase token cap | recorded in `summary.budgetTokens`; `budget` is read-only in a script |
|
||||
|
||||
Because the emitted script composes the **same** `gsd-executor` agent the
|
||||
Because the emitted script composes the **same** `msd-executor` agent the
|
||||
inline path uses, with worktree isolation applied **per plan** from the
|
||||
manifest's `use_worktree` field, it produces the same `SUMMARY.md` artifacts
|
||||
and commits — the only difference is the execution vehicle. `use_worktree`
|
||||
@@ -102,7 +102,7 @@ The first slice ships **detection + emission + declarative ultraplan ownership**
|
||||
The emitter is exercised at the contract level (structure, overlap splitting,
|
||||
resume, budget, anti-injection). End-to-end execution through the Workflow tool
|
||||
is verifiable only inside Claude Code with the tool present. Full install-profile
|
||||
migration of the `gsd-ultraplan-phase` skill into the capability's `skills[]`
|
||||
migration of the `msd-ultraplan-phase` skill into the capability's `skills[]`
|
||||
array is a follow-up (it touches the cluster/profile machinery); for v1 the
|
||||
manifest *declares* ultraplan ownership at `plan:post` and the existing skill's
|
||||
own runtime gate continues to no-op on non-Claude runtimes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Context engineering
|
||||
|
||||
> Why GSD Core exists, and the problem it is designed to solve.
|
||||
> Why MSD Core exists, and the problem it is designed to solve.
|
||||
|
||||
---
|
||||
|
||||
@@ -23,15 +23,15 @@ The naive response is to `/clear` and start over. But that loses continuity. You
|
||||
|
||||
---
|
||||
|
||||
## GSD Core's answer: fresh-context subagents
|
||||
## MSD Core's answer: fresh-context subagents
|
||||
|
||||
GSD Core's central insight is that *most* of the work in a coding session does not need to happen in the main context at all. Research, planning, code writing, and verification are each discrete, bounded tasks. Each can be handed to a specialised subagent that starts with a clean, carefully scoped context window — and reports its result back to a thin orchestrator that stays lean.
|
||||
MSD Core's central insight is that *most* of the work in a coding session does not need to happen in the main context at all. Research, planning, code writing, and verification are each discrete, bounded tasks. Each can be handed to a specialised subagent that starts with a clean, carefully scoped context window — and reports its result back to a thin orchestrator that stays lean.
|
||||
|
||||
This is not a workaround for context rot. It is a structural solution.
|
||||
|
||||
The orchestrator — your main session — never touches source files. It spawns agents, collects their results, updates shared state, and routes to the next step. Because it does very little itself, its context window grows slowly and predictably. The heavy work happens in agents that each start fresh, receive exactly the context they need for their task, and terminate when done.
|
||||
|
||||
Consider what this means in practice. When you run `/gsd-plan-phase`, the orchestrator:
|
||||
Consider what this means in practice. When you run `/msd-plan-phase`, the orchestrator:
|
||||
|
||||
1. Loads a compact JSON context payload (project summary, phase goal, relevant config).
|
||||
2. Spawns a researcher agent with a 200k-token clean window.
|
||||
@@ -44,11 +44,11 @@ Each agent operates at full capacity, unencumbered by the accumulated history of
|
||||
|
||||
## Spec-driven development and meta-prompting
|
||||
|
||||
Context engineering alone is not enough. If an agent starts fresh but receives vague instructions, it will produce vague output. GSD Core pairs fresh-context subagents with two complementary disciplines:
|
||||
Context engineering alone is not enough. If an agent starts fresh but receives vague instructions, it will produce vague output. MSD Core pairs fresh-context subagents with two complementary disciplines:
|
||||
|
||||
**Spec-driven development** means that every phase produces structured artefacts before execution begins. A `CONTEXT.md` captures implementation decisions from the Discuss step. A `RESEARCH.md` records what the researcher found. A `PLAN.md` breaks work into discrete, dependency-ordered tasks with explicit acceptance criteria. By the time an executor agent touches a file, it has a precise specification to work from — not a re-interpretation of a long conversation.
|
||||
|
||||
**Meta-prompting** means the agent definitions themselves are carefully engineered prompts, not ad-hoc instructions. The files in `gsd-core/workflows/` and `agents/` encode hard-won knowledge about how to scope tasks, what to verify, and when to escalate to a human checkpoint. The user does not need to re-explain this knowledge in every session; it is baked into the system's own prompts.
|
||||
**Meta-prompting** means the agent definitions themselves are carefully engineered prompts, not ad-hoc instructions. The files in `msd-core/workflows/` and `agents/` encode hard-won knowledge about how to scope tasks, what to verify, and when to escalate to a human checkpoint. The user does not need to re-explain this knowledge in every session; it is baked into the system's own prompts.
|
||||
|
||||
The combination is deliberate. Fresh context ensures each agent reasons clearly. Spec-driven artefacts ensure each agent reasons about the *right* thing. Meta-prompting ensures each agent knows *how* to reason about it well.
|
||||
|
||||
@@ -56,7 +56,7 @@ The combination is deliberate. Fresh context ensures each agent reasons clearly.
|
||||
|
||||
## The role of `.planning/`
|
||||
|
||||
Context engineering requires that knowledge survive context resets. GSD Core uses the file system for this. Every meaningful output is written to `.planning/` as human-readable Markdown or JSON. This means:
|
||||
Context engineering requires that knowledge survive context resets. MSD Core uses the file system for this. Every meaningful output is written to `.planning/` as human-readable Markdown or JSON. This means:
|
||||
|
||||
- Restarting your session (or the model crashing) does not lose work.
|
||||
- Any subsequent agent can read prior artefacts directly, without depending on a shared conversation history.
|
||||
@@ -70,16 +70,16 @@ Context engineering requires that knowledge survive context resets. GSD Core use
|
||||
|
||||
The fresh-context subagent model protects each spawned agent from accumulating noise. But there is a subtler problem: the *orchestrating session itself* fills up over time. A long-running orchestration silently consumes its own context window — loading payloads, reading status output, routing between phases. Without any signal about how much headroom remains, the session can quietly degrade or, worse, trigger an automatic compaction that silently discards planning state the orchestrator was relying on.
|
||||
|
||||
Since GSD 1.4.0, this is addressed by registering runtime lifecycle hooks. Rather than leaving headroom invisible, these hooks give GSD a per-turn signal — a moment to inspect how much context has been consumed and emit a warning before the window is exhausted. The hooks run inside the runtime itself, so the measurement is as close to authoritative as possible: GSD is not guessing from the outside.
|
||||
Since MSD 1.4.0, this is addressed by registering runtime lifecycle hooks. Rather than leaving headroom invisible, these hooks give MSD a per-turn signal — a moment to inspect how much context has been consumed and emit a warning before the window is exhausted. The hooks run inside the runtime itself, so the measurement is as close to authoritative as possible: MSD is not guessing from the outside.
|
||||
|
||||
### One idea, many runtime vocabularies
|
||||
|
||||
Each AI runtime exposes lifecycle events in its own vocabulary, but the purpose is the same across all of them: fire at boundaries that correspond to context pressure or turn transitions, so GSD can observe and react.
|
||||
Each AI runtime exposes lifecycle events in its own vocabulary, but the purpose is the same across all of them: fire at boundaries that correspond to context pressure or turn transitions, so MSD can observe and react.
|
||||
|
||||
- **Claude Code** fires `PreCompact` when a compaction is about to occur, `Stop` when a session turn ends, and `SubagentStop` when a spawned subagent completes. Together these bracket the moments when context has grown or a context-consuming task has just finished.
|
||||
- **Qwen** exposes `SubagentStop`, `Stop`, and `PreCompact`, mirroring Claude Code's shape in its own event system.
|
||||
|
||||
Think of these as the same concept — "notify GSD at context boundaries" — expressed in each runtime's native event vocabulary. This is the multi-runtime philosophy applied at the observability layer: GSD registers the semantically equivalent hook wherever each runtime exposes it, rather than demanding every runtime adopt a single event schema.
|
||||
Think of these as the same concept — "notify MSD at context boundaries" — expressed in each runtime's native event vocabulary. This is the multi-runtime philosophy applied at the observability layer: MSD registers the semantically equivalent hook wherever each runtime exposes it, rather than demanding every runtime adopt a single event schema.
|
||||
|
||||
For the per-runtime event matrix, see [FEATURES.md](../FEATURES.md) under Multi-Runtime Support. For how to enable hooks on your specific runtime, see [Install on your runtime](../how-to/install-on-your-runtime.md).
|
||||
|
||||
@@ -87,13 +87,13 @@ For the per-runtime event matrix, see [FEATURES.md](../FEATURES.md) under Multi-
|
||||
|
||||
Claude Code exposes a `FileChanged` event in addition to session-lifecycle hooks. Claude Code's `FileChanged` hook watches for changes to `config.json` and hot-reloads the project's `.planning/config.json` into the session. The practical reason is straightforward: configuration changes should take effect without forcing the user to clear and rebuild the session.
|
||||
|
||||
Requiring a `/clear` to pick up a config edit would destroy the very continuity the context-engineering design is trying to protect. By watching for `FileChanged` on `config.json`, GSD can reload configuration mid-session — adjusting model profiles, context-window thresholds, or routing preferences — without the user losing their place. The working context survives; the configuration updates beneath it.
|
||||
Requiring a `/clear` to pick up a config edit would destroy the very continuity the context-engineering design is trying to protect. By watching for `FileChanged` on `config.json`, MSD can reload configuration mid-session — adjusting model profiles, context-window thresholds, or routing preferences — without the user losing their place. The working context survives; the configuration updates beneath it.
|
||||
|
||||
### Effort signals for heavy and light skills
|
||||
|
||||
Beyond passive monitoring, GSD uses `effort:` frontmatter to signal the token budget appropriate for each skill. Heavy orchestrator skills (`plan-phase`, `execute-phase`, `autonomous`) declare `effort: max`; quick-status skills (`progress`, `stats`) declare `effort: low`.
|
||||
Beyond passive monitoring, MSD uses `effort:` frontmatter to signal the token budget appropriate for each skill. Heavy orchestrator skills (`plan-phase`, `execute-phase`, `autonomous`) declare `effort: max`; quick-status skills (`progress`, `stats`) declare `effort: low`.
|
||||
|
||||
Note: an earlier version of GSD also applied `context: fork` to these three heavy skills to protect the main session's context budget. This was removed (#921) because `plan-phase`, `execute-phase`, and `autonomous` are **spawning orchestrators** — their core function is to spawn subagents (`gsd-planner`, `gsd-executor`, etc.), and a forked subagent context does not have the `Agent` tool. Context isolation for these skills comes from the subagents they spawn, not from forking the orchestrator itself.
|
||||
Note: an earlier version of MSD also applied `context: fork` to these three heavy skills to protect the main session's context budget. This was removed (#921) because `plan-phase`, `execute-phase`, and `autonomous` are **spawning orchestrators** — their core function is to spawn subagents (`msd-planner`, `msd-executor`, etc.), and a forked subagent context does not have the `Agent` tool. Context isolation for these skills comes from the subagents they spawn, not from forking the orchestrator itself.
|
||||
|
||||
Complementing this, quick-status skills explicitly declare low effort in their definitions. This is a budget-conscious signal in the opposite direction: these skills read minimal state and return concise output, keeping their own footprint small by design.
|
||||
|
||||
@@ -101,9 +101,9 @@ Complementing this, quick-status skills explicitly declare low effort in their d
|
||||
|
||||
This machinery is worth being honest about.
|
||||
|
||||
**Hooks add maintenance surface.** Every runtime GSD supports must have its hooks registered, tested, and kept in sync with that runtime's event API. When a runtime changes its event names or firing semantics, GSD's hook registration needs updating. This is the cost of per-runtime observability rather than a single shared mechanism.
|
||||
**Hooks add maintenance surface.** Every runtime MSD supports must have its hooks registered, tested, and kept in sync with that runtime's event API. When a runtime changes its event names or firing semantics, MSD's hook registration needs updating. This is the cost of per-runtime observability rather than a single shared mechanism.
|
||||
|
||||
**Headroom tracking is a heuristic.** The hooks give GSD a signal, not a guarantee. A single model call can consume tokens unpredictably depending on the response length, tool use, and caching behaviour. GSD uses headroom estimates to warn and steer, not to make hard guarantees about what will fit.
|
||||
**Headroom tracking is a heuristic.** The hooks give MSD a signal, not a guarantee. A single model call can consume tokens unpredictably depending on the response length, tool use, and caching behaviour. MSD uses headroom estimates to warn and steer, not to make hard guarantees about what will fit.
|
||||
|
||||
**Subagents are isolated.** A spawned subagent cannot see uncommitted state in the orchestrating session. This is not a bug — it is necessary for independence — but it means anything the subagent needs must be on disk before it is spawned. This is precisely why `.planning/` exists as the shared substrate: plan files, `STATE.md`, `CONTEXT.md`, and `config.json` are all durable, file-system artefacts that any context — orchestrator or subagent — can read. The context-engineering design is self-consistent: the same principle that makes fresh-context subagents work (shared state lives in files, not in a conversation) is what makes the multi-agent architecture viable. See also [Multi-agent orchestration](multi-agent-orchestration.md) for how `.planning/` serves the same role across the orchestrator → agent boundary.
|
||||
|
||||
@@ -113,11 +113,11 @@ This machinery is worth being honest about.
|
||||
|
||||
Honesty about trade-offs matters here.
|
||||
|
||||
**Overhead.** The phase loop introduces real friction. Running `/gsd-discuss-phase`, `/gsd-plan-phase`, and `/gsd-execute-phase` as separate steps takes more elapsed time than typing "write this feature" into a plain session. For a small, well-understood change, that overhead is not justified.
|
||||
**Overhead.** The phase loop introduces real friction. Running `/msd-discuss-phase`, `/msd-plan-phase`, and `/msd-execute-phase` as separate steps takes more elapsed time than typing "write this feature" into a plain session. For a small, well-understood change, that overhead is not justified.
|
||||
|
||||
**Latency.** Spawning multiple subagents with fresh context is slower than a single in-context edit. Research, planning, and execution each incur round-trip costs.
|
||||
|
||||
**Ceremony for simple tasks.** If you need to rename a variable, fix a typo, or add a missing import, the phase loop is overkill. GSD Core provides `/gsd-quick` and `/gsd-fast` for ad-hoc work that does not warrant a full phase. See [Handle quick and fast tasks](../how-to/handle-quick-and-fast-tasks.md).
|
||||
**Ceremony for simple tasks.** If you need to rename a variable, fix a typo, or add a missing import, the phase loop is overkill. MSD Core provides `/msd-quick` and `/msd-fast` for ad-hoc work that does not warrant a full phase. See [Handle quick and fast tasks](../how-to/handle-quick-and-fast-tasks.md).
|
||||
|
||||
The phase loop pays for itself when the work is complex enough that context rot is a real risk — multi-file features, cross-cutting refactors, work that spans hours or sessions. For everything else, reach for the lighter primitive.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The Embeddable Orchestration System (EoS)
|
||||
|
||||
> **Explanation** — This document describes *why* GSD is built around one
|
||||
> **Explanation** — This document describes *why* MSD is built around one
|
||||
> versioned interface for embedding inside many different host applications,
|
||||
> and *how* the interface points, negotiated axes, and adapter shapes fit
|
||||
> together. It is not a how-to; for field-level detail see the
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
## The problem it solves
|
||||
|
||||
GSD is a filesystem-native orchestration engine, not a standalone
|
||||
MSD is a filesystem-native orchestration engine, not a standalone
|
||||
application. Almost all of the useful work it does — running a loop,
|
||||
dispatching an agent, resolving a model, persisting state — happens *inside*
|
||||
some other program: a CLI, an IDE, or an agentic desktop app. Each of those
|
||||
@@ -21,16 +21,16 @@ model call gets routed, and its own storage model. There is no shared
|
||||
substrate a priori.
|
||||
|
||||
Before 1.7.0, every host integration was wired bespoke: a runtime-specific
|
||||
adapter that reached into GSD's internals however it needed to, and exposed
|
||||
adapter that reached into MSD's internals however it needed to, and exposed
|
||||
whatever surface that host happened to support. That does not scale. Each new
|
||||
host is a fresh bespoke integration to write and maintain, drift between
|
||||
hosts accumulates silently over time, and no third party can build a host
|
||||
integration without reverse-engineering GSD's internals from source.
|
||||
integration without reverse-engineering MSD's internals from source.
|
||||
|
||||
The **Embeddable Orchestration System (EoS)** is the answer: one public, versioned
|
||||
contract — the ADR-1239 Host-Integration Interface — that every host
|
||||
integration is expressed against, first-party and third-party alike (Phase A,
|
||||
#1690). A host does not reach into GSD's internals; it declares which
|
||||
#1690). A host does not reach into MSD's internals; it declares which
|
||||
interface points it binds and which values it supports for each negotiated
|
||||
axis, and the engine tells it, deterministically, what it gets.
|
||||
|
||||
@@ -38,8 +38,8 @@ axis, and the engine tells it, deterministically, what it gets.
|
||||
|
||||
The interface has three moving parts.
|
||||
|
||||
**Six interface points** are the places a host can bind to GSD: `command`
|
||||
(how a user invokes a GSD command), `dispatch` (how that invocation reaches
|
||||
**Six interface points** are the places a host can bind to MSD: `command`
|
||||
(how a user invokes a MSD command), `dispatch` (how that invocation reaches
|
||||
the orchestration loop), `model` (how model calls are routed), `hooks` (how
|
||||
lifecycle events fire), `state` (how `.planning/` state is read and
|
||||
written), and `artifact` (how generated files are produced). A host does not
|
||||
@@ -68,7 +68,7 @@ usable, is the subject of its own document:
|
||||
[Interface versioning and deprecation policy](interface-versioning-policy.md).
|
||||
|
||||
Underpinning all of it is the `undocumented` sentinel: the permanent,
|
||||
fail-closed fallback for an axis a host says nothing about. GSD never
|
||||
fail-closed fallback for an axis a host says nothing about. MSD never
|
||||
*guesses* a host's capability from context — a host that omits an axis gets
|
||||
the safe default for that axis, never an assumed one.
|
||||
|
||||
@@ -77,9 +77,9 @@ the safe default for that axis, never an assumed one.
|
||||
The single most useful mental model for a given host integration is which of
|
||||
two adapter shapes it uses, set by the `embeddingMode` axis.
|
||||
|
||||
**Imperative** hosts can run GSD's own shell preamble or programmatic
|
||||
**Imperative** hosts can run MSD's own shell preamble or programmatic
|
||||
dispatch directly at invocation time (`embeddingMode: imperative`). The host
|
||||
hands control to GSD's runtime launcher and GSD does the rest, live, on every
|
||||
hands control to MSD's runtime launcher and MSD does the rest, live, on every
|
||||
invocation. Most CLI-style and IDE-embedded hosts work this way — OpenCode,
|
||||
Cursor, Cline, Hermes, Qwen, Kilo, Trae, Kimi, Antigravity, and Augment are
|
||||
all imperative integrations.
|
||||
@@ -92,15 +92,15 @@ host.
|
||||
|
||||
The consequence of that split is concrete, not academic: a declarative
|
||||
host's model configuration is fixed at install time, because there is no
|
||||
live dispatch step at which GSD could re-resolve it. If the model
|
||||
live dispatch step at which MSD could re-resolve it. If the model
|
||||
configuration changes after install, a declarative host is silently stale
|
||||
until the next reinstall — which is why GSD warns when a declarative host's
|
||||
until the next reinstall — which is why MSD warns when a declarative host's
|
||||
model configuration changes without a matching reinstall (#1688). An
|
||||
imperative host has no equivalent gap, because it re-runs GSD's dispatch
|
||||
imperative host has no equivalent gap, because it re-runs MSD's dispatch
|
||||
logic on every invocation.
|
||||
|
||||
Three **host-capability profiles** — `programmatic-cli`, `declarative-cli`,
|
||||
and `ide` — give the axis combinations for the reference cases GSD actually
|
||||
and `ide` — give the axis combinations for the reference cases MSD actually
|
||||
targets: a baseline imperative CLI, a baseline declarative CLI, and a
|
||||
baseline IDE (active model mode, engine-owned hook bus, sandboxed storage).
|
||||
See `PROFILE_BASELINES` in the reference for the exact axis values each
|
||||
@@ -119,29 +119,29 @@ driven entirely through the adapter layer (#2103). Gemini CLI was retired in
|
||||
favor of its successor, Antigravity, which shares its underlying
|
||||
infrastructure (#1928).
|
||||
|
||||
A companion `gsd-mcp-server` (#1681) gives hosts that prefer an MCP
|
||||
A companion `msd-mcp-server` (#1681) gives hosts that prefer an MCP
|
||||
transport a way to reach interface points 1 and 5 (`command` and `state`)
|
||||
without implementing the shell-preamble dispatch path themselves — a second
|
||||
transport onto the same contract, not a second contract.
|
||||
|
||||
The clearest evidence that the contract is doing its job: because every host
|
||||
integration is now expressed as data — a descriptor, not bespoke code —
|
||||
`/gsd-surface` can reproduce a given runtime's generated agent output
|
||||
`/msd-surface` can reproduce a given runtime's generated agent output
|
||||
byte-for-byte from the same descriptors the installer itself consumes
|
||||
(#1575). Runtime output can no longer drift from what the installer
|
||||
produces, because there is only one source of truth for it.
|
||||
|
||||
## Where EoS ends and Capabilities begin
|
||||
|
||||
EoS is easy to conflate with GSD's other extensibility axis, Capabilities
|
||||
EoS is easy to conflate with MSD's other extensibility axis, Capabilities
|
||||
(ADR-857, ADR-1244), because both are commonly described as "third parties
|
||||
extending GSD." They answer different questions, and the distinction matters
|
||||
extending MSD." They answer different questions, and the distinction matters
|
||||
for anyone building against either surface.
|
||||
|
||||
**EoS is about *where* GSD runs** — which host application embeds the
|
||||
**EoS is about *where* MSD runs** — which host application embeds the
|
||||
orchestration engine, and how that host's command surface, model routing,
|
||||
hook bus, and storage bind to the engine. **Capabilities are about *what*
|
||||
GSD does** — feature plug-ins that attach at GSD's Loop Extension Points
|
||||
MSD does** — feature plug-ins that attach at MSD's Loop Extension Points
|
||||
inside the loop that is already running. A host integration and a capability
|
||||
are orthogonal axes: the same capability behaves identically regardless of
|
||||
which host is running the loop, and the same host runs any composed set of
|
||||
@@ -151,7 +151,7 @@ Each has its own non-endorsing discoverability registry (#2182): the **EoS
|
||||
Registry** lists third-party host integrations, and the **Community
|
||||
Capability Registry** lists third-party capabilities. Both share one entry
|
||||
schema shape, one non-endorsement stance, and one submission process — see
|
||||
[GSD Registries](../registries/README.md) for the full specification of
|
||||
[MSD Registries](../registries/README.md) for the full specification of
|
||||
both.
|
||||
|
||||
## Why a published interface — and what it costs
|
||||
@@ -166,7 +166,7 @@ separate, disciplined document rather than an informal understanding.
|
||||
|
||||
The benefit is the reason 1.7.0's fourteen-runtime migration and three new
|
||||
hosts were tractable at all: a new host is additive descriptor work against
|
||||
a published contract, not a fork of GSD's engine internals. A third-party
|
||||
a published contract, not a fork of MSD's engine internals. A third-party
|
||||
host author can build and test an integration against the documented axis
|
||||
vocabulary without waiting on, or coordinating with, the core team — the
|
||||
same posture the EoS Registry's non-endorsement stance formalizes for
|
||||
@@ -178,6 +178,6 @@ every new host.
|
||||
|
||||
- [Reference: the Host-Integration Interface](../reference/host-integration-interface.md)
|
||||
- [Interface versioning and deprecation policy](interface-versioning-policy.md)
|
||||
- [GSD Registries](../registries/README.md)
|
||||
- [MSD Registries](../registries/README.md)
|
||||
- [How overlay capabilities compose](capability-overlay-model.md)
|
||||
- [What's new in 1.7.0](../whats-new-1.7.0.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Interface versioning and deprecation policy
|
||||
|
||||
This explains how the GSD Host-Integration Interface (ADR-1239) evolves over
|
||||
This explains how the MSD Host-Integration Interface (ADR-1239) evolves over
|
||||
time — what is an additive change, what is breaking, how `PROTOCOL_VERSION`
|
||||
bumps, and what deprecation window host-plugin authors can rely on. The policy
|
||||
exists because a published SDK is a long-term compatibility commitment (Hyrum's
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# The live-DOM UAT capability
|
||||
|
||||
Why GSD can drive a browser during execution, and why it does that from a purpose-built agent
|
||||
Why MSD can drive a browser during execution, and why it does that from a purpose-built agent
|
||||
instead of from the plan executor.
|
||||
|
||||
## The problem
|
||||
|
||||
A phase with a live-UI acceptance criterion could not be finished by the agent that executed
|
||||
it. `gsd-executor` carries no browser tools, so it did the correct thing — returned a
|
||||
it. `msd-executor` carries no browser tools, so it did the correct thing — returned a
|
||||
`checkpoint:human-action` at the gate — even though the work was not actually human-only. An
|
||||
orchestrator with a browser MCP server could do it unattended.
|
||||
|
||||
@@ -18,7 +18,7 @@ own `autonomous: false` marker could not distinguish **"a human must judge this"
|
||||
|
||||
## The shape that was not taken
|
||||
|
||||
The obvious fix is to add browser globs to `agents/gsd-executor.md`'s `tools:` line. It is one
|
||||
The obvious fix is to add browser globs to `agents/msd-executor.md`'s `tools:` line. It is one
|
||||
line, and an absent MCP server simply means the tool is not offered, so it is inert for anyone
|
||||
without one.
|
||||
|
||||
@@ -37,7 +37,7 @@ is the only control that exists:
|
||||
integrity + reversibility are the barrier."* There is no domain allowlist and no gate that
|
||||
inspects what a browser call fetched.
|
||||
|
||||
The codebase already reflected this instinct. `gsd-ui-auditor` — the one subagent that produces
|
||||
The codebase already reflected this instinct. `msd-ui-auditor` — the one subagent that produces
|
||||
UI screenshots — captures via CLI rather than taking an MCP tool grant. The executor carrying
|
||||
only `mcp__context7__*` while the researcher agents carry the full web-reaching set is a
|
||||
deliberate separation, not an oversight.
|
||||
@@ -53,14 +53,14 @@ One default-off capability owns everything:
|
||||
capability's `activationKey`. With it off the capability resolves **inactive**, and
|
||||
`resolveLoopHooks` is fail-closed on `state.active === true` — the hook does not render at
|
||||
all. The step's own `when` guard is a second, independent gate.
|
||||
- **The agent.** `gsd-dom-verifier` carries `mcp__chrome-devtools__*` and
|
||||
- **The agent.** `msd-dom-verifier` carries `mcp__chrome-devtools__*` and
|
||||
`mcp__claude-in-chrome__*` in **its own** `tools:` line, and carries no `Bash`. Browser reach
|
||||
is confined to one agent that only exists to look at a DOM.
|
||||
- **The step.** Registered at `execute:wave:post` as a `step` hook with `onError: skip`. A step
|
||||
is additive by construction — it never halts the host. Blocking preconditions are `gate`s,
|
||||
and this capability declares none.
|
||||
|
||||
`gsd-executor`'s tool surface is unchanged in every configuration. That is a tested invariant,
|
||||
`msd-executor`'s tool surface is unchanged in every configuration. That is a tested invariant,
|
||||
asserted as an absence, because that is the only way it is observable.
|
||||
|
||||
## Why the existing Playwright path was left alone
|
||||
@@ -79,7 +79,7 @@ new families the same two-condition shape Playwright already possessed.
|
||||
`chrome-devtools-mcp` holds an exclusive lock on its browser profile, so parallel execution
|
||||
waves will collide. The tempting design is a lease or queue around the profile.
|
||||
|
||||
GSD cannot enforce one. `--isolated` is a flag on the **user's** MCP server registration; GSD
|
||||
MSD cannot enforce one. `--isolated` is a flag on the **user's** MCP server registration; MSD
|
||||
neither launches that server nor passes its arguments. Coordination over a resource you do not
|
||||
own is theatre — it adds machinery, and the lock still happens.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Multi-agent orchestration in GSD Core
|
||||
# Multi-agent orchestration in MSD Core
|
||||
|
||||
> **Explanation** — This document describes *why* GSD Core is designed around
|
||||
> **Explanation** — This document describes *why* MSD Core is designed around
|
||||
> multi-agent orchestration and *how the pieces fit together*. It is not a
|
||||
> step-by-step guide. For configuration, see
|
||||
> [Configure model profiles](../how-to/configure-model-profiles.md) and the
|
||||
@@ -18,7 +18,7 @@ agent writes the fifth file in a complex task, it may have already forgotten
|
||||
the constraint stated in the first message. This is sometimes called *context
|
||||
rot*.
|
||||
|
||||
GSD Core's multi-agent design is a direct response to that problem. Instead of
|
||||
MSD Core's multi-agent design is a direct response to that problem. Instead of
|
||||
one long-running agent carrying the whole session, a thin orchestrator spawns
|
||||
short-lived specialised agents, each with a **fresh 200 K-token context window**
|
||||
and *only the artifacts it needs* to do its specific job. The orchestrator
|
||||
@@ -29,17 +29,17 @@ collects the result, and updates shared state in `.planning/`.
|
||||
|
||||
## The orchestrator → agent pattern
|
||||
|
||||
Every workflow in `gsd-core/workflows/` follows the same shape:
|
||||
Every workflow in `msd-core/workflows/` follows the same shape:
|
||||
|
||||
```text
|
||||
Orchestrator (workflow .md file)
|
||||
│
|
||||
├── Load context
|
||||
│ gsd-tools.cjs init <workflow> <phase>
|
||||
│ msd-tools.cjs init <workflow> <phase>
|
||||
│ → JSON: project info, config, state, phase details
|
||||
│
|
||||
├── Resolve model
|
||||
│ gsd-tools.cjs resolve-model <agent-name>
|
||||
│ msd-tools.cjs resolve-model <agent-name>
|
||||
│ → opus | sonnet | haiku | inherit
|
||||
│
|
||||
├── Spawn specialised agent (Task/SubAgent call)
|
||||
@@ -51,7 +51,7 @@ Orchestrator (workflow .md file)
|
||||
├── Collect result
|
||||
│
|
||||
└── Update state
|
||||
gsd-tools.cjs state update / state patch / state advance-plan
|
||||
msd-tools.cjs state update / state patch / state advance-plan
|
||||
```
|
||||
|
||||
The orchestrator is deliberately thin. It does not reason about the domain,
|
||||
@@ -61,19 +61,19 @@ the orchestrator's context from accumulating domain noise.
|
||||
|
||||
### The agent roster
|
||||
|
||||
GSD Core's agents fall into functional categories that map onto the
|
||||
MSD Core's agents fall into functional categories that map onto the
|
||||
research → plan → execute → verify pipeline:
|
||||
|
||||
| Category | Agents | Typical parallelism |
|
||||
|---|---|---|
|
||||
| Researchers | `gsd-project-researcher`, `gsd-phase-researcher`, `gsd-ui-researcher`, `gsd-advisor-researcher` | 4 parallel (stack, features, architecture, pitfalls) |
|
||||
| Synthesisers | `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, up to 3 revision iterations |
|
||||
| Executors | `gsd-executor` | Parallel within a wave, sequential across waves |
|
||||
| Verifiers | `gsd-verifier` | Sequential, after all executors complete |
|
||||
| Mappers | `gsd-codebase-mapper` | 4 parallel sub-probes |
|
||||
| Auditors | `gsd-ui-auditor`, `gsd-security-auditor` | Sequential |
|
||||
| Researchers | `msd-project-researcher`, `msd-phase-researcher`, `msd-ui-researcher`, `msd-advisor-researcher` | 4 parallel (stack, features, architecture, pitfalls) |
|
||||
| Synthesisers | `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, up to 3 revision iterations |
|
||||
| Executors | `msd-executor` | Parallel within a wave, sequential across waves |
|
||||
| Verifiers | `msd-verifier` | Sequential, after all executors complete |
|
||||
| Mappers | `msd-codebase-mapper` | 4 parallel sub-probes |
|
||||
| Auditors | `msd-ui-auditor`, `msd-security-auditor` | Sequential |
|
||||
|
||||
Each agent definition (in `agents/*.md`) declares its allowed tool access,
|
||||
purpose, and colour for terminal output. An agent that only needs to read files
|
||||
@@ -87,7 +87,7 @@ For the complete agent roster, see [Inventory](../INVENTORY.md#agents).
|
||||
|
||||
## Wave-based parallel execution
|
||||
|
||||
The most visible expression of multi-agent design is how `/gsd-execute-phase`
|
||||
The most visible expression of multi-agent design is how `/msd-execute-phase`
|
||||
handles a set of plans that may depend on one another.
|
||||
|
||||
Before spawning any executor, the orchestrator performs a **wave analysis**:
|
||||
@@ -173,7 +173,7 @@ than diluted by noise from other pipeline stages.
|
||||
|
||||
**Context hygiene across sessions.** Because all state lives in
|
||||
`.planning/` as human-readable Markdown and JSON (not in any agent's context
|
||||
window), GSD workflows survive context resets (`/clear`), tab switches, and
|
||||
window), MSD workflows survive context resets (`/clear`), tab switches, and
|
||||
multi-day breaks. The next agent always starts from persisted, verified
|
||||
artifacts rather than from a reconstructed memory of a long conversation.
|
||||
|
||||
@@ -186,7 +186,7 @@ Multi-agent orchestration is not free.
|
||||
**Coordination overhead.** Each agent spawn is a round-trip: the orchestrator
|
||||
must format a prompt, hand off context, wait for the subagent to complete
|
||||
(typically 1–5 minutes), and then parse the result. A single capable agent
|
||||
working in one context would finish faster for simple tasks. GSD mitigates
|
||||
working in one context would finish faster for simple tasks. MSD mitigates
|
||||
this by making parallelism the default wherever dependencies permit — the
|
||||
four researchers in a `plan-phase` run simultaneously, not sequentially.
|
||||
|
||||
@@ -199,7 +199,7 @@ expectations.
|
||||
|
||||
**Context stitching cost.** Packaging the right artifacts for each agent
|
||||
requires the orchestrator to spend tokens assembling and transmitting context
|
||||
payloads. This is the cost of isolation. The `gsd-tools.cjs init` handler
|
||||
payloads. This is the cost of isolation. The `msd-tools.cjs init` handler
|
||||
produces a JSON payload that balances completeness with token budget, applying
|
||||
cache-friendly ordering so that the stable parts of the payload (project
|
||||
definition, config) hit the cache on repeat invocations.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# GSD Core security model
|
||||
# MSD Core security model
|
||||
|
||||
> **Explanation** — This document describes *why* GSD Core has the security
|
||||
> **Explanation** — This document describes *why* MSD Core has the security
|
||||
> posture it does and *how the layers fit together*. It is not a reference for
|
||||
> every hook parameter. For the `/gsd-secure-phase` command and its options,
|
||||
> every hook parameter. For the `/msd-secure-phase` command and its options,
|
||||
> see [Commands](../COMMANDS.md). For the implementation-level hook
|
||||
> architecture, see [Architecture § Hook System](../ARCHITECTURE.md#hook-system).
|
||||
> For the org-wide security baseline (scanner controls, incident checklists,
|
||||
@@ -13,13 +13,13 @@
|
||||
## Why AI-driven development needs a dedicated security posture
|
||||
|
||||
A conventional code editor does not execute arbitrary packages on your behalf.
|
||||
GSD Core does. The research → plan → execute pipeline automates the full path
|
||||
MSD Core does. The research → plan → execute pipeline automates the full path
|
||||
from "name a package" to "run `npm install <package>`", from "write a
|
||||
planning artifact" to "use that artifact as an LLM system prompt". Each
|
||||
automation step removes a human from the loop — and each removal is a
|
||||
potential attack surface.
|
||||
|
||||
GSD Core's security model is built around one organising principle:
|
||||
MSD Core's security model is built around one organising principle:
|
||||
**defence in depth**. No single control is assumed to be perfect. Several
|
||||
overlapping layers each reduce a distinct class of risk, and together they
|
||||
make the attack surface substantially harder to exploit without eliminating
|
||||
@@ -45,7 +45,7 @@ The insidious quality of slopsquatting is that a hallucinated name that passes
|
||||
`npm view` *looks legitimate*. The registry entry proves only that someone
|
||||
registered the name — not that the package does what the AI said it does, not
|
||||
that it has any legitimate users, and not that its install scripts are safe.
|
||||
Without a gate, a hallucinated name would flow undetected through GSD's
|
||||
Without a gate, a hallucinated name would flow undetected through MSD's
|
||||
researcher → planner → executor pipeline and eventually run as
|
||||
`npm install <attacker-package>` on your machine.
|
||||
|
||||
@@ -53,8 +53,8 @@ researcher → planner → executor pipeline and eventually run as
|
||||
|
||||
The gate operates across three pipeline stages:
|
||||
|
||||
**Research stage.** When `gsd-phase-researcher` recommends external packages,
|
||||
it runs `gsd-tools query package-legitimacy check --ecosystem <npm|pypi|crates>
|
||||
**Research stage.** When `msd-phase-researcher` recommends external packages,
|
||||
it runs `msd-tools query package-legitimacy check --ecosystem <npm|pypi|crates>
|
||||
<pkgs>` against each one. Verdicts (`OK|SUS|SLOP`) are computed from live
|
||||
registry APIs against thresholds `{ minAgeDays: 30, minWeeklyDownloads: 1000,
|
||||
requireRepo: true }`, plus terminal short-circuits for non-existence and
|
||||
@@ -64,7 +64,7 @@ Legitimacy Audit` table in `RESEARCH.md`. Packages tagged `[SLOP]`
|
||||
`RESEARCH.md` entirely** before the file is saved. They never reach the
|
||||
planner.
|
||||
|
||||
**Planning stage.** `gsd-planner` reads the Audit table. For any package
|
||||
**Planning stage.** `msd-planner` reads the Audit table. For any package
|
||||
tagged `[SUS]` (suspicious: newly registered, low download count, no source
|
||||
repository, or naming pattern close to a popular package) or `[ASSUMED]`
|
||||
(sourced from WebSearch rather than direct registry verification), the planner
|
||||
@@ -73,7 +73,7 @@ checkpoint includes a direct link to the registry page and specific things to
|
||||
look for: maintainer history, issue-tracker activity, absence of suspicious
|
||||
install scripts.
|
||||
|
||||
**Execution stage.** If an install fails, `gsd-executor` **surfaces a
|
||||
**Execution stage.** If an install fails, `msd-executor` **surfaces a
|
||||
checkpoint and stops**. It does not silently try an alternative package name —
|
||||
which could itself be malicious. This is an explicit rule in the executor's
|
||||
behaviour (RULE 3 in the executor agent definition).
|
||||
@@ -122,7 +122,7 @@ downgrading everything to `[ASSUMED]`.
|
||||
|
||||
### The threat
|
||||
|
||||
GSD Core generates Markdown files that become LLM system prompts. The
|
||||
MSD Core generates Markdown files that become LLM system prompts. The
|
||||
research pipeline reads external web content; the planning pipeline
|
||||
incorporates user-supplied text (`--text-file`, `--prd`); the execution
|
||||
pipeline writes planning artifacts that are later re-read as agent context.
|
||||
@@ -133,9 +133,9 @@ exfiltrate information.
|
||||
|
||||
### How the defences work
|
||||
|
||||
GSD Core addresses prompt injection at three levels.
|
||||
MSD Core addresses prompt injection at three levels.
|
||||
|
||||
**Input validation (`security.cjs`).** The `gsd-core/bin/lib/security.cjs`
|
||||
**Input validation (`security.cjs`).** The `msd-core/bin/lib/security.cjs`
|
||||
module is the central security utility. It provides:
|
||||
|
||||
- Path containment: user-supplied file paths and directories are validated to
|
||||
@@ -176,7 +176,7 @@ legitimately does not exist yet. A lexical check **cannot see a symlink**, so a
|
||||
caller relying on one for a write-confinement guarantee must pair it with its
|
||||
own symlink refusal. Three call sites use it, each for a stated reason.
|
||||
|
||||
The backup-restore gate in `gsd-core/bin/gsd-tools.cjs` rejects symlinks outright:
|
||||
The backup-restore gate in `msd-core/bin/msd-tools.cjs` rejects symlinks outright:
|
||||
the canonical predicate accepts a link whose target resolves inside the root, but
|
||||
for a restore that is still wrong, because writing through the link overwrites
|
||||
whatever it points at instead of materializing a regular file at the backed-up
|
||||
@@ -225,9 +225,9 @@ file is still linted), leaving their hand-rolled comparisons permanently
|
||||
un-ratcheted; the only remedy is a fix-forward migration, never an edit to a
|
||||
shipped body.
|
||||
|
||||
**Runtime hook: `gsd-prompt-guard.js`.** This hook fires on every Write or
|
||||
**Runtime hook: `msd-prompt-guard.js`.** This hook fires on every Write or
|
||||
Edit call that targets `.planning/` files. It scans the content being written
|
||||
for injection patterns shared with `gsd-read-injection-scanner.js` through
|
||||
for injection patterns shared with `msd-read-injection-scanner.js` through
|
||||
`hooks/lib/injection-patterns.js` — one module both hooks `require()`, so the
|
||||
two surfaces cannot drift apart (#3504). The set is deliberately a subset of
|
||||
`security.cjs`'s patterns: the hooks stay loadable standalone, without the
|
||||
@@ -236,24 +236,24 @@ but does not block the write. The rationale is that a false-positive block on
|
||||
a legitimate planning write would be more disruptive than a missed injection
|
||||
in a secondary scan layer.
|
||||
|
||||
**Runtime hook: `gsd-read-injection-scanner.js`.** This hook fires on the
|
||||
**Runtime hook: `msd-read-injection-scanner.js`.** This hook fires on the
|
||||
output of every Read, WebFetch, and WebSearch tool call. It scans the *content
|
||||
that was just read or fetched* for injected instructions in untrusted content —
|
||||
catching cases where an attacker has embedded instructions in a file or remote
|
||||
resource that GSD is about to incorporate into an agent's context. The 10
|
||||
resource that MSD is about to incorporate into an agent's context. The 10
|
||||
research and doc-ingest agents additionally carry a shared `<security_context>`
|
||||
data/instruction boundary (defined in
|
||||
`gsd-core/references/untrusted-input-boundary.md`): `gsd-project-researcher`,
|
||||
`gsd-phase-researcher`, `gsd-ui-researcher`, `gsd-assumptions-analyzer`,
|
||||
`gsd-advisor-researcher`, `gsd-doc-classifier`, `gsd-doc-synthesizer`,
|
||||
`gsd-research-synthesizer`, `gsd-ai-researcher`, and `gsd-domain-researcher`.
|
||||
`msd-core/references/untrusted-input-boundary.md`): `msd-project-researcher`,
|
||||
`msd-phase-researcher`, `msd-ui-researcher`, `msd-assumptions-analyzer`,
|
||||
`msd-advisor-researcher`, `msd-doc-classifier`, `msd-doc-synthesizer`,
|
||||
`msd-research-synthesizer`, `msd-ai-researcher`, and `msd-domain-researcher`.
|
||||
Any content fetched or read by those agents is treated as data, never as
|
||||
instructions, regardless of what the content claims to be.
|
||||
|
||||
**Opt-in blocking (`security.injection_blocking`).** By default all injection
|
||||
detections are advisory-only (logged, not blocked). Setting
|
||||
`security.injection_blocking = true` in `.planning/config.json` (a registered
|
||||
config key — `gsd config-set security.injection_blocking true`) upgrades
|
||||
config key — `msd config-set security.injection_blocking true`) upgrades
|
||||
HIGH-confidence detections to **blocking**. Be precise about what this does: the
|
||||
scanner is a **PostToolUse** hook, so it runs *after* the Read/WebFetch/WebSearch
|
||||
has already executed and the fetched content is already in the model's transcript.
|
||||
@@ -269,15 +269,15 @@ not a redactor.
|
||||
|
||||
**CI scanner.** `prompt-injection-scan.security.test.cjs` scans all agent, workflow,
|
||||
and command files for embedded injection vectors as part of the test suite.
|
||||
This catches injection attempts in the GSD source itself — for example, a
|
||||
This catches injection attempts in the MSD source itself — for example, a
|
||||
supply-chain attack that modified a workflow file to add a role-override
|
||||
instruction.
|
||||
|
||||
### Read Injection Scanner vs Prompt Guard
|
||||
|
||||
The two hooks cover complementary surfaces. `gsd-prompt-guard.js` watches
|
||||
The two hooks cover complementary surfaces. `msd-prompt-guard.js` watches
|
||||
*writes to planning artifacts* — it catches injection being planted.
|
||||
`gsd-read-injection-scanner.js` watches *reads and remote fetches* — it catches
|
||||
`msd-read-injection-scanner.js` watches *reads and remote fetches* — it catches
|
||||
injection being ingested from external content (a dependency's README, a
|
||||
third-party config file, a user-provided document, or any URL fetched via
|
||||
WebFetch or WebSearch). The in-prompt `<security_context>` boundary in research
|
||||
@@ -285,10 +285,10 @@ agents provides an additional containment layer: even if an injected string
|
||||
reaches an agent, it is structurally separated from the instruction region.
|
||||
Together these controls bracket the ingest → store → re-read lifecycle.
|
||||
|
||||
**Runtime hook: `gsd-workflow-guard.js` — advisory vs. blocking posture.**
|
||||
**Runtime hook: `msd-workflow-guard.js` — advisory vs. blocking posture.**
|
||||
This hook has two legs with two deliberately different failure postures. The
|
||||
edit leg is **advisory**: when `hooks.workflow_guard` is enabled it warns on
|
||||
edits made outside a GSD workflow, and on any internal error it fails open
|
||||
edits made outside a MSD workflow, and on any internal error it fails open
|
||||
(exit 0) — a broken advisory must never wedge a session's tool calls. The
|
||||
Bash leg carries the hook's one **hard block**: `git add -f` / `git add
|
||||
--force` on an `agent-*` or `worktree-agent-*` branch is blocked outright
|
||||
@@ -308,7 +308,7 @@ one hard block this hook owns.
|
||||
|
||||
## Layer 3 — Repository and dependency integrity
|
||||
|
||||
Upstream of GSD's runtime behaviour, the `open-gsd` organisation enforces
|
||||
Upstream of MSD's runtime behaviour, the `open-gsd` organisation enforces
|
||||
controls at the repository and package level. These are documented in full in
|
||||
[`docs/security/baseline.md`](../security/baseline.md) and are summarised
|
||||
here for completeness.
|
||||
@@ -317,7 +317,7 @@ here for completeness.
|
||||
`package-lock.json` and verified against published checksums before install.
|
||||
A `scripts/check-npm-integrity.cjs` gate detects invalid versions, missing
|
||||
packages, and extraneous packages at CI time. This mitigates dependency
|
||||
confusion and typosquatting attacks against GSD's own dependencies.
|
||||
confusion and typosquatting attacks against MSD's own dependencies.
|
||||
|
||||
**Secret scanning.** Every commit and PR is scanned for hardcoded secrets.
|
||||
Intentional test fixtures must be annotated with the project-standard
|
||||
@@ -333,7 +333,7 @@ hide malicious content in diffs.
|
||||
|
||||
## Layer 4 — Subprocess execution
|
||||
|
||||
GSD starts external programs constantly: git, npm, reviewer CLIs declared by
|
||||
MSD starts external programs constantly: git, npm, reviewer CLIs declared by
|
||||
capabilities, and whatever a gate predicate names. Every one of those is a
|
||||
place where an argument could become a command. One module owns the whole
|
||||
question — `src/shell-command-projection.cts`, the single platform seam.
|
||||
@@ -342,7 +342,7 @@ question — `src/shell-command-projection.cts`, the single platform seam.
|
||||
the mechanism behind CVE-2024-27980: the shell re-parses the argument list, so
|
||||
a value containing `&` or `|` stops being data and becomes a second command.
|
||||
Node 26 additionally deprecates `shell: true` alongside an argument array
|
||||
(DEP0190), because arguments are concatenated rather than escaped. GSD resolves
|
||||
(DEP0190), because arguments are concatenated rather than escaped. MSD resolves
|
||||
binaries explicitly instead.
|
||||
|
||||
**Explicit resolution, not shell lookup.** `resolveExecutableBinary` scans
|
||||
@@ -407,21 +407,21 @@ creative injection that does not match known patterns, or an injection that
|
||||
arrives through a channel the hooks do not cover. The previously uncovered
|
||||
channel of content injected into a dependency's published README and read by a
|
||||
subagent browsing documentation is now scanned at ingress by
|
||||
`gsd-read-injection-scanner.js` (which covers WebFetch and WebSearch output)
|
||||
`msd-read-injection-scanner.js` (which covers WebFetch and WebSearch output)
|
||||
and structurally isolated in-prompt by the `<security_context>` boundary in
|
||||
research agents — but novel jailbreaks and low-signal injections may still pass
|
||||
undetected. Defence in depth means each layer makes the attack harder, not that
|
||||
any single layer makes it impossible.
|
||||
|
||||
**What the UI-SPEC provenance rule does not eliminate:** `gsd-ui-checker`
|
||||
**What the UI-SPEC provenance rule does not eliminate:** `msd-ui-checker`
|
||||
Dimension 7 requires a component inventory to record the command that
|
||||
enumerated it, and instructs the checker never to run that command — it is
|
||||
text from a document, not an instruction to the agent. **That barrier is
|
||||
prompt-level only.** The checker holds a `Bash` grant it genuinely needs (the
|
||||
agent-skills bootstrap shells out through `gsd_run`), and tool grants here are
|
||||
agent-skills bootstrap shells out through `msd_run`), and tool grants here are
|
||||
not command-scoped, so nothing structurally prevents execution of a command
|
||||
string lifted out of a UI-SPEC. No shipped instruction does so, and the spec is
|
||||
written by `gsd-ui-researcher`, which carries the `<security_context>`
|
||||
written by `msd-ui-researcher`, which carries the `<security_context>`
|
||||
untrusted-input boundary for its web and MCP ingress — but this is defense by
|
||||
instruction, not by capability. The same shape is older and wider in Dimension 6,
|
||||
where the *researcher* is told to run `npx shadcn view {block} --registry {url}`
|
||||
@@ -452,8 +452,8 @@ and disclosure policy.
|
||||
|
||||
## Related
|
||||
|
||||
- [Commands](../COMMANDS.md) — includes `/gsd-secure-phase` and
|
||||
`/gsd-code-review` with security-relevant flags
|
||||
- [Commands](../COMMANDS.md) — includes `/msd-secure-phase` and
|
||||
`/msd-code-review` with security-relevant flags
|
||||
- [Architecture § Hook System](../ARCHITECTURE.md#hook-system) —
|
||||
implementation detail on every hook, its event trigger, and safety properties
|
||||
- [SECURITY.md](../../SECURITY.md) — vulnerability reporting, org-wide
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# The phase loop
|
||||
|
||||
> The central mental model for how GSD Core organises work.
|
||||
> The central mental model for how MSD Core organises work.
|
||||
|
||||
---
|
||||
|
||||
## What the loop is
|
||||
|
||||
GSD Core structures all development work as a repeating cycle:
|
||||
MSD Core structures all development work as a repeating cycle:
|
||||
|
||||
```text
|
||||
Discuss → (UI design) → Plan → Execute → Verify → Ship
|
||||
@@ -30,7 +30,7 @@ The Discuss step is deliberately lightweight. It is a conversation, not a specif
|
||||
|
||||
### UI design (optional)
|
||||
|
||||
For phases with a visual component, there is an optional `/gsd-ui-phase` step between Discuss and Plan. It produces a `UI-SPEC.md` — a design contract that describes layout, interaction, and visual behaviour before any code is written. This step is worth running when the UI is complex enough that ambiguity in the design would produce divergent implementation choices. A clear design contract is far cheaper to write than to re-implement.
|
||||
For phases with a visual component, there is an optional `/msd-ui-phase` step between Discuss and Plan. It produces a `UI-SPEC.md` — a design contract that describes layout, interaction, and visual behaviour before any code is written. This step is worth running when the UI is complex enough that ambiguity in the design would produce divergent implementation choices. A clear design contract is far cheaper to write than to re-implement.
|
||||
|
||||
### Plan
|
||||
|
||||
@@ -87,7 +87,7 @@ A good phase scope is one where:
|
||||
- The execution can be parallelised into a handful of non-overlapping plans, not dozens.
|
||||
- There is a clear, testable definition of done that a verifier can check without reading the entire codebase.
|
||||
|
||||
Concretely: "Add HMAC-SHA256 signature validation middleware" is a good phase scope. "Build the authentication system" usually is not — it almost always contains multiple independent concerns that would be better as separate phases. "Fix the typo in the README" is below the threshold where the loop adds value; use `/gsd-quick` instead.
|
||||
Concretely: "Add HMAC-SHA256 signature validation middleware" is a good phase scope. "Build the authentication system" usually is not — it almost always contains multiple independent concerns that would be better as separate phases. "Fix the typo in the README" is below the threshold where the loop adds value; use `/msd-quick` instead.
|
||||
|
||||
When in doubt, split. A smaller phase completes faster, verifies more confidently, and makes it easier to course-correct if a design decision turns out to be wrong.
|
||||
|
||||
@@ -113,7 +113,7 @@ The loop exists because each step prevents failures that are genuinely expensive
|
||||
|
||||
When the loop works well, it feels like a rhythm: a cadence of focused, bounded work where each step is clear because the previous step did its job. The overhead is real, but it is front-loaded — paid in minutes of planning rather than hours of rework.
|
||||
|
||||
For work that falls below the threshold where the loop is warranted, GSD Core provides lighter primitives. The phase loop is one tool, not the only tool.
|
||||
For work that falls below the threshold where the loop is warranted, MSD Core provides lighter primitives. The phase loop is one tool, not the only tool.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user