Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Release Process

Kael releases are made from one reviewed commit on main. Crate publication, native installers, updater metadata, and the Git tag must all identify that same commit and version. Never publish from a dirty worktree.

Documentation-only changes

Documentation is not a framework release. Changes limited to docs/**, Markdown files such as README.md or crate READMEs, llms.txt, or the docs workflow do not require a workspace version bump, changelog release section, platform rebuild, crate publication, or Git tag.

The Documentation workflow validates those changes on pull requests. A push to main builds and deploys the guide to GitHub Pages. Platform Readiness runs one small classifier for required-check compatibility, then skips the macOS, Linux, Windows, and browser build jobs. The stable Platform readiness check passes after classification, so documentation pull requests remain mergeable.

Keep unreleased documentation improvements on main. They become part of the next crate release naturally when a later code change requires a new version. Do not dispatch Publish crates for a documentation-only commit.

Changes to source, manifests, lockfiles, build scripts, fixtures, or platform workflows are not documentation-only and still require the normal code gates.

Prepare the release candidate

Update the workspace version, kael.dist.toml, scaffold dependency version, and the dated changelog section together. Then run the local gates:

cargo fmt --all --check
bash scripts/ci/verify-cross-targets.sh
bash scripts/ci/audit-dependencies.sh
bash scripts/ci/verify-kael.sh default
bash scripts/publish-all.sh --preflight
bash scripts/ci/verify-docs.sh

On macOS, these commands require full Xcode rather than Command Line Tools for the package archive's default Metal shader build. Select it either system-wide with xcode-select or per shell with DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer.

The documentation gate builds every page, copies llms.txt, rejects orphaned pages, broken local links, duplicate HTML IDs, stale LLM routes, oversized font assets, and guides that stop including the compiled quick-start source. The quick-start example is compiled on native and Wasm targets in Platform Readiness.

The publication preflight selects all 34 crates in dependency order, checks their license and package contents, builds the actual .crate archives as one unpublished workspace set, compiles every extracted archive, and enforces the crates.io 10 MiB compressed archive limit. It does not upload anything.

verify-cross-targets.sh uses Zig to link the portable Linux test graphs from the development machine and separately checks the public Wasm graphs. It is a fast compiler/linker preflight, not runtime evidence: it cannot execute Metal, Direct3D, WebView2, WKWebView, WebKitGTK, or browser engines.

Commit and push the complete candidate before treating runtime evidence as release evidence. That exact push starts the compact Platform Readiness gate: Linux quality/package checks, Linux renderer/WebView runtime, the browser matrix, macOS native/WKWebView/Metal/browser-hardware checks, and two Windows native/WebView/MSI compatibility runners. The Metal browser job must report a non-software WebGL adapter; merely omitting the forced SwiftShader query is not sufficient.

After Platform Readiness is green, run Publish crates with publish=false. This is a cheap attestation: it requires a successful Platform Readiness run whose head_sha exactly matches the checked-out candidate and does not rerun the same platform matrix.

gh workflow run release.yml --ref main -f publish=false
gh run list --workflow release.yml --branch main --limit 1
gh run watch <run-id> --exit-status

Do not substitute a Zig cross-compile for the hosted platform runtime jobs.

Publish crates and tag the commit

The crates-io GitHub environment must contain CARGO_REGISTRY_TOKEN. After the non-publishing workflow run is green, dispatch the same workflow with publish=true:

gh workflow run release.yml --ref main -f publish=true
gh run list --workflow release.yml --branch main --limit 1
gh run watch <run-id> --exit-status

The workflow only publishes from refs/heads/main, requires the exact confirmation generated from the workspace version, uploads crates in dependency order, waits for each registry version to become visible, and can resume a partial upload without overwriting an immutable crates.io version.

After all crates are visible, create the annotated version tag on the exact published commit and push only that tag:

git tag -a v0.4.1 <published-commit-sha> -m "Kael 0.4.1"
git push origin v0.4.1

macOS distribution order

kael.dist.toml may contain the public Developer ID identity and team ID. Keep notary credentials out of the repository. Store them once with Apple's tool and provide only the profile name through KAEL_NOTARY_PROFILE:

xcrun notarytool store-credentials <profile> \
  --apple-id <apple-id> --team-id <team-id>

The production order is deliberate: sign the hardened-runtime app, create the DMG, timestamp-sign the DMG, notarize it, and staple the accepted ticket.

cargo build --release -p kael-cli --bin kael
cargo run -p xtask -- bundle kael.dist.toml \
  --output dist --binary target/release/kael
cargo run -p xtask -- sign kael.dist.toml --artifact dist/kael.dmg
KAEL_NOTARY_PROFILE=<profile> cargo run -p xtask -- \
  notarize kael.dist.toml --artifact dist/kael.dmg

codesign --verify --deep --strict --verbose=4 dist/Kael.app
codesign --verify --strict --verbose=4 dist/kael.dmg
xcrun stapler validate dist/kael.dmg

Bundling signs the app before it enters the disk image. The standalone signer uses a trusted timestamp and omits app-only hardened-runtime flags for a DMG. Production notarization fails closed when KAEL_NOTARY_PROFILE is missing.

Windows and Linux installers

On Windows, install the pinned WiX v4 toolchain used by CI. Supply the PFX path and password through KAEL_WINDOWS_CERTIFICATE and KAEL_WINDOWS_CERTIFICATE_PASSWORD; do not commit the password. Bundling signs the MSI with SHA-256 and a trusted timestamp. Run scripts/ci/verify-windows-msi.ps1 against the result to prove the MSI database, payload hash, extracted executable, and Authenticode status.

Linux bundling produces the .deb and AppImage payloads. The standalone Linux signer creates an armored detached GPG signature using the maintainer's selected key. Verify installer behavior on the same supported distribution baseline used by platform-readiness CI.

Signed updater metadata

Generate the Ed25519 updater key pair once:

cargo run -p xtask -- generate-update-key

Store the private value as KAEL_UPDATE_SIGNING_KEY; never commit or print it in CI logs. Put only the matching public key in updater.public_key in kael.dist.toml. A production xtask publish requires real regular-file artifacts, non-placeholder hashes and sizes, a selected update artifact that is also uploaded, and a private key that matches the configured public key. Dry-run feeds are deliberately unsigned and are not release artifacts.

Browser artifacts

The browser target is published through the same crates and source tree, not as a forked UI implementation. Before tagging, retain the generated-project parity report, optimized Wasm size report, suite-scale report, and Chromium/Firefox/ WebKit matrix report from the exact SHA. Also retain the macOS hardware report, its renderer/vendor identity, the compositor screenshots, and the raw retained framebuffer PNGs. The latter keep visual evidence deterministic when an automation compositor omits a restored WebGL plane. Browser security boundaries such as permission prompts and cross-origin iframe restrictions remain capability differences; they must be handled through Kael's typed capability reports rather than platform-specific view code.