Skip to content

Commit ed1bde0

Browse files
committed
docs(skill): rewrite /release to tag HEAD, not commit uncommitted work
Perry's workflow bumps the version on every main commit. /release should just tag whatever's on HEAD (usually 20-60 commits ahead of the last tag) and create the GitHub release. The old skill assumed "uncommitted diff to release" was the input, which doesn't match reality — last tag was v0.5.112 while HEAD was v0.5.155. New skill: - clean worktree is a STOP condition, not the trigger - reads version from Cargo.toml, verifies tag doesn't exist - tags HEAD, pushes, creates GH release - watches release-packages.yml (gated on Tests + simctl-tests since v0.5.155) - never retags or force-pushes; failures mean patch-forward
1 parent 6a68bff commit ed1bde0

1 file changed

Lines changed: 110 additions & 33 deletions

File tree

.claude/skills/release/SKILL.md

Lines changed: 110 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,134 @@
11
---
22
name: release
3-
description: Create a new Perry release — commit all changes, push, bump version, tag, create GitHub release, build and install locally
3+
description: Create a new Perry release — tag the current HEAD (version already in Cargo.toml / CLAUDE.md from prior commits), push the tag, create a GitHub release, and watch the gated release-packages workflow
44
disable-model-invocation: true
5-
argument-hint: [description of changes]
5+
argument-hint: [optional: "minor" to request a minor bump instead of just tagging HEAD, or free-text release highlights]
66
allowed-tools: Bash, Read, Edit, Write, Glob, Grep
77
---
88

99
# New Perry Release
1010

11-
Create a new Perry release with all current uncommitted changes.
11+
## Model (important — read before acting)
12+
13+
Perry's day-to-day workflow already bumps the patch version on **every** commit that lands on `main`. The CLAUDE.md workflow rule is explicit: each on-main commit touches `[workspace.package] version` in `Cargo.toml` and prepends a `Recent Changes` entry in `CLAUDE.md`. That means by the time `/release` runs, the current HEAD already knows what version it is.
14+
15+
`/release` therefore does **not**:
16+
- bump the version (it's already bumped)
17+
- commit anything (the work is already committed, usually across many commits)
18+
- write a changelog entry (already in CLAUDE.md)
19+
20+
What `/release` **does**:
21+
1. Reads the current version off HEAD
22+
2. Tags HEAD with `vX.Y.Z` and pushes the tag
23+
3. Creates a GitHub Release (notes assembled from the commits since the previous tag)
24+
4. Watches `release-packages.yml` — which now gates on `Tests` + `Simulator Tests (iOS)` — and reports when publish succeeds or fails
25+
26+
There will typically be tens of commits between releases. That's normal; releases are a distribution event, not a commit event.
1227

1328
## Steps
1429

15-
1. **Survey changes**: Run `git status` and `git diff --stat` to understand all modified and new files. Read the diffs to understand what changed.
30+
### 1. Sanity checks
31+
32+
- `git status`**must be clean**. If there are uncommitted changes, STOP and report. Those changes belong in regular commits (with version bumps + CLAUDE.md entries), not folded silently into a release.
33+
- `git rev-parse --abbrev-ref HEAD` — must be `main`. If not, STOP.
34+
- `git fetch origin && git log HEAD..origin/main --oneline` — must be empty. If origin is ahead, pull/resolve first.
35+
36+
### 2. Read the current version
37+
38+
Grep `Cargo.toml` for `^version = "` under `[workspace.package]`. This is the version to tag. Do **not** bump it here — the `$ARGUMENTS` "minor" handling is only for the edge case where the most recent on-main commit forgot to bump, which is rare.
39+
40+
Verify: `perry --version` (if installed locally) should match, and the `**Current Version:**` line in CLAUDE.md should match. If the three sources disagree, STOP and report — something is off in the history.
41+
42+
### 3. Verify the tag doesn't exist
43+
44+
```bash
45+
git rev-parse "vX.Y.Z" 2>/dev/null && echo "tag exists — aborting" && exit 1
46+
```
47+
48+
If the tag already exists locally or on origin, STOP. Either the release already shipped, or someone started it and didn't finish; either way, don't silently duplicate.
49+
50+
### 4. Survey commits since the last tag
51+
52+
```bash
53+
last_tag=$(git describe --tags --abbrev=0)
54+
git log "$last_tag"..HEAD --oneline
55+
```
56+
57+
There may be 20–60 commits. Read their subjects, mentally group by `fix:` / `feat:` / `docs:` / `chore:`. The GitHub Release body will summarize them. Don't paste the raw commit list — the release notes should be a *summary*.
58+
59+
### 5. Tag + push
60+
61+
```bash
62+
git tag "vX.Y.Z"
63+
git push origin "vX.Y.Z"
64+
```
65+
66+
This tag push fires three workflows in parallel (see `.github/workflows/`):
67+
- `test.yml` — runs the full PR test matrix on the tag SHA
68+
- `simctl-tests.yml` — tier-2 iOS simulator doc-example verification
69+
- `release-packages.yml` — waits for the two above via its `await-tests` gate job, then builds binaries and publishes brew / apt / npm / GitHub release assets
70+
71+
### 6. Create the GitHub Release
72+
73+
```bash
74+
gh release create "vX.Y.Z" \
75+
--title "vX.Y.Z" \
76+
--notes "$(cat <<'EOF'
77+
## Highlights
78+
- ...
79+
80+
## Fixes
81+
- ...
82+
83+
## Features
84+
- ...
85+
86+
## Infrastructure
87+
- ...
88+
EOF
89+
)"
90+
```
1691

17-
2. **Determine version**: Read `CLAUDE.md` for the current version. Bump the patch version (e.g., 0.4.6 → 0.4.7). If `$ARGUMENTS` mentions "minor" bump the minor version instead.
92+
Group the commits since the last tag by type. Keep each bullet to one line. Link to issue numbers where the commit message mentions them. If `$ARGUMENTS` was provided, use it as the "Highlights" seed.
1893

19-
3. **Update version in Cargo.toml**: Edit `Cargo.toml` at the workspace level — the version is under `[workspace.package]`.
94+
**Note**: `release-packages.yml` also triggers on `release: published`. Since we already pushed the tag in step 5, both the tag-push and release-published paths converge — `concurrency` at the workflow level deduplicates.
2095

21-
4. **Update CLAUDE.md**:
22-
- Update `**Current Version:**` to the new version
23-
- Add a new `### vX.Y.Z` section under `## Recent Changes` (above existing entries) with 1-2 line summaries of each change
96+
### 7. Watch the gated publish
2497

25-
5. **Stage and commit**: Stage all changed and new files by name (never use `git add -A`). Commit with message format:
26-
```
27-
<type>: <concise summary> (vX.Y.Z)
98+
```bash
99+
gh run watch $(gh run list --workflow="Release Packages" --limit 1 --json databaseId --jq '.[0].databaseId')
100+
```
28101

29-
- bullet points for each change
30-
```
31-
Where `<type>` is `fix`, `feat`, or `fix` + `feat` combined as appropriate.
102+
Expected timeline on the tag push:
103+
- `Tests` finishes in ~12 min
104+
- `Simulator Tests (iOS)` finishes in ~15 min
105+
- `release-packages` `await-tests` unblocks when both are green, then build+publish runs ~20 min
32106

33-
6. **Push**: `git push origin main`
107+
If `await-tests` shows a failed gate workflow in its logs, the release is blocked. Investigate the failed run, fix on main, cut the next patch. Do **not** re-tag vX.Y.Z — bump to vX.Y.(Z+1) and tag that. Retagging a published tag is a cardinal sin.
34108

35-
7. **Tag**: Create and push tag `vX.Y.Z`:
36-
```
37-
git tag vX.Y.Z && git push origin vX.Y.Z
38-
```
109+
### 8. Verify locally (optional but recommended)
39110

40-
8. **GitHub release**: Create via `gh release create` with a body containing:
41-
- `## Bug Fixes` section (if any fixes)
42-
- `## Features` section (if any features)
43-
- `## Tests` section (if new tests added)
44-
Each with bullet points describing the changes.
111+
After the release is published:
112+
```bash
113+
cargo install --path crates/perry --force
114+
perry --version # should print vX.Y.Z
115+
```
45116

46-
9. **Build all crates**: `cargo build --release` (timeout 10 minutes)
117+
Report back:
118+
- GitHub release URL
119+
- Whether `release-packages.yml` was green end-to-end
120+
- Local `perry --version` confirming the new build
47121

48-
10. **Install perry binary**: `cargo install --path crates/perry --force` (timeout 10 minutes)
122+
## Failure modes
49123

50-
11. **Verify**: Run `perry --version` and confirm it shows the new version.
124+
- **Dirty worktree**: STOP. Don't commit; hand control back to the user.
125+
- **Tag already exists**: STOP. Investigate before deciding whether to bump further or resume a partial release.
126+
- **Gate workflow failed (Tests or Simulator Tests)**: the tag is public but the release can't publish. Fix on main, push a new patch commit (with its own version bump + CLAUDE.md entry), then `/release` again. The stale vX.Y.Z tag is harmless — no assets, no GH release body; some git log noise.
127+
- **`release-packages.yml` build leg failed**: similar — investigate, patch forward, never retag.
51128

52-
## Important
129+
## What NOT to do
53130

54-
- Always read diffs before writing the commit message — understand what changed
55-
- Never skip the build+install step — the release isn't done until perry is locally updated
56-
- If the build fails, fix the issue before proceeding with the release
57-
- Report the GitHub release URL and final `perry --version` output when done
131+
- Do not create commits during the release. If CLAUDE.md needs an entry, it needed it at commit time; it's too late now.
132+
- Do not rewrite or amend the version-bump commit. Just tag HEAD as-is.
133+
- Do not use `git add -A` anywhere in this skill — a dirty worktree is a STOP condition, not a thing to sweep into a release.
134+
- Do not force-push tags.

0 commit comments

Comments
 (0)