Development record
installable-versioned-plugin
Summary
spc-11 delivers itd-67 in two slices that meet at the release cut:
- The changelog slice — the
abcd launch shipwrite-verb, the host-delegated composer that writes the release prose, the completeness bijection that makes that prose faithful by construction, and the read-onlyabcd changelogpreview. - The distribution slice — the derived version rendered into
plugin.json/marketplace.jsonin the release payload only, the documented install and update path, and a light installability smoke.
The version number itself comes from spc-10 (itd-73); spc-11 consumes it. The
programme plan is
.abcd/development/plans/2026-07-21-derived-version-and-changelog.md; its
Outcomes section is authoritative where it touches anything below.
Scope
Changelog slice
abcd launch ship— the write-verb, which does not exist today:launchis dry-run-only andShip()stops atWouldPublish. Mirroringdisembark, it is a host-orchestrated flow over two Go entry points, not one linear call:- emit — the deterministic record set, the derived version, and the guardrail result;
- the host runs the composer agent;
- ingest (
--changelog-json) — run the bijection, then write the dated heading and render the release-payload manifest version.
- Two fail-closed refusals, wired into the emit step:
- A new release-changelog composer agent, distinctly named (the
CHANGELOGandREADMEagent slots are occupied by two documents the plugin loader mis-registers as agents — iss-110). Modelled onpress-release-composer/principle-distiller: host-delegated per ADR-25, cite-or-be-dropped, an injection-canary fixture, and aprompt_versionper itd-5. - The completeness bijection — the set of record ids cited by the composer
must equal the required set minus every
internalrecord: no omission, no invention. A mismatch loud-stages and refuses; nothing partial is ever written. The agent controls wording and the Keep-a-Changelog section only; the version and the inclusion set are deterministic. abcd changelog(bare) — the deterministic-only preview: next version, the decidingimpact, the record list, and the guardrail status. No agent, no prose, no writes. Prose is generated exactly once, at the reviewed ship.
Distribution slice
versionrendered intoplugin.jsonandmarketplace.jsonin the release payload only. The dev tree stays version-absent (ADR-19); the existinglaunch/lockstep.gorelease-mode contract enforces the pair.- The install and update path in the README —
/plugin marketplace add <personal account>/abcd→/plugin install abcd@abcd-marketplace; update with/plugin update abcd. - A light installability smoke —
marketplace.jsonandplugin.jsonparse,sourceresolves, and every declared command/skill/agent/hook path exists. A missing path FAILS.
Approach
The cut stays a reviewed pull request (ADR-37): everything derived lands in
the ship PR, reviewed once, then durable. auto-release.yml and release.yml
are untouched — the generated heading matches the grep they already run, so the
workflow contract is preserved rather than replaced. No bot writes to main.
The prose is the only non-deterministic part of the cut, so it sits outside the
deterministic core and behind a verifier: the Go side computes the exact record
set, the agent writes lines that each cite a record id, and the Go side accepts
the result only if the cited set matches exactly. Faithfulness is structural, not
a matter of trusting the model. The two-entry-point shape exists for the same
reason disembark has it — the host, not the core, is where an agent runs, and a
CI-only context has no model. If the composer is unreachable, the verb loud-stages
and writes nothing.
impact never decides the Keep-a-Changelog section. The bijection guards
id-completeness only; a four-value enum cannot express Security or
Deprecated, so the section is the composer's judgement from record content.
The light smoke resolves the declared surface through the same seam itd-66's deep tier will use, so the deep tier is a drop-in upgrade of the assertion rather than a rewrite of the resolution.
Migration
One clean cutover, not a fold. The maintainer performs a final manual ADR-37 roll
of the current hand-written [Unreleased] block, picking the version. The
derived machinery then starts pristine from the next cut: [Unreleased] is
empty and every subsequent section is fully derived. The current [Unreleased]
mixes shipped issues with a not-yet-shipped intent, so it does not map onto the
derived set and folding it would double-count.
Reconciliations with the intent as written
The intent predates itd-73 and its own resolution of the open questions below; these are recorded as decided, not left open.
- Bump-tier selection. itd-67's "a phase completed since the last launch →
minor" heuristic is superseded by itd-73's
impactderivation (spc-10). The bump falls out of the records' declaredimpact, not out of phase membership. spc-11 consumes the number and never computes one. - Where the changelog lives. A single
CHANGELOG.mdwhose newest dated## [X.Y.Z] - <date>headingauto-release.ymlgreps. Not the marketplace entry, not tag annotations. - Generated, not hand-curated. From the shipped intents and resolved issues, via the composer agent under the bijection — not from the launch report and not from commit-message parsing.
- Seed version. The base is whatever the newest git tag says, read at the cut; there is no fixed seed and no fixed "next after 0.3.0".
- Tagging.
launch shipdoes not tag. It writes the dated heading in the ship PR;auto-release.ymltags on merge. This is ADR-37 preserved, and it is what itd-67's "tags the repo" criterion resolves to in the current architecture. - Refusing an empty cut. Nothing shipped since the tag → no bump, "nothing to release", no heading written. A forced patch re-snapshot is not offered.
- Where the install path is documented. The repo README. Not mirrored into
docs/.
itd-66 is deferred
itd-66 (launch-payload-render-parity) is DEFERRED to a follow-up, after this
programme. itd-67's own acceptance criteria frame its smoke as light … later
upgraded to call itd-66's deep version, so the deferral is a clean split rather
than a blocker. itd-66 owns the materialised payload render, the .abcd/**
leak-proof assertion, symlink resolution, the parity diff against the previous
release, and the isolated-subprocess deep smoke. spc-11 builds the light tier and
positions the surface-resolution seam so itd-66 slots in.
Acceptance-criteria satisfaction
- The marketplace resolves and lists
abcd— the light smoke parsesmarketplace.json, asserts the singleabcdplugin entry, and resolvessource: "./". - Install registers the full
/abcd:*surface — the light smoke asserts every declared command/skill/agent/hook path exists in the payload; a missing path FAILS. Tested in both directions. - A new ship bumps
plugin.json.version, updatesmarketplace.json, and the repo is tagged — the derived version is rendered into both manifests in the release payload under the existing lockstep contract; the tag follows from the dated heading via the unchangedauto-release.yml. - The bump tier and its reason are recorded —
abcd changelogand the emit step both report the next version and the decidingimpact, naming the record that decided it. - An auto-recorded changelog generated from shipped intents and resolved
issues, with a single home — the composer flow above, under the bijection,
writing one
CHANGELOG.md. - The version lives in the manifest and tags, not duplicated across doc bodies — the dev tree carries no version; the sole in-tree carrier is the CHANGELOG dated heading, and the manifest fields exist only in the rendered release payload.
What this spec does not deliver
- The
impactfield, the two lints, the derivation arithmetic, and the surface guardrail — spc-10 (itd-73). - Everything itd-66 owns (see the deferral above).
- Publishing to any registry beyond the git repo and its tag.
- Pre-release channels.
Frontmatter
| id | spc-11 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-11-installable-versioned-plugin.md
open on GitHub ↗ · commit history ↗
References1
- itd-67abcd Is An Installable, Versioned Claude Code Plugin Whose Repo Is Its Own Marketplace And Whose Every Launch Bumps, Tags, And Publishes A New Versionimplements
mentions18
- adr-19The plugin version lives ONLY in the released artifact; the working tree stays unversioned, and the version location is chosen by a schema-validated decision, not hard-coded
- adr-25The LLM is host-delegated by default; oracles are opt-in adapters
- adr-37Releases are changelog-driven — rolling `[Unreleased]` is the release decision, and automation tags exactly that commit
- dcn-26072100000000012026-07-21 — itd-66 (`launch-payload-render-parity`) is DEFERRED to a follow-up
- dcn-26072100000000022026-07-21 — itd-67's "a phase completed since the last launch -> minor" bump
- iss-110agents/CHANGELOG.md and agents/README.md are plain docs (the itd-5 prompt-version log; a readme) but the plugin agent-loader globs agents/*.md, so both are mis-registered as agents (abcd:CHANGELOG, abcd:README appear in the harness agent list). They have no agent frontmatter and are not invokable workers. Fix: either move these docs out of agents/ (e.g. to .abcd/development/ or a docs path) or make the loader skip non-agent files (require agent frontmatter). Surfaced by the derived-changelog plan adversarial review, which had assumed the abcd:CHANGELOG slot was free for a new composer agent.
- iss-115There is no uniqueness lint for spec ids, so two concurrent branches always mint the same spc-N. abcd mints the next free id from the local tree, so any two branches cut from the same base collide silently: the itd-73/itd-67 programme and the itd-95/itd-96 programme both minted spc-10 and spc-11 on 2026-07-21. The collision is invisible on each branch and only appears on merge, where it breaks the bidirectional intent-spec link in BOTH directions at once — 'itd-95 names spc-10, but spc-10 claims itd-73' and 'itd-67 names spc-11, but spc-11 claims itd-96' — because whichever spec wins the store lookup leaves the other intent's link dangling. iss-74 added an issue-id uniqueness lint; specs need the same guard, and record-lint is the natural home so CI catches it on the PR rather than a human catching it at merge. Consider also whether minting should reserve ids in a way concurrent branches cannot duplicate.
- iss-120Sequential record ids are minted from the local tree, so two parallel programmes mint the same next id — both took spc-10, spc-11, iss-110 and iss-111, costing four renumber commits across the episode. This generalises iss-115 (spec ids lack a uniqueness lint): issue and intent ids have armed detectors via the shared validateIDUnique primitive, spec and ADR ids have none, and detection-after-collision is the only mitigation anywhere. The design call is whether detection everywhere is enough or minting itself should be made collision-free (id-range leases per programme, mint-at-merge), which trades away human-readable sequential ids.
- iss-2609230733540527itd-67 ac-4 promises a phase-completion bump tier named in the launch report and a major bump only via an explicit --version <x.0.0>; delivered reality: the tier derives from record impact (internal/core/changelog/version.go), the report names the deciding impact and record and no phase, and the ship verb carries no --version flag at all — spc-11 records the supersession under Reconciliations but the intent's criterion was never amended, and the documented human override for the first 1.0.0 has no verb: the only path is a hand-written CHANGELOG heading. Found by the itd-67 fidelity audit (rcp-7af1556ce4f7).
- itd-5Every Agent Prompt Carries Its Version, Earns Its Lock, And Survives Injection
- itd-47Oracle-Backed Gates Pass Honestly Without A Human In The Loop
- itd-66abcd Renders The Exact Public Payload, Proves The Excludes Never Leak, And Smoke-Tests The Installed Surface Before Any Snapshot
- itd-73abcd Cuts the Version — You Never Type One
- itd-80An Intent Ships Itself: `planned → shipped` Follows Its Spec Closing, With A Fidelity Audit Attached
- itd-2609231013154443Every release arrives with a press release composed from what shipped
- one-writer-per-fileOne writer per file
- spc-10derived-versioning
- spc-2609231435545473The release cut writes RELEASE.md from the press releases of the intents it shipped