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:
11
.changeset/2999-capability-eos-takeover-process.md
Normal file
11
.changeset/2999-capability-eos-takeover-process.md
Normal 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)
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
@@ -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
|
||||
|
||||
141
docs/how-to/take-over-a-capability-or-eos.md
Normal file
141
docs/how-to/take-over-a-capability-or-eos.md
Normal 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)
|
||||
Reference in New Issue
Block a user