# CommandKit release procedure ## Scope and release order CommandKit publishes source-only Go module releases. Each module has an independent version and immutable annotated tag. A successful source-tag push completes the source release. A separate local delivery command can publish a Gitea release page; there are no binaries, checksums, or other delivery assets. CI, module proxy availability, and consumer installation are not completion gates. Publish in dependency order: core, then `ckconfig`, then `ckprompt`. The integration modules require the preceding CommandKit releases, so prepare and publish each module only after its CommandKit dependencies are available. A root release runs only the root module's default suite; it need not run suites for independently released integrations. Use branch `main`, remote `origin`, and expected effective push endpoint `ssh://git@forge.maximumdirect.net:22222/base-layer/commandkit.git`. The selected module profile enforces the endpoint. The maintainer needs the selected [release toolchain](#release-toolchain), Git push access, and a POSIX shell. This procedure follows the [release policy](policy/release.md); release-note footers follow the [OSS discoverability policy](policy/oss.md#discoverability). ReleaseKit v0.9.0 (`go.maximumdirect.net/releasekit`) owns candidate validation, publication guards, tag creation, tag publication, and outcome reporting. Its pinned public contracts are the [CLI reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/cli.md), [profile reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/config.md), the [publication guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/publish.md), and the [delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/delivery.md). The repository selects one default module suite per invocation. The launcher uses the root module’s registered tool with native host settings and read-only module metadata. ## Release toolchain The selected release toolchain is **Go 1.26.8**. Each module declares a consumer minimum of **Go 1.26.0**. Maintainers use Go 1.26.8 for dependency preparation, candidate validation, and ReleaseKit execution. The [consumer guide](consumers/guide.md#go-compatibility) and [release policy](policy/release.md#consumer-minimum-and-release-toolchain) describe these selections. Select Go 1.26.8 on `PATH`; the launcher uses `GOTOOLCHAIN=local`. If needed, install it with the standard Go tools: ```sh GOWORK=off GOTOOLCHAIN=local go install golang.org/dl/go1.26.8@latest go1.26.8 download export PATH="$(go1.26.8 env GOROOT)/bin:$PATH" hash -r GOWORK=off GOTOOLCHAIN=local go version ``` ## Modules, versions, notes, and shared files Select exactly one module with the launcher: | Selector | Physical module directory | Release note | Full tag | | --- | --- | --- | --- | | `core` | repository root | `docs/releases/.md` | `` | | `ckconfig` | `integrations/ckconfig` | `integrations/ckconfig/docs/releases/.md` | `integrations/ckconfig/` | | `ckprompt` | `integrations/ckprompt` | `integrations/ckprompt/docs/releases/.md` | `integrations/ckprompt/` | Use a fresh stable semantic version (`vMAJOR.MINOR.PATCH`) for the selected module. Before `v1.0.0`, a minor release may change a documented contract when its note explains the impact and consumer action. Never reuse a published version. Each release note starts with a product title and exact version, gives a proportionate summary and compatibility guidance, and ends with immutable links to that module's local grant, license, and attribution paths. The full tag in each URL includes the integration directory where applicable. For future notes, use `https://forge.maximumdirect.net/base-layer/commandkit/src/tag/FULL_TAG/` followed by the repository-relative path: `COPYRIGHT`, `LICENSE`, and `docs/oss/attribution.md` for core, or those paths prefixed with the selected integration directory. Future tag URLs need not resolve before publication. All three release profiles explicitly select the repository-root `COPYRIGHT`, `LICENSE`, and `docs/oss/attribution.md` through `validation.shared_files`. ReleaseKit requires these committed files to exist in the candidate. The list does not expand Go validation scope; see the pinned [profile reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/config.md). Each integration also distributes its own `COPYRIGHT`, `LICENSE`, and `docs/oss/attribution.md`. These module-local materials are separate from the explicit root shared-file list and remain subject to the [OSS policy](policy/oss.md). Automatic module file inputs include applicable module-local files and stop at independent nested-module boundaries. Their inclusion does not itself enable license or content validation. Each profile selects Go formatting, Markdown links, workspace-file and local replacement checks, and forbids the committed `.releasekit/gitea-token` path. These upstream checks inspect committed inputs; module file selection stops at independent module boundaries, while the forbidden path covers the repository. They do not replace domain review. Publication also runs the selected module’s standard offline suite and ReleaseKit’s candidate/note and publication guards. ## Prepare and publish one candidate Prepare dependencies in the selected module before the candidate is finalized. Do this after the preceding CommandKit module has been published and before the selected candidate suite is run. For `core`, run the command at the repository root; for integrations, run it from that module directory. Commit any resulting `go.mod` or `go.sum` changes with the release candidate. The sum files must reflect dependencies actually downloaded for that module; do not fabricate future sums. Then commit the selected module's release note and all intended candidate changes on `main`, and publish the candidate commit to `origin`. Set one module directory and version from the table above, then run the corresponding publication command: ```sh module_dir=. (cd "$module_dir" && GOWORK=off GOTOOLCHAIN=local go mod download) # Commit reviewed dependency changes and the selected module's note on main. git push origin HEAD:refs/heads/main ./scripts/release core vX.Y.Z # For integrations use: ./scripts/release ckconfig vX.Y.Z # or: ./scripts/release ckprompt vX.Y.Z ``` Run only the command for the selected module. Its profile runs the complete offline deterministic default suite once for that module, checks candidate and remote guards, creates the annotated tag from the matching note, and pushes only that full tag. `./scripts/releasekit core check vX.Y.Z` is an optional diagnostic, not a required pre-publication step: publication repeats validation. Use the relevant integration selector and its version when diagnosing that module. Inspect the registered tool with `./scripts/releasekit version`. The launcher does not push `main`; publish the candidate commit first. Successful source publication does not wait for CI, proxy availability, or downstream installation. ## Completion and ambiguous publication A successful push to the expected endpoint completes the source release. ReleaseKit also attempts to save private publication evidence under the repository's Git common directory, shared by linked worktrees. It reports the saved record path or a recording warning separately from publication status; a storage failure does not change publication status. Records can contain credential-bearing endpoints. Retain them privately while recovery is needed and remove them when their recovery value expires; retention is maintainer-owned. On an ambiguous result, use the recovery command printed for that invocation's saved record. To discover records and explicitly select the matching attempt, the shared helper can also be used: ```sh ./scripts/releasekit publication-attempts ./scripts/releasekit reconcile --record /absolute/path/to/attempt.json ``` Replace the example record path with the saved path for the intended attempt. Relative record paths resolve from the repository root. Discovery lists local evidence without querying remotes or selecting an attempt. Reconciliation observes the recorded endpoint, full tag, and tag object without rerunning candidate validation or changing tags. It distinguishes confirmed publication, current absence, conflict, and an unresolved observation. Current absence does not prove that a version was never published. The pinned [CLI reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/cli.md#recover-a-saved-publication-attempt-or-discover-local-attempts) owns recovery statuses and structured output; the [publication guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/publish.md#retain-and-reconcile-publication-evidence) describes record storage and recovery entry points. If no usable record was saved, use the exact endpoint, full tag, and annotated tag object reported by that invocation. Query only that exact tag ref at the captured endpoint. An exact tag-object match confirms publication, a different object is a conflict, successful output without the ref shows current absence, and a failed query leaves the result unresolved. Do not infer the captured endpoint's state from another remote or a rewritten URL. Resolve unknown publication state before retrying. ReleaseKit may retain a local tag after a failed push. Remove an unpublished local tag only after proving absence at the captured endpoint and confirming that the tag was never published or used by another release channel. Never move, overwrite, recreate, or delete a published tag. Resolve conflicts with a fresh version; corrections to published source require a new version. ## Hosted delivery After source publication, check out the original tagged source with a clean worktree and index, then deliver the selected module's page: ```sh ./scripts/releasekit core deliver vX.Y.Z # Or use ckconfig or ckprompt with that module's semantic version. ``` The profile derives the full module-specific tag from the version. Delivery uses the checked-in release note as a page-only body and reports its own outcome and URL separately from source publication. Retry later from the same original tagged source. The pinned [delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/delivery.md) owns delivery and retry behavior. A nonblank `RELEASEKIT_GITEA_TOKEN` takes precedence over the repository-relative `.releasekit/gitea-token` file. Keep the credential directory ignored and retain its local contents. Credentials and Gitea availability do not gate source publication.