docs(#2999): document the takeover process for a capability, reviewer lane, or EoS integration (#3000)

* docs(#2999): document the capability / reviewer-lane / EoS takeover process

The capability ecosystem documented a complete forward lifecycle — develop,
publish, version, import, update, remove, turn off — but nothing covering a
change of maintainer for an entry that already exists. Adds
docs/how-to/take-over-a-capability-or-eos.md defining four takeover modes
(consensual handoff, adoption fork, first-party absorption, retirement), the
PR shape each takes, a per-surface snapshot of the inherited user-visible
contract, and an install-continuity checklist.

Also corrects .github/PULL_REQUEST_TEMPLATE/registry-entry.md, which directed
contributors to a 'Registry' Discussions category that does not exist — the
category is named 'EoS Registry' per docs/registries/README.md, and because
'discussion' is a required field the thread must exist before the PR is
opened, so the wrong name stalled contributors at the first required step.

Closes #2999

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(#2999): backfill changeset pr number to 3000

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-08-02 14:02:58 -04:00
committed by GitHub
parent a987cf2731
commit d770365753
4 changed files with 154 additions and 1 deletions

View File

@@ -0,0 +1,11 @@
---
type: Added
pr: 3000
---
**New how-to: [Take over a capability, reviewer lane, or EoS integration](../docs/how-to/take-over-a-capability-or-eos.md).** The capability ecosystem documented a complete forward lifecycle — develop, publish, version, import, update, remove, turn off — but nothing covering a change of *maintainer* for an entry that already exists. There is no `gsd capability transfer` command and no rename tooling, and `docs/registries/README.md` specifies submission and the narrow removal policy but never transfer, so a would-be adopter had no documented path and a reviewing maintainer had no stated bar.
The guide defines four takeover modes and the PR shape each one takes. **T1 — consensual handoff** keeps the `id` and the entry, changes only `repo` / `author` / `install` / `uninstall`, and requires a permalink to the outgoing author's public handoff comment in the entry's Discussion. That permalink is mandatory rather than advisory because entry-update authorship is not verified anywhere: `scripts/registry-schema.cjs` and `npm run validate:registry` check an entry's shape, not who is changing it, and the registry-entry PR template's "`repo` links to a repository I own" is a self-attestation — so a PR repointing `repo` and `author` at an unrelated account passes every automated gate, and the reviewing maintainer is the only control. **T2 — adoption fork** takes a new `id`, opens a new Discussion, and leaves the original entry untouched, because the narrow removal policy removes an entry only for illegal content, malware, spam, or a dead link and never for staleness or abandonment: an abandoned-but-working entry can never be reclaimed, so adoption is always additive and the original `id` stays taken. **T3 — first-party absorption** routes through `approved-feature` plus an ADR, lands under `capabilities/<id>/capability.json` per ADR-894, annotates rather than deletes the registry entry, and requires a migration note telling existing users to `gsd capability remove <old-id>` first — config keys are exclusive to one capability and skill/agent stems must be unique, so a first-party capability that collides with an installed overlay wins *silently*, leaving the user running code they did not think they were running. **T4 — retirement** is restricted to the four narrow grounds with evidence in the PR body.
Around the modes the guide adds an evidence pack, license and reserved-prefix and consent gates, a per-surface snapshot of the inherited user-visible contract (`loopExtensionPoints` / `hookKinds` / `configKeys` / `requires` / `runtimeCompat` for Feature Capabilities; `slug` / `flags` / `reviewsSection` uniqueness across the merged first-party and overlay set for reviewer lanes; `protocolVersion`, `interfacePoints`, `profile` and the eight ADR-1239 axes for EoS integrations), and an install-continuity checklist covering the failure modes that break existing consumers — `id` continuity, since consent is stored per `(realpath(projectRoot), capability id)` and an `id` change re-prompts every installed project and orphans the update path; re-stating `integrity` and `provenance` after a rebuild under new ownership; holding the executable-surface set steady so the handoff is not itself a consent event; and not narrowing `engines.gsd` without a matching `compatVersions` row. Post-takeover obligations note that a Release must be cut under the new repo, since there is no re-registration and both the shields badge and the `releases/latest` permalink render live from `repo`. The two enforcement gaps — unverified entry-update authorship, and the absence of any `id` migration path — are stated explicitly in the guide so the process is not mistaken for something CI verifies.
**Fixed alongside:** `.github/PULL_REQUEST_TEMPLATE/registry-entry.md` directed contributors to file their Discussion in a `Registry` category that does not exist. `docs/registries/README.md` names the category `EoS Registry` and explicitly notes the name is misleading because it carries threads for all three catalogs. Because `discussion` is a required field, the thread must exist *before* the entry's PR is opened — so a contributor following the template stalled at the first required step of the submission process. (#2999)

View File

@@ -72,7 +72,7 @@ Full schema and process: [docs/registries/README.md](../../docs/registries/READM
## Checklist
- [ ] `npm run validate:registry` passes locally against my entry
- [ ] `discussion` links to a GitHub Discussion in the `Registry` category (or notes that one will be created on merge, per [docs/registries/README.md](../../docs/registries/README.md))
- [ ] `discussion` links to a GitHub Discussion in the `EoS Registry` category — which, despite its name, carries threads for all three registries (or notes that one will be created on merge, per [docs/registries/README.md](../../docs/registries/README.md))
- [ ] `.changeset/` fragment added with an `Added` type describing the new listing
---

View File

@@ -38,6 +38,7 @@ Language versions: [English](README.md) · [Português (pt-BR)](pt-BR/README.md)
- [Develop a Capability for GSD 1.5+](how-to/develop-a-capability.md) — add feature Capabilities, hook fragments, and registry entries
- [Ship a reviewer lane in your capability](how-to/ship-a-reviewer-lane.md) — declare a `reviewer` body so `/gsd-review` discovers, invokes, and renders your external review CLI or model endpoint
- [List your reviewer lane in the registry](how-to/list-your-reviewer-lane.md) — publish a lane you have built to the Reviewer Lane Registry so other people can find and install it
- [Take over a capability or EoS integration](how-to/take-over-a-capability-or-eos.md) — assume maintainership of an existing third-party capability, reviewer lane, or EoS host integration through a handoff, an adoption fork, first-party absorption, or a de-listing
- [Add or update a host's integration](how-to/add-or-update-a-host-integration.md) — set a host's documentation-sourced `runtime.hostIntegration` axes (ADR-1239 Phase A), with the `undocumented` sentinel rule
- [Turn a capability off (and keep it off)](how-to/turn-a-capability-off.md) — disable a capability via the surface, or gate individual hooks off without removing the capability
- [Drive GSD from a tracker issue](how-to/drive-gsd-from-a-tracker-issue.md) — start a phase from a GitHub, Linear, or Jira issue

View File

@@ -0,0 +1,141 @@
# How to take over a capability, reviewer lane, or EoS integration
A **takeover** changes who maintains something that already exists and is already listed — a third-party Feature Capability, a reviewer lane, or an Embeddable Orchestration System (EoS) host integration.
There is no `gsd capability transfer` command and no rename tooling. A takeover is a governance process executed entirely through registry pull requests and the entry's GitHub Discussion thread. Everything below is manual and auditable by design.
## Decide what you are taking over
| Surface | Manifest | Registry source | Ships in |
|---|---|---|---|
| First-party capability | `capabilities/<id>/capability.json` | none — generated registry only | the `gsd-core` release |
| Third-party Feature Capability | `capability.json`, `role: "feature"` | `docs/registries/capabilities.json` | the author's own repo |
| Third-party reviewer lane | `capability.json`, `role: "reviewer"` | `docs/registries/reviewers.json` | the author's own repo |
| Third-party EoS host integration | ADR-1239 host plugin (no `capability.json` in `gsd-core`) | `docs/registries/eos.json` | the author's own repo |
A first-party capability has no registry entry and no external owner — changing who works on it is ordinary contribution, not a takeover. Use this guide only when an external `repo` and `author` are recorded somewhere under `docs/registries/`.
## Pick the takeover mode
| Mode | Entry condition | End state |
|---|---|---|
| **T1 — Consensual handoff** | The current author agrees, in public, to hand the project off | Same `id`, same entry, new `repo` and `author` |
| **T2 — Adoption fork** | The author is unreachable but the linked repo still works | **New** `id`, new entry, new Discussion; the original entry stays |
| **T3 — First-party absorption** | GSD absorbs the surface into `capabilities/<id>/` | In-repo capability; the registry entry is annotated, not deleted |
| **T4 — Retirement** | Illegal content, malware, spam, or a dead link | Entry removed |
> **The narrow removal policy constrains every mode.** A merged entry is removed only for illegal content, malware, spam, or a repo that is dead or completely non-functional. It is **never** removed for staleness, quality, abandonment, or a maintainer's disagreement with its design. An abandoned-but-working entry therefore cannot be reclaimed — T2 is always additive, and the original `id` stays taken forever.
## Step 1 — Build the evidence pack
Collect all of this before opening anything. Every later step reads from it.
- The current registry object, copied verbatim from `capabilities.json`, `reviewers.json`, or `eos.json`.
- The upstream `capability.json` (or, for EoS, the host plugin's own manifest), copied verbatim.
- `id`, `author`, `repo`, `license`, `enginesGsd`, and — for EoS — `protocolVersion`.
- The entry's `discussion` URL and its full comment history.
- A liveness probe of `repo`: is the default branch reachable and non-empty? If the link is dead, the correct mode is **T4**, not T2.
- The upstream release history — the shields badge and the update channel both read from `repo`, so a repo with no releases has no update channel at all.
## Step 2 — Verify you are allowed to take it over
**License gate.** T2 and T3 both require a fork or a derivative. If `license` is `UNLICENSED` or `Proprietary`, stop — neither mode is available without written permission from the rights holder.
**Reserved-prefix gate.** The `gsd-`, `gsd-core-`, and `anthropic-` prefixes are reserved for first-party, and a third-party id claiming one is rejected at the conformance gate. You may only move into a reserved prefix as part of **T3**.
**Consent gate (T1 only).** The handoff must be a public comment in the entry's Discussion thread, posted from the GitHub account that owns `repo`. A DM, an email, or a comment from any other account is not sufficient. The reason is structural: the registry-entry PR template's ownership statement is self-attested and no automated gate checks who is changing `repo` or `author`, so the Discussion permalink is the only auditable record that the handoff happened.
**Unreachability record (T2 only).** Document at least three contact attempts across at least 30 days — an issue on the upstream repo, a comment on the entry's Discussion, and one more public channel — each dated and linkable. Paste these into the T2 PR body.
## Step 3 — Snapshot the inherited contract
These fields are the user-visible contract. A takeover **preserves** them. If you intend to change them, do that afterward as a normal version bump under your own maintainership — never inside the ownership-change PR.
**Feature Capability** — `interactions.loopExtensionPoints` (which of the 12 Loop Extension Points it registers on), `hookKinds`, `configKeys`, `requires`, `runtimeCompat`, `produces`, `consumes`; plus the manifest's `skills` and `agents` stems, which must stay unique across the merged first-party and overlay set.
**Reviewer lane** — `interactions.slug`, `flags`, `transport`, `evidenceClass`, `reviewsSection`, `requiresBinaries`, `configKeys`. The `slug`, `flags`, and `reviewsSection` must remain unique across the merged first-party and overlay set; a collision breaks `/gsd-review` for anyone running both lanes.
**EoS host integration** — `protocolVersion`, `interactions.interfacePoints` (the subset of `command`, `dispatch`, `model`, `hooks`, `state`, `artifact` it binds), `interactions.profile`, and all eight required axes: `embeddingMode`, `commandSurface`, `dispatch`, `modelMode`, `hookBus`, `stateIO`, `transport`, `runtime` — plus `effortSurface` if the entry already carries it.
## Step 4 — Work the continuity checklist
Each item below breaks an existing install if you get it wrong.
- **Keep the `id`.** Consent is stored per `(realpath(projectRoot), capability id)`. Changing the `id` re-prompts consent in every project that has the capability installed, and orphans the old `gsd capability update <id>` path.
- **Re-state `integrity`.** The `sha512-<base64>` hash is computed over the published artifact. A rebuild under new ownership produces a new hash, and anyone who pinned with `--integrity` will fail verification until you publish and communicate the new value.
- **Re-state `provenance`.** `sourceRepo` and `commit` must point at the new repository and the exact commit you published.
- **Re-consent on executable-surface change.** If the set of hooks, MCP servers, or command modules changes, installers are re-prompted. Keep it identical through the takeover so the handoff itself is not a consent event.
- **Do not narrow `engines.gsd`.** If you raise the floor, add the corresponding `compatVersions` row so older GSD versions can still resolve a working version.
- **Make `install` and `uninstall` copy-pasteable against the new repo.** They are exact commands, not descriptions, for capability and reviewer entries.
- **Do not drop `protocolVersion`** on an EoS entry. It must stay an integer of 1 or greater and must still name the ADR-1239 protocol the integration actually implements.
## Step 5 — Execute the mode
All registry work follows the standard submission process: fork, edit exactly one JSON object, run `npm run gen:registry`, commit **both** the JSON source and the regenerated markdown, and open one PR from a `docs/<issue#>-<slug>` branch using the registry-entry PR template. Never hand-edit the generated `.md` — the `gen:registry --check` drift gate rejects it. **One entry, one PR**, always.
### T1 — Consensual handoff
1. Change only `repo`, `author`, `install`, and `uninstall` — plus `homepage` and `license` if they genuinely changed.
2. Leave `id`, `discussion`, and the entire `interactions` object byte-identical.
3. Put the permalink to the outgoing author's public handoff comment in the PR body. Without it the PR is indistinguishable from an entry hijack and a maintainer should decline it.
4. Run `npm run validate:registry` locally.
5. Add a `.changeset/` fragment typed `Changed`.
### T2 — Adoption fork
1. Fork upstream under your own account, honoring the license.
2. Choose a **new** `id`. The original is permanently taken.
3. Open a new Discussion in the `EoS Registry` category — which, despite its name, carries threads for all three registries. The `discussion` field is required, so the thread must exist before the PR.
4. State in `description` that this is a maintained fork of the original id, and link it.
5. Leave the original entry completely untouched. Its install command keeps resolving to the original repo forever; that is the intended behavior, not a bug to route around.
6. Add a `.changeset/` fragment typed `Added`.
### T3 — First-party absorption
Absorption is a feature-scale change, so the contribution rules apply before any code: an issue carrying `approved-feature`, and an ADR recording the decision.
1. Land the capability as `capabilities/<id>/capability.json` per ADR-894, with `role`, `tier`, and a `requires` list that is acyclic and tier-monotone. Declare `runtimeCompat`.
2. Reserved prefixes are now available to you, and first-party wins every collision — id, skill and agent stems, config keys, command families.
3. Regenerate the capability registry with `scripts/gen-capability-registry.cjs --write`.
4. Update `CONTEXT.md` domain terms, `docs/README.md`, and the surface docs the capability touches.
5. **Do not delete the registry entry.** Absorption is not one of the four removal grounds. Note the supersession in `description` through a separate `Changed` PR.
6. **Publish a migration note telling existing users to run `gsd capability remove <old-id>` first.** Config keys are exclusive to one capability and skill/agent stems must be unique; a first-party capability that collides with an installed overlay wins silently, leaving the user running code they did not think they were running.
### T4 — Retirement
1. Cite exactly one of the four grounds — illegal, malware, spam, or dead/non-functional link — and put the evidence in the PR body.
2. Remove the single object, regenerate, and commit both files.
3. Add a `.changeset/` fragment typed `Removed`.
Staleness, low quality, an unmaintained-but-working project, or a design you would have built differently are **not** grounds. If that is your situation, the mode is T2.
## Step 6 — Post-takeover obligations
- **Cut a GitHub Release under the new repo.** There is no re-registration on new versions: the shields badge and the `releases/latest` permalink render live from `repo`, so releases are the update channel forever. A takeover with no release leaves consumers with a badge that never moves.
- **Bump `version`** in the manifest, and add a `compatVersions` row if you raised the `engines.gsd` floor.
- **Publish the new `integrity` hash and `provenance` object.**
- **Keep the Discussion thread.** It is the continuity record across maintainers, and it carries the community's upvotes and experience reports.
## What a takeover must not do
- Change `interactions` in the same PR as the ownership change. Split them.
- Repoint `repo` at a fork while the original is alive and maintained. That is an entry hijack, not a takeover.
- Reclaim an `id` that is still listed.
- Remove a working entry in order to make room for a replacement.
- Rename into `gsd-`, `gsd-core-`, or `anthropic-` outside of T3.
- Bundle the change with any other registry entry, code change, or unrelated docs edit.
## Known gaps in the enforcement path
Two parts of this process rest on human judgment rather than an automated gate. Both are worth knowing before you rely on the process.
1. **Entry-update authorship is unverified.** `scripts/registry-schema.cjs` and `npm run validate:registry` check the shape of an entry, not who is changing it. A PR that repoints `repo` and `author` at an unrelated account passes every automated gate. The reviewing maintainer is the only control, which is why the public handoff permalink in Step 5 is mandatory rather than advisory.
2. **There is no `id` migration path.** With no transfer or rename tooling, `id` continuity is manual, and an `id` change is a hard break for every installed consumer — a consent re-prompt, a broken update path, and an orphaned ledger entry.
## Related
- [Develop a Capability for GSD 1.5+](develop-a-capability.md)
- [How to publish a capability so others can install it](publish-a-capability.md)
- [Version a capability](version-a-capability.md)
- [Remove a capability](remove-a-capability.md)
- [GSD Registries: schema and submission process](../registries/README.md)