development
md 152 lines 6.17 KB
Rendered Raw
1 ---
2 name: release
3 description: Cut a tagged release of the splitfire-agent crate. Covers the version-bump checklist, the gate (fmt/clippy/test), fast-forwarding main, the annotated tag that fires the cross-platform release and crates.io workflows, and verifying the published GitHub release and crate. Use whenever the user asks to release, cut, tag, or publish a new splitfire-agent version.
4 allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5 user-invocable: true
6 ---
7
8 # Release
9
10 How to cut a `splitfire-agent` release. Releases are driven by git tags. Pushing a
11 `v*` tag fires two workflows:
12
13 - `.github/workflows/release.yml` — builds the binary on five targets
14 (darwin-arm64/x64, linux-x64/arm64, windows-x64) and publishes a GitHub release
15 with auto-generated notes and the archives attached.
16 - `.github/workflows/release-crates.yml` — runs `cargo publish --locked` to push
17 the crate to crates.io, authenticated by **trusted publishing**: a GitHub OIDC
18 token is exchanged for a short-lived crates.io token. There is no
19 `CARGO_REGISTRY_TOKEN` secret to store or rotate.
20
21 Branch model: work lands on `development` (via PRs); `main` is the release branch;
22 every tag points at a commit that is on `main`. Previous tags were plain annotated
23 (not GPG-signed) tags authored by the maintainer, message `Release vX.Y.Z`.
24
25 ---
26
27 ## 0. One-time setup: the trusted publisher
28
29 Trusted publishing needs a publisher registered on crates.io **before** the first
30 tagged run. The crate must already be on crates.io (a first-ever publish still
31 needs a manual `cargo login` + `cargo publish`), and you must be a crate owner.
32 Then: crate page → **Settings → Trusted Publishing → Add → GitHub**:
33
34 - Repository owner: `SplitFireAI`
35 - Repository name: `splitfire-agent`
36 - Workflow filename: `release-crates.yml` (the bare filename, not a path)
37 - Environment: leave blank unless the job also declares `environment:`
38
39 The workflow filename is part of the trust claim, so renaming the workflow breaks
40 publishing until the crates.io config is updated to match — keep the two in sync.
41
42 ---
43
44 ## 1. Confirm the version is bumped
45
46 The version bump often already landed with the feature PR — check before assuming
47 you need a bump commit. These three must agree and must be the version you're
48 releasing:
49
50 - `Cargo.toml` (`version = "X.Y.Z"`)
51 - `Cargo.lock` (the `splitfire-agent` package entry)
52 - `registry/agent.json` (`"version": "X.Y.Z"`)
53
54 ```sh
55 grep -m1 '^version' Cargo.toml
56 grep -A2 '^name = "splitfire-agent"' Cargo.lock | grep version
57 grep '"version"' registry/agent.json
58 ```
59
60 If a bump is needed, edit all three, run `cargo build` to refresh `Cargo.lock`, and
61 commit on `development` (or the release branch) before continuing. `registry/` is the
62 ACP registry submission; keeping its `version` in sync with `Cargo.toml` is part of
63 the release, per AGENTS.md.
64
65 ## 2. Run the gate
66
67 CI runs exactly these three; run them locally and get them green before tagging. Use
68 `cargo` directly — this is a Rust crate, the global `rv` rule is Ruby-only.
69
70 ```sh
71 cargo fmt -- --check
72 cargo clippy --locked --all-targets -- -D warnings
73 cargo test --locked
74 ```
75
76 ## 3. Get the release commit onto main
77
78 `main` must fast-forward to the commit you're releasing (no merge commit, matching
79 history). Verify there is nothing on `main` that isn't on your source branch:
80
81 ```sh
82 git log --oneline main..origin/main # expect empty (main not ahead)
83 git log --oneline origin/main..development # the commits you're about to release
84 ```
85
86 Fast-forward `main` to the release commit (works without checking it out), then push:
87
88 ```sh
89 git branch -f main development
90 git push origin main
91 ```
92
93 ## 4. Tag and push
94
95 Confirm your git identity and gh account are the maintainer's before tagging — the
96 `git-commit-signing` skill governs identity selection. Match the previous tag's
97 style: plain annotated, message `Release vX.Y.Z`. Pushing the tag is what fires the
98 release workflow, so push it last.
99
100 ```sh
101 git tag -a vX.Y.Z -m "Release vX.Y.Z"
102 git push origin vX.Y.Z
103 ```
104
105 ## 5. Verify the published release
106
107 The workflow takes ~8-9 minutes (five-target matrix). Watch it, then confirm all
108 five assets are attached:
109
110 ```sh
111 gh run list --workflow=release.yml --limit 1
112 gh run view <run-id> --json status,conclusion,jobs \
113 --jq '{status,conclusion,jobs:[.jobs[]|{name,conclusion}]}'
114 gh release view vX.Y.Z
115 ```
116
117 A green release has five assets:
118 `splitfire-agent-{darwin-arm64,darwin-x64,linux-arm64,linux-x64}.tar.gz` and
119 `splitfire-agent-windows-x64.zip`.
120
121 Also confirm the crate published:
122
123 ```sh
124 gh run list --workflow=release-crates.yml --limit 1
125 curl -s https://crates.io/api/v1/crates/splitfire-agent | python3 -Ic \
126 'import sys,json;print(json.load(sys.stdin)["crate"]["max_version"])'
127 ```
128
129 ---
130
131 ## Notes
132
133 - A release is outward-facing and hard to reverse (public binaries, cached/indexed).
134 The user asking to "release vX.Y.Z" authorizes it; still report faithfully if a
135 gate step fails rather than tagging anyway.
136 - The GitHub release is created by `github-actions[bot]`, not the tagger. That's
137 expected — the workflow uses `GITHUB_TOKEN`.
138 - Release notes are auto-generated from merged PRs since the previous tag
139 (`--generate-notes`). There is no hand-written CHANGELOG file in this repo.
140 - crates.io is immutable and append-only: a version can be published exactly once,
141 then only *yanked* (hidden from new resolves, existing lockfiles keep working) —
142 never replaced or deleted. So the tag's `Cargo.toml` version must not already be on
143 crates.io; any re-release needs a fresh version bump. The `ed-*` dependencies are
144 already on crates.io, so no dependency needs publishing first. To publish manually
145 instead of via CI: `cargo login` once (token from crates.io/settings/tokens), then
146 `cargo publish --locked` from the tagged commit.
147 - `crates-io-auth-action` is pinned to `v1.0.5` deliberately: the action repo has
148 no moving `v1` tag (only `v1.0.x`), so the `@v1` shown in the crates.io docs
149 example fails to resolve. Bump the pin when a newer release lands.
150 - If a platform build fails after the tag is pushed, fix the cause and re-run the
151 failed jobs (`gh run rerun <run-id> --failed`); the release-create step tolerates
152 an already-existing release and `--clobber`s assets, so re-runs are safe.