Release pipeline
Component spec. Constrained by ADR-0042, ADR-0041, ADR-0003, ADR-0025.
Scope
This spec covers the CI pipelines, release workflows, dependency resolution rules, and distribution artifacts for the kaged project. It does not cover the daemon binary build itself (see daemon.md + ADR-0041) or the install script's runtime behavior (see ADR-0042 §5–§6).
1. Package classes and resolution
Three package classes exist. Resolution rules differ by class.
| Class | Examples | Lives | Dependency spec | Published |
|---|---|---|---|---|
| Internal workspace | @kaged/daemon, @kaged/harness, @kaged/dsl, @kaged/wire, … |
packages/ in the monorepo |
workspace:* + TS source paths (ADR-0025) |
Never |
| External published | @kaged/utils, @kaged/natives, @kaged/sso, @kaged/sso-fixtures, reference plugins |
Own repos (kaged-dev/kaged-<thing>) |
Registry semver (^x.y.z) or exact pin for contracts |
npm with provenance |
| In-tree plugins | @kaged/plugin-memory-markdown, @kaged/plugin-memory-hindsight, @kaged/plugin-webhook-notify |
plugins/ in the monorepo |
workspace:* for internal deps; registry semver for externals |
From their own repos (mirrors) |
1.1 Resolution rules
- Internal packages use
workspace:*inpackage.jsonand declare TS sourcepathsin theirtsconfig.jsonper ADR-0025. The paths are monorepo-internal only — they do not appear in published packages. - External packages use registry semver (
"@kaged/utils": "^0.0.2"). Nolink:, nofile:, noworkspace:*. - Contract packages (e.g.
@kaged/sso-fixtures) use exact-pin ("@kaged/sso-fixtures": "0.0.1") perdocs/conventions.md§Cross-repo contract packages. bun linkis a documented local override for active co-development of extracted packages. The committed lockfile always reflects registry versions. CI and Docker never link.
1.2 TS paths policy
tsconfig.json paths entries exist only for internal workspace packages. External packages (@kaged/utils, @kaged/natives, @kaged/sso-fixtures) must not have paths entries — TypeScript resolves their types from the installed npm package.
2. Clean-clone invariant
⛔ invariant: a fresh git clone of the monorepo + bun install --frozen-lockfile (no sibling repos, no bun link, no environment variables beyond Bun itself) must:
- Typecheck:
bun --filter '*' typecheckexits 0. - Test:
bun test --recursive packages/ plugins/— all tests pass. - Format:
bunx biome ci .exits 0. - Build the release binary:
bun run scripts/build-release.ts --target=linux-x64 --outfile=dist/kaged-daemonexits 0. - Build the site:
bun run packages/site/build.tsexits 0.
This invariant is the acceptance criterion for Phase 0 (ADR-0042) and is enforced by the dev CI workflow.
3. Monorepo CI (dev)
Workflow: .github/workflows/ci.yml
Trigger: every push to main, every pull request.
Jobs
check (ubuntu-latest, Bun):
bun install --frozen-lockfilebun --filter '*' typecheckbun test --recursive packages/ plugins/bunx biome ci .
All four steps must pass. Failure blocks merge.
4. Monorepo CI (release)
Workflow: .github/workflows/release.yml
Trigger: push of a v* tag.
Jobs
build (matrix: linux-x64 on ubuntu-22.04, linux-arm64 on ubuntu-22.04-arm):
bun install --frozen-lockfilebun run scripts/build-release.ts --target=<arch> --outfile=dist/kaged-daemon- Copy the matching-arch
.nodebeside the binary. - Upload
dist/as a build artifact.
image (needs build, ubuntu-latest):
- Download build artifacts.
docker buildx buildmulti-arch (amd64 + arm64).- Push to
ghcr.io/kaged-dev/kaged-daemon:<tag>+:latest(skip:latestfor prerelease tags).
release (needs build, environment: release with required reviewer):
- Download build artifacts.
- Generate
SHA256SUMS. - Create a GitHub Release in
kaged-dev/kaged-releasesvia the cross-repo GitHub App token. - Upload per-arch binaries +
SHA256SUMSas release assets. - Copy changelog markdown into
kaged-releases. - Mark as prerelease if the tag contains
-(e.g.v0.1.0-rc.1).
Invariants
- ⛔ Release artifacts contain no embedded sourcemap (asserted by
assertNoSourcemapinbuild-release.ts). - ⛔ The image package is public on GHCR.
- ⛔ The tag matches the version in
packages/daemon/package.json.
5. Extracted-package CI
Each extracted repo carries its own CI, generalizing the pattern established by kaged-sso (ADR-0036).
Common pattern
Dev CI (push to main, PR):
bun install --frozen-lockfile- Typecheck
- Biome format check (
bunx biome ci .) - Test
Release CI (push of v* tag):
- Dev CI steps (gate).
- Verify tag matches
package.jsonversion. npm publish --provenance --access public(requiresNPM_TOKENsecret +id-token: writefor provenance).
Package-specific additions
kaged-natives: multi-platform matrix build (4 targets), platform packages published first, then the loader package withoptionalDependenciespinned.kaged-sso: lockstep publish of@kaged/sso+@kaged/sso-fixtures(same version, same tag). Container image pushed to GHCR.- Reference plugins (
kaged-plugin-memory-hindsight,kaged-plugin-memory-markdown,kaged-plugin-webhook-notify): standard dev + release CI.
6. kaged-releases repo
Scope: passive artifact host + script home. Builds no source and no binaries.
Contents (authored in-repo)
README.md— install instructions, quick start.install.sh— Docker MVP install script (§6.1).kaged— Docker wrapper CLI (§6.2).
Contents (received from monorepo release CI)
- Per-arch binaries +
SHA256SUMSas GitHub Release assets. - Changelog markdown copies.
CI
- Shellcheck on
install.shandkaged. - Optional install smoke-test in a container.
- No secrets, no npm publish.
mainis branch-protected.
6.1 install.sh (Docker MVP)
Detects Docker, pulls the image, writes a compose file with the project directory volume-mounted and port exposed, sets KAGED_UI_URL / KAGED_PUBLIC_URL, and installs the kaged wrapper to ~/.local/bin/ (or /usr/local/bin/ with --system).
Root/user host install modes are deferred to the v1 roadmap.
6.2 kaged wrapper
A thin shell shim on PATH that fronts the containerised daemon:
kaged start→docker compose up -dkaged stop→docker compose downkaged status→docker compose pskaged auth launch→docker exec kaged kaged-daemon auth launch-urlthenxdg-open/openkaged logs→docker compose logs -fkaged exec <cmd>→docker exec -it kaged <cmd>kaged update→docker compose pull && docker compose up -d
7. site-manifest.json descriptor (§1a contract)
Packages the site documents but does not build-depend on emit a site-manifest.json descriptor. The site consumes this descriptor instead of importing the package.
Schema
{
"name": "@kaged/<thing>",
"version": "0.1.0",
"description": "...",
"tools": [{ "name": "...", "description": "..." }],
"hooks": ["on_session_start", "..."],
"knobs": { "<key>": { "type": "range", "description": "..." } },
"config_schema": { "...JSON Schema..." },
"readme_excerpt": "First 500 chars of README"
}
Generation
A build:site-manifest script in the package generates the descriptor from the kaged-plugin.yaml manifest and package.json.
Freshness enforcement
CI regenerates the descriptor and diffs against the committed copy. A stale descriptor fails the build. Same anti-drift posture as schema regeneration and the sso-fixtures lockstep.
Delivery
The descriptor ships inside the published npm package (a file in the tarball). The site consumes the versioned copy at the pinned version.
Amendment log
- 2026-06-14: Initial spec, per ADR-0042.