chore: add release workflow skill
Co-Authored-By: OndeCode v1.0.1-acp <noreply@ondeinference.com>
Seto Elkahfi committed
Oct 10, 2026 at 15:01 UTC
727bc6d6857556c3994171cf70801b8b37d10a16
1 file changed
+173
.agents/skills/release/SKILL.md
new
+173
@@ -0,0 +1,173 @@
1
+---
2
+name: release
3
+description: Cut a release of the onde-ed Rust workspace. Covers version bumping, the release branch/PR flow, tagging, and the two tag-triggered GitHub Actions (crates.io publish and Swift XCFramework). Use when asked to create, cut, or publish a release.
4
+allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5
+user-invocable: true
6
+---
7
+
8
+# Skill: Release
9
+
10
+## What This Skill Covers
11
+
12
+How to cut a release of the `onde-ed` Cargo workspace: bumping the version,
13
+landing it through the branch/PR flow, tagging, and what the two tag-triggered
14
+workflows do automatically afterwards.
15
+
16
+## The one-number rule
17
+
18
+The whole workspace releases on **one version**. Every crate declares
19
+`version.workspace = true`, so a release changes exactly one source of truth:
20
+the root `Cargo.toml`.
21
+
22
+```toml
23
+[workspace.package]
24
+version = "X.Y.Z"
25
+```
26
+
27
+Plus the internal path dependencies in the same file, which pin the version
28
+explicitly:
29
+
30
+```toml
31
+ed-agent = { version = "X.Y.Z", path = "crates/ed-agent" }
32
+ed-mcp = { version = "X.Y.Z", path = "crates/ed-mcp" }
33
+ed-acp = { version = "X.Y.Z", path = "crates/ed-acp" }
34
+ed-acp-tui = { version = "X.Y.Z", path = "crates/ed-acp-tui" }
35
+ed-acp-testkit = { version = "X.Y.Z", path = "crates/ed-acp-testkit" }
36
+ed-onde-account = { version = "X.Y.Z", path = "crates/ed-onde-account" }
37
+```
38
+
39
+Bump all of these together. The crate manifests under `crates/*/Cargo.toml`
40
+need no edits.
41
+
42
+## Versioning
43
+
44
+Semver. Given the current `X.Y.Z`:
45
+- **patch** (`Z+1`) — bug fixes, internal changes, no API additions.
46
+- **minor** (`Y+1`, `Z=0`) — backwards-compatible API additions.
47
+- **major** (`X+1`, `Y=Z=0`) — breaking changes.
48
+
49
+## Step-by-step
50
+
51
+The base branch is **`development`**; `main` is the promoted/stable branch.
52
+Releases land on `development` first, get tagged, then `development` is promoted
53
+to `main`.
54
+
55
+### 1. Branch off `development`
56
+
57
+```sh
58
+git checkout development && git pull
59
+git checkout -b release/X.Y.Z
60
+```
61
+
62
+### 2. Bump the version
63
+
64
+Edit the root `Cargo.toml` (`[workspace.package] version` and the internal
65
+`ed-*` path-dependency versions). A quick way, run from the repo root:
66
+
67
+```sh
68
+sed -i '' 's/OLD\.VER\.SION/X.Y.Z/g' Cargo.toml
69
+```
70
+
71
+### 3. Refresh the lockfile and verify
72
+
73
+```sh
74
+cargo check --workspace # updates Cargo.lock, catches breakage
75
+```
76
+
77
+`cargo fmt --all -- --check`, `cargo test --locked --workspace`, and
78
+`cargo clippy --locked --workspace --all-targets -- -D warnings` must all pass —
79
+the release workflow re-runs them and fails the publish otherwise.
80
+
81
+### 4. Commit and push
82
+
83
+```sh
84
+git add Cargo.toml Cargo.lock
85
+git commit -m "Release X.Y.Z: bump the workspace"
86
+git push
87
+```
88
+
89
+Commit subject convention: `Release X.Y.Z: bump the workspace`.
90
+
91
+### 5. Open the release PR → `development`
92
+
93
+```sh
94
+gh pr create --base development --head release/X.Y.Z \
95
+ --title "Release X.Y.Z" --body "..."
96
+gh pr edit <n> --add-assignee <you> --add-reviewer <reviewer>
97
+```
98
+
99
+### 6. Merge, then tag the merge commit
100
+
101
+After approval, merge the PR, update local `development`, and tag **the merge
102
+commit** (this is what every historical release tag points at):
103
+
104
+```sh
105
+gh pr merge <n> --merge
106
+git checkout development && git pull
107
+git tag vX.Y.Z <merge-sha>
108
+git push origin vX.Y.Z
109
+```
110
+
111
+> The tag name carries a `v` prefix (`vX.Y.Z`); the workspace version does not
112
+> (`X.Y.Z`). The workflows strip the `v` when comparing, so they must match on
113
+> the numeric part.
114
+
115
+### 7. Promote `development` → `main`
116
+
117
+Open a second PR to bring `main` up to the tagged state:
118
+
119
+```sh
120
+gh pr create --base main --head development --title "Merge development → main (vX.Y.Z)"
121
+```
122
+
123
+Merging it runs `ci.yml` on `main` as a final green check.
124
+
125
+## What the tag triggers
126
+
127
+Pushing a `vX.Y.Z` tag fires **two** workflows. Both start with a `preflight`
128
+job that validates the tag matches the `ed-agent` version in `Cargo.toml`, then
129
+runs fmt + test + clippy. If the version and tag disagree, the release fails
130
+here — this is the safety net for step 6.
131
+
132
+### `release-sdk-rust.yml` → crates.io
133
+
134
+- Dry-runs the workspace publish with `cargo-workspaces` (plain
135
+ `cargo publish --dry-run` can't resolve the inter-crate path deps post-package).
136
+- Publishes crates in dependency order to crates.io.
137
+- `cargo workspaces plan --skip-published` makes re-runs safe: a run that dies
138
+ mid-publish only publishes the crates still missing from the registry.
139
+
140
+### `release-sdk-swift.yml` → XCFramework + `ed-swift`
141
+
142
+- Builds the `EdFramework.xcframework` for Apple targets (~2h20m build;
143
+ **not** cancel-in-progress — killing it leaves half-published state).
144
+- Creates a GitHub Release with the xcframework zip + checksum as assets.
145
+- Checks out `ondeinference/ed-swift`, rewrites `Package.swift` with the new
146
+ release URL + checksum, copies the generated `ed_agent_ffi.swift`, commits,
147
+ pushes to `ed-swift` `main`, and tags it `vX.Y.Z`.
148
+
149
+## Manual / recovery runs
150
+
151
+Both workflows have a `workflow_dispatch` with a `publish` boolean and a
152
+`release_tag` input. Use this to re-publish an existing tag if a run failed
153
+after tagging — e.g. the crates.io publish succeeded but the Swift build timed
154
+out. Point it at the existing `vX.Y.Z` tag; the crates.io re-run skips anything
155
+already on the registry.
156
+
157
+## Toolchain
158
+
159
+The Rust toolchain is pinned in `rust-toolchain.toml` (currently `1.94.0`).
160
+Workflows read `channel` from it, so a toolchain bump is a normal source change,
161
+not release-time config.
162
+
163
+## Checklist
164
+
165
+- [ ] On a `release/X.Y.Z` branch off `development`.
166
+- [ ] Root `Cargo.toml`: `[workspace.package] version` + all `ed-*` path deps bumped.
167
+- [ ] `cargo check --workspace` run (Cargo.lock updated).
168
+- [ ] fmt / test / clippy all green locally.
169
+- [ ] Commit `Release X.Y.Z: bump the workspace`.
170
+- [ ] PR → `development`, reviewed, merged.
171
+- [ ] `vX.Y.Z` tag on the merge commit, pushed.
172
+- [ ] `development` → `main` PR opened/merged.
173
+- [ ] Both tag workflows green (crates.io + Swift).