From 49793465d707d1f08d54841a14834a202a1e8bdc Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Fri, 31 Jul 2026 09:29:51 -0400 Subject: [PATCH] docs(#2915): how-to for listing a reviewer lane, and correct the stale listing section (#2917) * docs(#2904): how-to for listing a reviewer lane in the registry #2912 shipped the Reviewer Lane Registry, which lands in 1.9.1. Two docs consequences. New: docs/how-to/list-your-reviewer-lane.md. A Diataxis how-to for the publish task -- which of the three catalogs applies (and why a runtime carrying a reviewer body lists under its primary install shape instead), opening the required discussion thread BEFORE the PR, the three fields that reject entries most often (slug grammar differs from id, flags stay kebab when the slug is snake, install/uninstall must be copy-pasteable), regenerate-don't-hand-edit, and register-once-then-Releases. Links the registry README for the field table rather than duplicating it -- the spec is reference, this is the task flow. Corrected: ship-a-reviewer-lane.md said "Listing your lane is not wired yet" and pointed at #2904 as future work. #2906 merged at 11:25Z and #2912 at 12:11Z, so that section shipped false the moment the registry landed. Replaced with the publish pointer. Indexed the new guide and the generated catalog in docs/README.md, and added the guide to develop-a-capability.md's ecosystem list. Co-Authored-By: Claude Opus 5 (1M context) * docs(#2904): caveat credential-bearing configKeys in both the guide and the spec Isolated security review found the worked entry's `configKeys: ["acme.api_key"]` modelled storing a live credential with no note on where that value ends up. Verified: config values are written in plaintext to .planning/config.json (docs/CONFIGURATION.md:227 -- masking is display-only, "that file is the security boundary"), and planning.commit_docs defaults to true (:466). So a credential declared that way lands in the installing user's git repository unless they have gitignored .planning/. None of the twelve first-party lanes does this -- they own only review.models.*, host, and prompt-budget keys. The pattern originates in docs/registries/README.md:221, shipped by #2912, so the caveat goes on BOTH surfaces rather than only on the copy that inherited it -- the spec's example is what future authors will read first. Co-Authored-By: Claude Opus 5 (1M context) * chore(#2915): backfill changeset PR number pr: 0 -> 2917. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: sim Co-authored-by: Claude Opus 5 (1M context) --- .changeset/vivid-eagles-forage.md | 5 ++ docs/README.md | 2 + docs/how-to/develop-a-capability.md | 1 + docs/how-to/list-your-reviewer-lane.md | 114 +++++++++++++++++++++++++ docs/how-to/ship-a-reviewer-lane.md | 8 +- docs/registries/README.md | 2 + 6 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 .changeset/vivid-eagles-forage.md create mode 100644 docs/how-to/list-your-reviewer-lane.md diff --git a/.changeset/vivid-eagles-forage.md b/.changeset/vivid-eagles-forage.md new file mode 100644 index 000000000..87e403865 --- /dev/null +++ b/.changeset/vivid-eagles-forage.md @@ -0,0 +1,5 @@ +--- +type: Added +pr: 2917 +--- +**Reviewer lanes can now be listed for discovery** — a new how-to walks lane authors through publishing to the Reviewer Lane Registry: which of the three catalogs applies, opening the required discussion thread first, the fields that reject entries most often, and why registering once means GitHub Releases become the update channel. (#2904) diff --git a/docs/README.md b/docs/README.md index 08a22c305..76aa7f4f3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,6 +37,7 @@ Language versions: [English](README.md) · [Português (pt-BR)](pt-BR/README.md) - [Design a UI phase](how-to/design-a-ui-phase.md) — use the UI phase loop for frontend and visual work - [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 - [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 @@ -63,6 +64,7 @@ Language versions: [English](README.md) · [Português (pt-BR)](pt-BR/README.md) - [Capability matrix](reference/capability-matrix.md) — generated catalogue of every capability's role, tier, extension points, hook kinds, and `engines.gsd` - [Capability manifest](reference/capability-manifest.md) — the full `capability.json` schema and validation rules - [`gsd capability` command](reference/gsd-capability-command.md) — install / update / remove / list reference for third-party capabilities +- [Reviewer Lane Registry](registries/reviewer-registry.md) — generated catalogue of third-party reviewer lanes, with their flags, transport, and install commands --- diff --git a/docs/how-to/develop-a-capability.md b/docs/how-to/develop-a-capability.md index 38cae6abe..5d374956f 100644 --- a/docs/how-to/develop-a-capability.md +++ b/docs/how-to/develop-a-capability.md @@ -246,6 +246,7 @@ From GSD 1.6.0, capabilities are versioned (the `version` field is required in ` - **How-to** — [Version and update a capability](../how-to/version-a-capability.md): manage `version`, `engines.gsd`, and `compatVersions`; use `gsd capability update`. - **How-to** — [Remove a capability](../how-to/remove-a-capability.md): uninstall cleanly with `gsd capability remove`, including the `--purge-data` option. - **How-to** — [Ship a reviewer lane in your capability](../how-to/ship-a-reviewer-lane.md): declare a `reviewer` body (GSD 1.9.0+) so `/gsd-review` discovers and invokes your external review CLI or model endpoint. +- **How-to** — [List your reviewer lane in the registry](../how-to/list-your-reviewer-lane.md): publish a lane to the Reviewer Lane Registry (GSD 1.9.1+) so other people can find and install it. - **Reference** — [Capability manifest](../reference/capability-manifest.md): all fields and validation rules for `capability.json`. - **Reference** — [Capability matrix](../reference/capability-matrix.md): which first-party capabilities exist, their extension points, and their compatibility matrix. - **Explanation** — [Capability trust model](../explanation/capability-trust-model.md): how declarative and executable capabilities are treated differently at install time. diff --git a/docs/how-to/list-your-reviewer-lane.md b/docs/how-to/list-your-reviewer-lane.md new file mode 100644 index 000000000..0526570d8 --- /dev/null +++ b/docs/how-to/list-your-reviewer-lane.md @@ -0,0 +1,114 @@ +# How to list your reviewer lane in the registry + +**Goal:** Get a reviewer lane you have built into the **Reviewer Lane Registry**, so other people can find it, install it, and give you feedback. + +**Prerequisites:** A working lane in a public repository, with a tagged release. If you have not built one yet, start with [Ship a reviewer lane in your capability](ship-a-reviewer-lane.md). GSD 1.9.1 or later. + +Listing is a documentation PR against `gsd-core`. There is no separate account, package publish, or approval queue — you append one JSON object, regenerate a catalog, and open a PR. + +--- + +## Check you are aiming at the right catalog + +GSD has three discoverability catalogs, and picking the wrong one costs you a review round-trip. Pick by what your capability *is*, not by what it does: + +| Your capability | Catalog | Source file | +|---|---|---| +| A lane and nothing else — `role: "reviewer"`, GSD never installs into it | **Reviewer Lane Registry** | `docs/registries/reviewers.json` | +| A runtime GSD installs into, that *also* carries a `reviewer` body | Whichever matches its **primary install shape** — usually the Capability or EoS registry | `capabilities.json` / `eos.json` | +| A feature capability attaching at Loop Extension Points | Community Capability Registry | `docs/registries/capabilities.json` | + +The Reviewer Lane Registry exists specifically for lanes that are **not install targets in their own right**. If your capability is a host integration that happens to review as well, it belongs under its primary shape — do not list it twice. + +--- + +## Open the discussion thread first + +The `discussion` field is **required**, so the thread has to exist before you open the PR. Doing this second is the most common way to get sent back. + +Start an open-ended discussion in the **EoS Registry** category. Despite the name, that category carries threads for all three catalogs. One thread per entry; it is where upvotes, experience reports, and your follow-up live. + +Keep the URL — it goes straight into the entry. + +--- + +## Write your entry + +Append **exactly one** object to `docs/registries/reviewers.json`: + +```json +{ + "id": "acme-review-lane", + "name": "Acme Review Lane", + "type": "reviewer", + "repo": "some-org/gsd-lane-acme", + "description": "Adds an Acme-hosted model as an external reviewer lane for /gsd-review, evaluating diffs against Acme's static-analysis findings.", + "author": "Some Org ", + "license": "MIT", + "enginesGsd": ">=1.9.1", + "install": "gsd capability install https://github.com/some-org/gsd-lane-acme.git#v1.0.0", + "uninstall": "gsd capability remove acme-review-lane", + "interactions": { + "slug": "acme", + "flags": ["--acme"], + "transport": "openai-http", + "evidenceClass": "diff-only", + "reviewsSection": "## Acme Review", + "requiresBinaries": [], + "configKeys": ["acme.api_key"], + "runtimeCompat": ["all"] + }, + "discussion": "https://github.com/open-gsd/gsd-core/discussions/1236" +} +``` + +Three fields reject entries more often than the rest, so check them before anything else: + +- **`interactions.slug`** must equal your manifest's `reviewer.slug` and follows the *lane* grammar `^[a-z0-9][a-z0-9_-]*$` — underscores and a leading digit are allowed (`lm_studio`, `4o-mini`). This is **not** the same grammar as the top-level `id`, which is kebab-only. +- **`interactions.flags`** are kebab even when the slug is snake: `lm_studio` → `--lm-studio`. Each must match `^--[a-z0-9][a-z0-9-]*$`. +- **`install`** and **`uninstall`** must be exact and copy-pasteable. Someone will paste them verbatim; a placeholder that does not run is the one thing a directory cannot tolerate. + +**If a `configKeys` entry holds a live credential, say so in your README.** The example above declares `acme.api_key` to show the shape, and that shape has a consequence worth understanding before you copy it. Config values are written **in plaintext** to `.planning/config.json` — masking applies to display only, and that file is the security boundary. `planning.commit_docs` defaults to `true`, so unless the installing user has gitignored `.planning/`, a credential stored that way lands in their repository. None of the twelve first-party lanes stores a credential this way; they own only `review.models.*`, host, and prompt-budget keys. If your lane genuinely needs a secret, document the exposure for your users rather than leaving them to discover it — and never invent your own storage side-channel to route around it. + +Everything else follows the shared entry shape. For the complete field-by-field table, see the [registry specification](../registries/README.md#reviewer-entries-reviewersjson-type-reviewer). + +--- + +## Regenerate the catalog + +Never hand-edit `docs/registries/reviewer-registry.md` — it is generated, and a drift gate will fail your PR: + +```bash +npm run gen:registry +``` + +Commit **both** the JSON source and the regenerated markdown. + +--- + +## Open the PR + +Branch as `docs/-`, and use the [registry-entry PR template](../../.github/PULL_REQUEST_TEMPLATE/registry-entry.md). + +**One entry, one PR.** Do not bundle additions, updates, or removals together. + +A maintainer checks one thing: whether the entry is a real, linkable solution with every required field present. It is not a quality review — inclusion is explicitly [not an endorsement](../registries/README.md#non-endorsement-stance), and entries are removed only for illegal content, malware, spam, or a dead link. Nobody will reject your lane for design decisions they would have made differently. + +--- + +## Ship new versions without touching the registry + +**Register once.** Your GitHub Releases are the update channel from then on. + +Each entry embeds a live shields.io badge and a permalink to your repository's latest release, rendered directly by GitHub's markdown viewer. Cutting `v1.1.0` updates what visitors see with no follow-up PR. + +The one thing worth revisiting is `enginesGsd` — if a later version of your lane starts depending on a newer GSD, update that range so the catalog does not advertise compatibility you no longer support. + +--- + +## Related + +- [Ship a reviewer lane in your capability](ship-a-reviewer-lane.md) — build the lane you are listing +- [Registry specification](../registries/README.md) — the full entry schema, non-endorsement stance, and removal policy +- [Reviewer Lane Registry](../registries/reviewer-registry.md) — the generated catalog itself +- [Publish a capability](publish-a-capability.md) — versioning, `engines.gsd`, and distribution diff --git a/docs/how-to/ship-a-reviewer-lane.md b/docs/how-to/ship-a-reviewer-lane.md index a874449db..335658e67 100644 --- a/docs/how-to/ship-a-reviewer-lane.md +++ b/docs/how-to/ship-a-reviewer-lane.md @@ -160,13 +160,13 @@ Two naming rules are easy to conflate, so keep them apart. Your `slug` may not b An *unknown* field inside your `reviewer` body behaves differently: it is a non-fatal warning on stderr, never a build failure. A manifest built against a newer GSD degrades visibly instead of crashing. -### Listing your lane is not wired yet +### Publish it so people can find it -You can build, install, and run a third-party lane today. You cannot yet **list** it in a discoverability catalog, and it is better to know that before you write the entry than after. +From GSD 1.9.1, a lane has its own discoverability catalog: the [Reviewer Lane Registry](../registries/reviewer-registry.md). Listing is a documentation PR — append one entry to `docs/registries/reviewers.json`, regenerate, open a PR. Register once; your GitHub Releases are the update channel from then on. -Neither existing registry accepts a lane. A [Community Capability Registry](../registries/capability-registry.md) entry requires a non-empty `loopExtensionPoints` and a `hookKinds` value, and a lane registers on zero loop extension points by design — the two fields are unsatisfiable rather than merely unset. The [EoS Registry](../registries/eos-registry.md) is for host integrations that embed the orchestration engine through the ADR-1239 interface, which a reviewer lane does not do. +Follow [List your reviewer lane in the registry](list-your-reviewer-lane.md) for the task flow. -Do not work around this by filing a loop extension point your lane does not use. A third `reviewer` entry type is tracked by [#2904](https://github.com/open-gsd/gsd-core/issues/2904) for a 1.9.x point release; until it lands, distribute your lane by URL and it will install and run normally. +The Reviewer Lane Registry is for lanes that are **not install targets in their own right**. If your `reviewer` body rides on a `role: "runtime"` capability, list that capability under whichever catalog matches its primary install shape instead — one entry, not two. --- diff --git a/docs/registries/README.md b/docs/registries/README.md index bdf650244..de0118bdd 100644 --- a/docs/registries/README.md +++ b/docs/registries/README.md @@ -197,6 +197,8 @@ Example: | `configKeys` | yes | Federated config keys it owns (may be empty). | | `runtimeCompat` | yes | Array of compatible runtimes; `["all"]` is allowed. | +> **Credential-bearing `configKeys` carry an exposure the example below does not show.** Config values are written in plaintext to `.planning/config.json` — masking is display-only, and that file is the security boundary — while `planning.commit_docs` defaults to `true`. A key holding a live credential therefore lands in the installing user's repository unless they have gitignored `.planning/`. No first-party reviewer lane stores a credential this way. If yours must, document the exposure in your own README. + Example: ```json