Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .agents/skills/manage-ci/references/current-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,27 @@ Read it with `../SKILL.md` and `ci/ci.md` before editing CI.
| `main_windows.yml` (`Main · Windows`) | push to `main` | Exhaustive main planning plus the same-commit reusable Windows lane |
| `ci.yml` | `workflow_call` only | Inert migration shim for the former main ingress filename; no push trigger or dispatch |
| `ci-control.yml` (`CI · Manual Full`) | dispatch on default branch | Explicit operator-only full plan, bounded lane dispatch and correlated diagnostic checks |
| `release.yml` | release tags, dispatch | Release-only signing, assets and publication |
| `release.yml` | release tags, dispatch | Canonical version synchronization, release-only signing, assets and publication |
| `website-pages.yml` | main website paths, dispatch | Public website deployment |
| `pr_cleanup.yml` | PR close, dispatch | Positively matched cleanup only |
| `pr_auto_assign.yml` | PR lifecycle | Metadata only |

Other scheduled, deployment, Docker, package, canary and cache-warming
workflows are independent of required PR readiness.

For a non-canary manual dispatch, `release.yml` runs the checked-in
`scripts/release-version.sh`, creates one linear release-source commit when the
tracked version surface changes, and fast-forwards `main` before any release
build starts. `just release` is a preflight and synchronous dispatcher for that
same workflow. A tag-push release is read-only with respect to `main` and is
accepted only when the tag is already reachable from `main` and applying the
same version script produces no tracked diff. Canary dispatches never update
`main` or publish. The publish job creates only the release-specific tag commit
for generated Swift/SDK resources and enables GitHub-generated release notes.
The comparison base is the highest stable `vMAJOR.MINOR.PATCH` tag below the
target; prerelease tags are excluded so RC and final notes use the same stable
baseline.

The five PR lifecycle rows and five main push rows above are the complete
allowed routine validation entry sets. Their separation and direct GitHub log
visibility are contractual, not a presentation preference. `pr_builds.yml`,
Expand Down
65 changes: 65 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ jobs:
metadata:
name: Resolve release metadata
runs-on: ubuntu-24.04
permissions:
contents: write
outputs:
tag: ${{ steps.meta.outputs.tag }}
version: ${{ steps.meta.outputs.version }}
source_sha: ${{ steps.source.outputs.sha }}
release_notes_base: ${{ steps.source.outputs.release_notes_base }}
prerelease: ${{ steps.meta.outputs.prerelease }}
skip_gpu_bundles: ${{ steps.meta.outputs.skip_gpu_bundles }}
canary: ${{ steps.meta.outputs.canary }}
Expand Down Expand Up @@ -136,6 +140,64 @@ jobs:
echo "Manual release tag already exists and is immutable: $RELEASE_TAG" >&2
exit 1
fi
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 24
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable 2026-07-16
- name: Prepare canonical release source
id: source
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ steps.meta.outputs.tag }}
CANARY: ${{ steps.meta.outputs.canary }}
run: |
set -euo pipefail
source_sha="$GITHUB_SHA"

if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then
scripts/release-version.sh "$RELEASE_TAG"
if ! git diff --quiet; then
echo "Release tag $RELEASE_TAG does not contain its complete version update." >&2
echo "Run scripts/release-version.sh $RELEASE_TAG, commit the result on main, and create a new tag." >&2
git status --short >&2
exit 1
fi
elif [[ "$CANARY" == "true" ]]; then
echo "Canary release: leaving main unchanged."
else
scripts/release-version.sh "$RELEASE_TAG"
git add --update
if ! git diff --quiet; then
echo "Release version preparation left unstaged tracked changes:" >&2
git status --short >&2
exit 1
fi
if git diff --cached --quiet; then
echo "main already contains the complete $RELEASE_TAG version update."
else
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -m "$RELEASE_TAG: prepare release source"
fi
source_sha="$(git rev-parse HEAD)"
release_remote="https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git push "$release_remote" "$source_sha:refs/heads/main"
fi

release_notes_base="$(
git tag --list 'v*' |
python3 scripts/select-release-notes-base.py "$RELEASE_TAG"
)"
if [[ -n "$release_notes_base" ]]; then
echo "GitHub release notes will compare $release_notes_base...$RELEASE_TAG."
else
echo "No earlier stable release tag exists; GitHub release notes have no explicit comparison base."
fi
{
echo "sha=$source_sha"
echo "release_notes_base=$release_notes_base"
} >> "$GITHUB_OUTPUT"
- name: Select trusted Linux runners
id: runners
uses: ./.github/actions/select-ci-runners
Expand Down Expand Up @@ -1607,6 +1669,7 @@ jobs:
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
ref: ${{ needs.metadata.outputs.source_sha }}
# Archive verification and manifest generation run before any push
# credential is exposed to a shell.
persist-credentials: false
Expand Down Expand Up @@ -1747,6 +1810,8 @@ jobs:
with:
tag_name: ${{ needs.metadata.outputs.tag }}
prerelease: ${{ needs.metadata.outputs.prerelease }}
generate_release_notes: true
previous_tag: ${{ needs.metadata.outputs.release_notes_base }}
overwrite_files: false
files: release-artifacts/*

Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -689,11 +689,11 @@ For stale instances (crashed mesh-llm leaving behind a runtime dir):

See `RELEASE.md` for the full process.

Current release flow: kick off the **Release** workflow (`.github/workflows/release.yml`) from the GitHub Actions UI via `workflow_dispatch` with the version input (e.g. `v0.X.Y`).
Current release flow: kick off the **Release** workflow (`.github/workflows/release.yml`) from the GitHub Actions UI via `workflow_dispatch` with the version input (e.g. `v0.X.Y`), or run `just release v0.X.Y` to preflight and dispatch that same workflow.

The dispatched workflow handles everything: it bumps versions via `scripts/release-version.sh`, generates and patches the SwiftPM manifest, packages SDK console assets, creates and pushes the release tag at a release-prep commit, builds the full artifact matrix (macOS, Linux CPU/ARM64/CUDA/CUDA-Blackwell/ROCm/Vulkan, Windows CPU/CUDA/ROCm/Vulkan), and publishes the GitHub release. Dispatch inputs include `skip_gpu_bundles` and `canary` (dry-run: build + smoke without publishing).
The dispatched workflow handles everything: it bumps versions via `scripts/release-version.sh`, commits the tracked version surface to `main` before building, generates and patches the SwiftPM manifest, packages SDK console assets, creates and pushes the release tag at a release-prep commit, builds the full artifact matrix (macOS, Linux CPU/ARM64/CUDA/CUDA-Blackwell/ROCm/Vulkan, Windows CPU/CUDA/ROCm/Vulkan), and publishes the GitHub release with generated notes. Dispatch inputs include `skip_gpu_bundles` and `canary` (dry-run: build + smoke without mutating `main` or publishing).

Pushing a `v*` tag manually also triggers the workflow, but that path requires preparing `Package.swift` and SDK console assets in the tag commit yourself — see `RELEASE.md`. Prefer the dispatch path.
Pushing a `v*` tag manually also triggers the workflow, but the tag must point to `main` history with the matching `scripts/release-version.sh` update already committed; it also requires preparing `Package.swift` and SDK console assets in the tag commit yourself. The workflow rejects a drifted tag. See `RELEASE.md` and prefer the dispatch path.

### Installer checksum sidecars

Expand Down
40 changes: 35 additions & 5 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@
Releases are normally cut by running the **Release** workflow
(`.github/workflows/release.yml`) from the GitHub Actions UI via
`workflow_dispatch` with the version input (for example `v0.31.0`). The
dispatched workflow bumps versions, generates and patches the SwiftPM
manifest, packages SDK console assets, creates and pushes the release tag,
builds all platform bundles, and publishes the GitHub release. After a complete
dispatched workflow uses `scripts/release-version.sh` as the single version
authority, commits the complete tracked version update to `main`, and only then
starts the release build. It later generates and patches the SwiftPM manifest,
packages SDK console assets, creates and pushes the release tag, builds all
platform bundles, publishes the GitHub release, and asks GitHub to generate the
release notes against the highest stable SemVer tag below the target. RC tags
are never selected as the comparison base, so every RC includes all changes
since the previous stable release, and the final release repeats that complete
range plus any post-RC changes. The `just release <version>` recipe performs
local preflight and
dispatches this same workflow; it does not maintain a second version-bump path.
Canary dispatches build the requested version without changing `main` or
publishing. After a complete
stable, non-canary release with the full GPU matrix succeeds, it dispatches
`Mesh-LLM/mesh-packaging` to package the verified release archives, publish the
native package release assets, publish the supported GHCR image matrix, and
Expand All @@ -17,6 +27,11 @@ include `skip_gpu_bundles` and `canary` (dry-run: build and smoke everything
without publishing). Releases that intentionally skip GPU bundles do not
dispatch the full packaging matrix.

Do not use GitHub's bare **Draft a new release** form as an alternate release
path. It bypasses the verified artifact graph. The Release workflow is the only
supported GitHub release publisher; the Actions UI, `just release`, and a
pre-versioned tag all enter that workflow.

The sections below document the underlying steps. They matter when releasing
manually via a tag push, debugging the workflow, or validating bundles
locally.
Expand Down Expand Up @@ -215,8 +230,23 @@ Verify:

## Publish

Push a `v*` tag to run `.github/workflows/release.yml`. The upstream release
workflow owns release archive production, but it does not publish OCI images.
Push a `v*` tag to run `.github/workflows/release.yml`. This lower-level path is
accepted only when the tag points to `main` history and already contains the
complete matching version update. Prepare and commit it before creating the
tag:

```bash
scripts/release-version.sh v0.X.Y
git add --update
git commit -m "v0.X.Y: prepare release source"
git push origin main
git tag v0.X.Y
git push origin v0.X.Y
```

The workflow rejects version-drifted tags instead of publishing binaries whose
source version disagrees with the release. The upstream release workflow owns
release archive production, but it does not publish OCI images.
`Mesh-LLM/mesh-packaging` is the canonical package, GHCR, and npm producer. It
starts only after a stable GitHub release and its complete CPU/GPU archive set
have published successfully. Prereleases never dispatch it. The upstream
Expand Down
21 changes: 21 additions & 0 deletions ci/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,27 @@ The temporary `ci.yml` reusable-only shim has no push trigger, dispatcher, or
lane calls. It can be removed with the other migration shims after the updated
runner contract is active on protected main.

### Release source and version ownership

`scripts/release-version.sh` is the single owner of the tracked release-version
surface. On a non-canary `release.yml` dispatch, the metadata job applies that
script, creates a linear release-source commit when needed, and fast-forwards
`main` before the build graph begins. `just release` only performs local
preflight, dispatches that workflow, and waits for its result. A tag push must
already be reachable from `main` and version-complete; the metadata job applies
the same script and rejects any tracked diff. Canary dispatches do not mutate
`main` or publish.

The later publish job checks out the canonical source commit, adds only the
generated SwiftPM/binding and SDK console resources needed by the immutable
release tag, publishes the assets, and enables GitHub-generated release notes.
The metadata job selects the highest stable `vMAJOR.MINOR.PATCH` tag below the
target as the explicit comparison base. It excludes every prerelease tag, so
release candidates and their final stable release use the same stable baseline;
the final notes retain the RC changes and add any post-RC changes.
The workflow-scoped token push does not fan out another main CI run; the release
graph is the evidence for that version-only source commit.

## Graph shape

```mermaid
Expand Down
Loading
Loading