ADR-1244 Phase 4 (D5 trust + D6 upgrade/compat). capability-trust.cjs (disclosure/consent, strict_known_registries, engines+compatVersions, reserved namespace) + capability-lifecycle.cjs (install/upgrade/remove/reconcile; ledger-as-commit-point _pending intent; atomic stage-then-swap; surgical marker-isolated shared-edit strip; owner-token lock) + capability-source promote/skipEnginesGate seams + loader pending-skip + config keys. No sandbox re-derived (consent+integrity+reversibility). 6 Codex adversarial rounds + /security-review (no HIGH) + /code-review; gsd-test green both platforms; CI green. Phase 5 (#1434) wires the CLI dispatch. Closes #1433. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.3 KiB
How to version and upgrade a capability
This guide covers two separate journeys: how a capability author keeps their manifest correctly versioned as GSD evolves, and how a capability consumer safely applies updates. Read only the section that matches your role; each stands alone.
If you author a capability
Choose a version number
Every capability.json must carry a version field expressed as a semver string. GSD rejects a capability manifest that omits it.
Use the standard semver conventions:
| Kind of change | Version bump | Examples |
|---|---|---|
| Backwards-compatible bug fixes or minor prompt improvements | patch (0.0.x) | Fix a typo in an agent instruction; tighten a hook condition. |
| New loop-extension hook, new skill, or new config key — existing consumers unaffected | minor (0.x.0) | Add a verify:post gate; add a new optional config key. |
Breaking change to the hook contract, removal of a skill or config key, change of id |
major (x.0.0) | Rename a hook extension point; remove a skill consumers depend on. |
Set the version in your manifest before every release:
{
"id": "my-deploy-gate",
"version": "1.2.0",
"engines": { "gsd": ">=1.6.0 <3.0.0" }
}
First-party capabilities are versioned automatically. The native capabilities shipped inside GSD (
capabilities/<id>/capability.json) are stamped in lockstep with the GSD package version at release time byscripts/sync-manifest-versions.cjs— theirversionalways equals the GSD version, so per-capability semver andcompatVersionsonly carry independent signal for third-party capabilities. As an author of a third-party capability, you own your own version line; the lockstep rule does not apply to you.
Decide when to raise engines.gsd
The engines.gsd range expresses which GSD host versions your capability is compatible with. GSD enforces this as a hard gate at install time and again at load time.
Raise the lower bound when you start using a GSD feature introduced in a specific release — for example, a loop extension point added in 1.7.0, a new manifest field, or a config federation key that does not exist in older GSD builds. Do not raise it pre-emptively; only raise it when the capability genuinely requires the newer behaviour.
When you do raise the lower bound:
- Bump
version(at minimum a minor bump, or a major bump if the change is otherwise breaking). - Update
engines.gsdto reflect the new minimum. - Add a
compatVersionsentry (see below).
Maintain compatVersions
compatVersions is a capability-version → GSD-version-range table that lets GSD offer older consumers a downgrade instead of a hard block. Each value is a semver range (the same grammar as engines.gsd), evaluated against the running GSD version:
{
"version": "2.0.0",
"engines": { "gsd": ">=1.7.0 <3.0.0" },
"compatVersions": {
"1.2.0": ">=1.6.0 <1.7.0"
}
}
This entry tells GSD: "version 1.2.0 of this capability is compatible with GSD versions >=1.6.0 <1.7.0." When a consumer's GSD is older than the current engines.gsd floor (1.7.0), GSD consults compatVersions, picks the newest capability version whose range the host satisfies, and offers that instead of failing outright.
Add a new entry only when you change engines.gsd — that is the only moment an older GSD version and a specific capability version become correlated. A compatVersions entry is not meaningful for a capability distributed as a bare tarball URL (a tarball exposes a single version and cannot be auto-selected from a table); it is only actionable for sources that enumerate versions: git tags, a registry, or npm.
Publish a new version
How consumers receive the update depends on your distribution channel.
Git tag. Commit the updated capability.json (with the new version field), then push a tag whose name matches the version:
git tag v1.2.0
git push origin v1.2.0
GSD's git adapter fetches tags to determine what is available. Without a matching tag, the new version is invisible to gsd capability outdated.
npm. Publish normally. GSD uses dist-tags to check for updates, so the standard npm publish flow is sufficient:
npm version 1.2.0
npm publish
New tarball. Upload the new archive at a URL and communicate the URL to consumers. GSD cannot auto-detect updates for tarball sources — consumers must run gsd capability update <id> <new-url> manually after you announce the new URL. If you anticipate frequent updates, consider switching to a git or npm source.
If you consume a capability
Check for available updates
Run:
gsd capability outdated
GSD contacts the source of each installed capability and reports which ones have a newer version available. Whether an update is detectable depends on the source:
| Source | Auto-detectable? |
|---|---|
| Git (tags / manifest) | Yes — GSD fetches available tags. |
| Registry | Yes — GSD queries the catalogue. |
| npm | Yes — GSD checks dist-tags. |
| Tarball URL | No — a tarball exposes one version; updates must be applied manually when the author announces a new URL. |
If a capability is installed from a tarball and the author publishes a new version at a different URL, you will need to run gsd capability update <id> <new-url> yourself once the author communicates the new address.
Apply an update
To update a specific capability:
gsd capability update <id>
To update all installed capabilities at once:
gsd capability update --all
Updates are atomic: GSD fully fetches and validates the new version before swapping it in. The ledger write is the commit point. If GSD stops mid-update (for example, due to a network failure), the next command run will detect the orphaned state via a reconciliation sweep and restore a consistent install — you will never be left with a half-updated capability.
Consent when the executable surface changes
If the new version adds or removes hooks, MCP server entries, or command modules compared to the version you have installed, GSD will pause and present a summary of the changes before proceeding. You must confirm explicitly; declining leaves the current version in place.
This re-prompt applies even if you previously consented to auto-update. The consent mechanism is scoped to the declared executable surface of a specific version, so a changed surface is always a fresh decision.
Auto-update is off by default for third-party capabilities. If you enable it, the re-prompt on executable-surface change still applies.
When engines.gsd no longer matches
If the new version of a capability requires a GSD version newer than what you have installed, GSD will tell you clearly and — where the source enumerates versions — offer the newest compatVersions-compatible version instead. If no compatible version is available, or the source is a bare tarball, you will need to either upgrade GSD or stay on your current capability version.