Release pipeline setup
Opt-in: koryph never blocks you
The release pipeline is fully optional. If a project has no
release block in koryph.project.json and no .github/workflows/release.yml
caller workflow installed, koryph never creates, touches, or expects release
infrastructure. koryph doctor reports "release not configured" for such
projects (LevelOK — it is a valid, intentional state).
You opt in by running koryph release setup. You opt out by removing (or
never adding) the release block and workflow file.
koryph release setup wires a project's release pipeline by rendering its
managed files from koryph's embedded templates and installing them into your
repository:
| File | Purpose |
|---|---|
.github/workflows/release.yml |
Caller workflow that invokes koryph's reusable release-train.yml |
.github/workflows/container.yml |
Optional GHCR image-release workflow, when release.container is configured |
release-please-config.json |
release-please package configuration |
.release-please-manifest.json |
Initial version manifest (written once, managed by release-please thereafter) |
The generated caller workflow invokes koryph/koryph's reusable .github/workflows/release-train.yml (koryph-0vf.3) via koryph/koryph/.github/workflows/release-train.yml@main. koryph's own release pipeline (.github/workflows/release-please.yml) is the first caller and uses the same-repository local-path form instead (./.github/workflows/release-train.yml) — see docs/developer-guide/releasing.md.
Prerequisites
- A project registered with koryph (
koryph project add). - The project's
koryph.project.jsonmust be loadable (runkoryph validate --project IDto check).
Quickstart
# Goreleaser build mode (mode A — cross-platform binaries via .goreleaser.yaml)
koryph release setup --project myproject --mode goreleaser
# Commands build mode (mode B — custom shell commands stage artifacts)
koryph release setup --project myproject --mode commands
# Specify the initial version (default: 0.0.0)
koryph release setup --project myproject --mode goreleaser --version 0.3.0
# Also provision the release bot GitHub App (requires scripts/provision-release-bot.sh)
koryph release setup --project myproject --mode goreleaser --bot
If the project already has a release block
If koryph.project.json already has a release block, --mode is optional. It overrides the build mode in the existing block if supplied:
# Re-render templates after editing koryph.project.json by hand
koryph release setup --project myproject
# Switch an existing goreleaser project to commands mode
koryph release setup --project myproject --mode commands
Build modes
Mode A — GoReleaser
"release": {
"type": "go",
"extra_files": ["internal/version/version.go"],
"artifacts_dir": "dist",
"build": {
"goreleaser": { "version": "~> v2.16" }
},
"sbom": true,
"provenance": true
}
Requires a .goreleaser.yaml at the repo root. GoReleaser manages cross-platform binary builds, checksums, cosign signing, and per-archive SBOMs. Set sbom: true to enable anchore/sbom-action and provenance: true for SLSA level-3 provenance.
Mode B — Commands
"release": {
"type": "simple",
"artifacts_dir": "dist",
"build": {
"commands": ["make build", "make package"]
}
}
An ordered list of shell commands (each run via sh -c) that build and stage artifacts into artifacts_dir. Use this for non-Go projects or bespoke build systems.
Optional GHCR container release
Add container to either build mode to publish an OCI image alongside the
ordinary release train:
"release": {
"type": "simple",
"build": {
"commands": ["make build"]
},
"container": {
"registry": "ghcr.io",
"image": "acme/widget"
}
}
GitHub Container Registry is the supported registry. image is a
registry-relative OCI image name: do not include ghcr.io, a tag, or a digest.
The generated workflow builds the repository-root Dockerfile, pushes an
immutable digest, promotes only the release's vX.Y.Z tag to that digest, then
signs, SBOMs, and attests the same digest. Only its gated publishing job has
permission to write packages and publish attestations; ensure your organization
permits the repository's GITHUB_TOKEN to create or update its GHCR package.
After adding or changing this block, run koryph release setup to render
.github/workflows/container.yml. koryph doctor --project myproject checks
that the configured workflow and repository-root Dockerfile exist, and that
the workflow has not drifted from the current container-release template. See
Releasing projects for the
full release, verification, and repair contract.
Release block reference (koryph.project.json)
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | yes | release-please release type (go, simple, node, …) |
extra_files |
[]string |
no | Additional files whose version strings release-please bumps |
artifacts_dir |
string | no | Build artifact directory (default: dist) |
build.goreleaser |
object | one of | Mode A: GoReleaser config (version field) |
build.commands |
[]string |
one of | Mode B: ordered shell commands |
sbom |
bool | no | Enable SBOM generation via anchore/sbom-action |
provenance |
bool | no | Enable SLSA provenance via slsa-framework/slsa-github-generator |
container.registry |
string | no | OCI registry; currently must be ghcr.io |
container.image |
string | with container |
Registry-relative OCI image name, without registry, tag, or digest |
Exactly one of build.goreleaser or build.commands must be set. koryph validate enforces this.
Remaining HUMAN steps
After koryph release setup prints "Remaining HUMAN steps:", you need to:
- Provision a GitHub App (release bot): if no release bot app exists, create one and note its App ID and private key. Use
--botto runscripts/provision-release-bot.sh --attachautomatically. - Set repository secrets:
RELEASE_BOT_APP_IDandRELEASE_BOT_PRIVATE_KEY— required by the reusablerelease-train.yml. - Review branch-protection rulesets: add the release bot's GitHub App identity to the "Bypass pull request requirements" list on
main. - Commit and push the generated files to trigger the first release-please run.
- GoReleaser users: verify
.goreleaser.yamlis present at the repo root. - Provenance users: confirm
id-token: writepermission is available in your GitHub org. - Container users: verify a repository-root
Dockerfileand that the repository'sGITHUB_TOKENmay create and write the configured GHCR package.
Bot-less mode (rung 2)
Installing a GitHub App is optional. The caller workflow falls back to
GITHUB_TOKEN when RELEASE_BOT_APP_ID / RELEASE_BOT_PRIVATE_KEY are
absent. Release PRs are opened and updated correctly, but check workflows
do NOT fire on release-please-authored events because GitHub prevents
GITHUB_TOKEN-caused events from triggering workflows (platform rule, not a
koryph limitation).
To trigger checks without a bot, run once per release:
koryph release kick --repo OWNER/REPO
This closes then reopens the Release PR under your gh auth token (a real
actor), which causes GitHub to fire all required check workflows. Add --wait
to poll until checks conclude:
koryph release kick --repo OWNER/REPO --wait
See release-bot.md for a complete fallback ladder (PAT alternative, admin-merge escape hatch) and their trade-offs.
Re-running setup
koryph release setup is idempotent for the workflow and config files (they are always overwritten with the latest render). When release.container is removed, setup also removes the previously generated .github/workflows/container.yml, so re-running setup disables image publishing. The manifest file (.release-please-manifest.json) is never overwritten after the first write — release-please manages it from that point on.