feat(release): opt into linux-musl artifacts via shared workflow - #48
Merged
Conversation
Pass the new dot-github rust-release.yml inputs that landed in #18 over there: linux_musl_required: true — block release on musl build failure linux_musl_verify_alpine: true — exec the x86_64-musl binary inside alpine:latest after build to catch dlopen/NSS/locale surprises that pass the static-link `file` assertion Both inputs were spike-validated end-to-end at spike/musl-build before the upstream PR landed: cross builds for both musl arches succeeded (~1m45s each, statically linked), x86_64 host smoke test passed, and the binary executed cleanly inside alpine:latest (`anc 0.3.0`). Also bundled (carried in the dirty working tree across the session; related RELEASES.md polish): - Update RELEASES.md release-pipeline table from 5 → 7 targets, naming both musl rows and the two opt-in inputs. - Document the cliff.toml chore-skip footgun and the 'CHANGELOG is generated, never hand-written' rule under `Releasing dev to main`. Adds a new step 9 (review CHANGELOG) and renumbers the push step to 10. Tightens the existing 'PRs and changelog generation' section to point at the new rule.
Upstream agentnative-site `dev` advanced from 0.1.0 to 0.2.0 since this fixture was last synced. The drift-check workflow caught it on PR #48. No host map change — only the version string differs — so the generated Rust map (SkillHost / KNOWN_HOSTS / resolve_host) is unaffected, but keeping the committed fixture in sync with upstream prevents drift-check from failing on every subsequent PR.
brettdavies
added a commit
that referenced
this pull request
May 4, 2026
## Summary Releases v0.3.1, an artifact-set release: ships `x86_64-unknown-linux-musl` and `aarch64-unknown-linux-musl` static binaries on every release. No source change versus v0.3.0 — the binary is identical; only the artifact set is wider. Consolidates one dev commit: - **#48 — `feat(release): opt into linux-musl artifacts via shared workflow`** — passes `linux_musl_required: true` and `linux_musl_verify_alpine: true` to the shared `rust-release.yml@main` (those inputs landed in brettdavies/.github#18). Bundled with the inputs change is a `RELEASES.md` polish: 5 → 7 target table update plus a separate cliff.toml chore-skip + "never hand-written" rule that was pre-existing dirty in the working tree. Triple-diff verification before opening: A is exactly the 6 expected ship-surface files; B contains only release-prep files (Cargo.toml, Cargo.lock, CHANGELOG.md) plus the always-divergent completions/; no guarded engineering-doc paths leaked. ## Changelog ### Added - Ship `x86_64-` and `aarch64-unknown-linux-musl` static binaries on every release. Statically linked against musl libc, so they run on Alpine and other musl-libc-host distros without glibc, and on every glibc distro too. ### Documentation - Document the `cliff.toml` chore-skip footgun and the "CHANGELOG is generated, never hand-written" rule in `RELEASES.md` under `Releasing dev to main`. - Update the release-pipeline target table from 5 → 7 targets, naming the two musl rows and the two opt-in inputs (`linux_musl_required`, `linux_musl_verify_alpine`). ## Type of Change - [x] `feat`: New feature (non-breaking change which adds functionality) ## Related Issues/Stories - Story: n/a - Issue: n/a - Architecture: n/a - Related PRs: #48 (this release's only consolidated dev commit), brettdavies/.github#17 (shared-workflow musl matrix rows + soft-fail), brettdavies/.github#18 (release of #17 to main) ## Testing - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Unit tests: pass on dev as part of #48 CI (fmt, clippy, test, audit, package check, drift-check) - Integration tests: n/a (no source change vs v0.3.0) - Coverage: unchanged End-to-end musl validation completed pre-merge in the throwaway `spike/musl-build` workflow: - `cross build --release --locked --target x86_64-unknown-linux-musl` — green, statically linked - `cross build --release --locked --target aarch64-unknown-linux-musl` — green, statically linked - `file target/.../release/anc` matched `statically linked` for both arches - x86_64 host smoke test (`anc --version`) — `anc 0.3.0` - Belt-and-suspenders: `docker run --rm --pull always -v ".../release:/musl-bin:ro" alpine:latest /musl-bin/anc --version` — `anc 0.3.0` The `release` pipeline (now 7 targets) re-runs all of the above on the v0.3.1 tag push, so the binaries shipped to the GitHub Release will be the freshly-built ones, not the spike's. ## Files Modified **Modified:** - `.github/workflows/release.yml` — passes the two new shared-workflow inputs. - `Cargo.toml` — version 0.3.0 → 0.3.1. - `Cargo.lock` — `cargo update -p agentnative` regen. - `CHANGELOG.md` — `scripts/generate-changelog.sh` extracted #48's `## Changelog` section into a v0.3.1 entry. Cross-checked: cliff.toml chore-skip didn't drop anything (commit subject was `feat`, not `chore`). - `RELEASES.md` — release-pipeline table 5 → 7 targets + bundled cliff.toml/never-hand-written documentation. - `src/skill_install/skill.json` — fixture refresh from upstream agentnative-site dev (caught by drift-check on #48; brought along here). **Created:** - None. **Renamed:** - None. **Deleted:** - None. ## Breaking Changes - [x] No breaking changes The binary surface is unchanged. New consumers on Alpine gain an install path; existing consumers see no difference. ## Deployment Notes After this PR squash-merges to `main`: ```bash git checkout main && git pull git tag -a -m "Release v0.3.1" v0.3.1 git push origin main --tags ``` The tag push triggers the now-7-target release pipeline. After the GitHub Release reaches `published` (homebrew dispatch and finalize-release flip), backport per the new convention: ```bash ./scripts/sync-dev-after-release.sh v0.3.1 git push origin dev ``` The throwaway `spike/musl-build` branch (local + remote) can be pruned any time after this PR opens; it served its purpose. ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow Conventional Commits - [x] Self-review of code completed (PR #48 review applies; release-prep commits are bump/completions/CHANGELOG/skill-fixture as scripted) - [x] Tests added/updated and passing (validated via spike + #48 CI) - [x] No new warnings or errors introduced - [x] Changes are backward compatible
11 tasks
brettdavies
added a commit
to brettdavies/.github
that referenced
this pull request
May 4, 2026
## Summary Fixes a silent matrix-expansion failure introduced in #17/#18 that bit agentnative-cli's first attempt at v0.3.1 (release run [25336702699](https://github.com/brettdavies/agentnative-cli/actions/runs/25336702699)). The build job's `continue-on-error: ${{ matrix.soft_fail && !inputs.linux_musl_required }}` evaluated to `null` for non-musl matrix rows when the caller passed `linux_musl_required: true` — `matrix.soft_fail` was undefined for those rows, `null && false` returns `null`, and GHA refuses non-boolean job-level booleans by silently dropping the entire build matrix from the run. The absence cascaded: `publish-crate` `needs: build` skipped, `release` and `homebrew` skipped behind it, the v0.3.1 tag pushed but no crate published / release created / formula dispatched. Belt-and-suspenders fix: - **Belt**: normalize the expression to `matrix.soft_fail == true` (and the same on the post-build annotation step's `if:`), so missing-field rows evaluate to `false` instead of `null`. - **Suspenders**: set `soft_fail: false` explicitly on every non-musl row, so the matrix is self-documenting (every row's stance is grep-able) and the implicit-default footgun stops being a footgun. Either fix alone closes the immediate bug. Both together prevent the class — a future matrix row added without `soft_fail` won't reintroduce this failure. ## Changelog ### Fixed - Fix silent build-job matrix expansion failure when the caller passed `linux_musl_required: true`. The expression `matrix.soft_fail && !inputs.linux_musl_required` returned `null` for matrix rows without `soft_fail`, which GHA refuses as a job-level boolean — the entire build matrix dropped from the run and `publish-crate` / `release` / `homebrew` skipped behind it. ## Type of Change - [x] `fix`: Bug fix (non-breaking change which fixes an issue) ## Related Issues/Stories - Story: n/a - Issue: n/a - Architecture: n/a - Related PRs: #17 (introduced the matrix rows + expression), #18 (released #17 to main), brettdavies/agentnative-cli#48 (consumer opt-in PR), brettdavies/agentnative-cli#49 (consumer release PR — the v0.3.1 tag has been deleted from agentnative-cli; will be re-pushed after this fix lands on main) ## Testing - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Unit tests: n/a (workflow-only repo) - Integration tests: n/a - Coverage: n/a `actionlint` clean on the modified `rust-release.yml`. The fix will be exercised in real conditions when agentnative-cli re-pushes its v0.3.1 tag after this lands on main — at that point all 7 matrix rows should instantiate (5 hard-fail, 2 soft-fail with `linux_musl_required: true` flipping them to hard-fail). The original spike validation (brettdavies/agentnative-cli `spike/musl-build`, 2026-05-04) confirmed the underlying musl build paths work; this PR addresses only the orchestration glue. ## Files Modified **Modified:** - `.github/workflows/rust-release.yml` — Adds explicit `soft_fail: false` to the 5 non-musl matrix rows (x86_64-linux-gnu, aarch64-linux-gnu, aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc). Updates the build-job `continue-on-error` expression and the post-build annotation step's `if:` to compare `matrix.soft_fail == true`. Adds a comment to the matrix block explaining the constraint and citing the failed run as the canary. **Created:** - None. **Renamed:** - None. **Deleted:** - None. ## Breaking Changes - [x] No breaking changes Existing consumers see no behavior change. Consumers passing `linux_musl_required: false` (default) saw working soft-fail behavior before this fix because `matrix.soft_fail && true` returned the matrix-row value (or null for non-musl rows, but with `continue-on-error: null` GHA seemingly tolerated it for some expansion paths — only the `linux_musl_required: true` path triggered the silent drop). The fix makes both paths reliable. ## Deployment Notes - [x] No special deployment steps required After merge to dev → cherry-pick to main, agentnative-cli will re-tag v0.3.1 and push. Pipeline should run clean: 7 matrix rows instantiate, 5 hard-fail, 2 musl rows hard-fail (because `linux_musl_required: true` flips their stance). On a successful musl build the alpine-verify step runs as before. ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow Conventional Commits - [x] Self-review of code completed - [x] Tests added/updated and passing (workflow-only; `actionlint` clean) - [x] No new warnings or errors introduced - [x] Changes are backward compatible
25 tasks
brettdavies
added a commit
to brettdavies/.github
that referenced
this pull request
May 4, 2026
## Summary Consolidates two fix commits to main: - **#20 — `fix(rust-release): normalize build matrix soft_fail evaluation`** — silent matrix-expansion failure in the build job's `continue-on-error` expression when callers pass `linux_musl_required: true`. Bit agentnative-cli's first attempt at v0.3.1 ([failed run](https://github.com/brettdavies/agentnative-cli/actions/runs/25336702699)) — tag pushed, no crate published, no release created. Tag has been deleted; will be re-pushed after this lands. Belt-and-suspenders fix: normalize the expression to `matrix.soft_fail == true` AND set `soft_fail: false` explicitly on every non-musl matrix row. - **#19 — `ci(lint): gate dev pushes and fail on actionlint findings`** — bundled because it landed on dev between #20 and the cut of this release branch. Single-file change to `.github/workflows/lint.yml` hardening this repo's own CI: actionlint now runs on dev pushes and fails the workflow on findings. Triple-diff verification clean: A has exactly the two expected files; B is empty (no non-doc paths on dev missing from this release); no guarded paths leaked. ## Changelog ### Fixed - Fix silent build-job matrix expansion failure when the caller passed `linux_musl_required: true`. The expression `matrix.soft_fail && !inputs.linux_musl_required` returned `null` for matrix rows without `soft_fail`, which GHA refuses as a job-level boolean — the entire build matrix dropped from the run and `publish-crate` / `release` / `homebrew` skipped behind it. ### Changed - `.github/workflows/lint.yml` (this repo's own CI) now runs actionlint on `push: dev` and fails the workflow on actionlint findings, raising the bar for what reaches dev. ## Type of Change - [x] `fix`: Bug fix (non-breaking change which fixes an issue) ## Related Issues/Stories - Story: n/a - Issue: n/a - Architecture: n/a - Related PRs: #20 (the rust-release fix), #19 (the lint hardening), #18 (the release that introduced the soft_fail bug), brettdavies/agentnative-cli#48 (consumer opt-in), brettdavies/agentnative-cli#49 (consumer release — v0.3.1 tag deleted, will be re-pushed after this lands) ## Testing - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Unit tests: n/a (workflow-only repo) - Integration tests: n/a - Coverage: n/a `actionlint` clean on both modified workflow files. The rust-release fix's real-world validation comes when agentnative-cli re-pushes its v0.3.1 tag after this lands — at that point all 7 matrix rows should instantiate, 5 hard-fail and 2 musl rows hard-fail (because `linux_musl_required: true` flips them). ## Files Modified **Modified:** - `.github/workflows/rust-release.yml` — see #20. - `.github/workflows/lint.yml` — see #19. **Created:** - None. **Renamed:** - None. **Deleted:** - None. ## Breaking Changes - [x] No breaking changes ## Deployment Notes - [x] No special deployment steps required After this lands on main, agentnative-cli re-tags v0.3.1 and pushes. Pipeline should run clean. ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow Conventional Commits - [x] Self-review of code completed (PR #20 and #19 reviews apply) - [x] Tests added/updated and passing (`actionlint` clean on both files) - [x] No new warnings or errors introduced - [x] Changes are backward compatible
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Opts agentnative-cli into the two new shared-workflow inputs that landed in
brettdavies/.githubPR #18, so futurereleases ship Alpine/musl artifacts. No source changes; the binary is identical to v0.3.0.
After this PR merges (and ships via a
release/v0.3.1cherry-pick tomain), every release will produce 7 archivesinstead of 5, adding
agentnative-x86_64-unknown-linux-musl.tar.gzandagentnative-aarch64-unknown-linux-musl.tar.gz. Alpine and other musl-libc-host distros gain a first-class install pathbeyond
cargo installand the existing glibc Linux artifact.Bundled: a small
RELEASES.mdpolish that was already dirty in the working tree (cliff.toml chore-skip warning + "neverhand-written" rule under
Releasing dev to main), plus the necessary 5 → 7 target table update.Changelog
Added
x86_64-andaarch64-unknown-linux-muslstatic binaries on every release. Statically linked against musl libc,so they run on Alpine and other musl-libc-host distros without glibc, and on every glibc distro too.
Documentation
cliff.tomlchore-skip footgun and the "CHANGELOG is generated, never hand-written" rule inRELEASES.mdunderReleasing dev to main. Adds a new review step (renumbered to 9) and tightens the existing "PRsand changelog generation" section.
Type of Change
feat: New feature (non-breaking change which adds functionality)Related Issues/Stories
refactor: enforce check_x → CheckStatus convention + toolchain supply-chain pin #17 to main). agentnative-cli
spike/musl-build(throwaway) was the validation surface.Testing
Test Summary:
End-to-end validation completed in the throwaway
spike/musl-buildworkflow before either upstream or this PR opened:cross build --release --locked --target x86_64-unknown-linux-musl: green, ~1m45s, statically linkedcross build --release --locked --target aarch64-unknown-linux-musl: green, ~1m45s, statically linkedfile target/.../release/ancmatchedstatically linkedfor both archesanc --version):anc 0.3.0docker run --rm --pull always -v $PWD/target/.../release:/musl-bin:ro alpine:latest /musl-bin/anc --version:anc 0.3.0. Confirms exec compatibility with musl-libc host (Alpine), not just staticlinkage.
actionlintclean on the modifiedrelease.yml. The pre-push hook (scripts/hooks/pre-push: fmt, clippy-Dwarnings,test, cargo-deny, Windows compat) passed.
Files Modified
Modified:
.github/workflows/release.yml: passeslinux_musl_required: trueandlinux_musl_verify_alpine: trueto theshared
rust-release.ymlworkflow.RELEASES.md: updates the release-pipeline table from 5 → 7 targets (naming the two musl rows and the two opt-ininputs), and bundles a separate cliff.toml chore-skip + "never hand-written" docs improvement that was already dirty
in the working tree.
Created:
Renamed:
Deleted:
Key Features
dlopen, NSS, locale) that passthe static-link
fileassertion.linux_musl_required: true) means a musl regression blocks the release, not a silent artifactomission.
Benefits
cargo installrequires the full Rust toolchain. Now:
wget+tar xf+ run.scratchcontainers gain a usable artifact too.time."
Breaking Changes
Deployment Notes
RELEASES.mdAfter this PR squash-merges to
dev, ship via the standard cherry-pick:release/v0.3.1fromorigin/main.Cargo.toml0.3.0 → 0.3.1;cargo update -p agentnative../scripts/generate-completions.sh,bash scripts/sync-skill-fixture.sh,./scripts/generate-changelog.sh.Cross-check the generated CHANGELOG section against this PR's
## Changelogbullets per the cliff.toml chore-skipwarning.
release: v0.3.1PR../scripts/sync-dev-after-release.sh v0.3.1 && git push origin devper the newconvention.
The throwaway
spike/musl-buildbranch in this repo can be pruned (locally + remotely) any time after this PR opens; itserved its purpose and was never merged anywhere.
Checklist
actionlintclean; pre-push hook clean)