release-ahp
Skill444 starsChanged 50 days agoMITView on GitHub
Cut a coordinated AHP release (spec + all 5 clients) — bumps every manifest, dates the CHANGELOGs, opens the release PR with auto-merge, and walks through pushing the six per-artifact tags. Use when the user says "release AHP X.Y.Z", "publish AHP", "cut a release", "tag the release", or similar. The skill also captures the recovery procedure for tags whose publish workflow didn't fire.
- Installs packages
- Commits and pushes
In this repository10 other files it gives its agents.
- AGENTS.mdAGENTS.md
- clients/dotnet/AGENTS.mdAGENTS.md
- clients/go/AGENTS.mdAGENTS.md
- clients/kotlin/AGENTS.mdAGENTS.md
- clients/swift/AGENTS.mdAGENTS.md
- docs/guide/agents.mdAGENTS.md
- channels-migrationSkill
- ahp-clientSkill
- session-metadata-migrationSkill
- groom-backlogSkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 6 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 28
If the user asks for a single-client release (e.g.
- Distinctive: line 51
Before touching anything, confirm with the user:
- Very specific: line 61
Create release/ahp-<version> off main.
- Distinctive: line 98
Record this commit's SHA: Every release tag points at it.
- Very specific: line 108
Run npm run generate at repo root — this regenerates every client's Version.generated.* and every release-metadata.json.
- Distinctive: line 139
If the repo's branch protection forces squash, fall back to either:
- Distinctive: line 143
Use the "Rebase and merge" strategy (also preserves both SHAs).
- Distinctive: line 145
Always confirm before merging which strategy preserves commit 1's SHA on main, and resolve any ambiguity with the user.
- Distinctive: line 165
If it doesn't exist (squash happened despite intent), open a follow-up discussion with the user before tagging.
- Very specific: line 190
After pushing the tags, prepend X.Y.Z to STABLE_DOC_VERSIONS in docs/.vitepress/versions.ts and merge that change to main so it becomes the …
- Very specific: line 240
Do not include the --deleted tag in the same git push command as the re-push — push them in separate git push invocations so each tag emits …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Releasing AHP
This skill is the operational counterpart to RELEASING.md
and the cross-cutting AGENTS.md. RELEASING.md is the
canonical reference for what to do per artifact; this skill captures the
order of operations and the foot-guns that bite during a multi-artifact
release.
The repo ships six independently-versioned artifacts but they are released
together by convention — pin the same X.Y.Z across all five client
manifests and the spec on every release unless the user explicitly asks
otherwise.
When to use this skill
The user wants to release AHP. Typical asks:
- "release AHP 0.3.0"
- "tag the release", "push the release tags", "run the publish workflows"
- "the next release will be X.Y.Z" (implies post-release bump)
- "the publish workflow didn't fire on tag T, can you re-trigger it"
If the user asks for a single-client release (e.g. "just bump Rust"),
prefer the .github/prompts/publish-*.prompt.md files instead — this skill
is for coordinated cross-artifact releases.
Mental model
A release is two commits in one PR, plus six tags pushed at the first commit's SHA after merge:
- Release commit — consumes
docs/.changes/*.jsonfragments into dated## [X.Y.Z]CHANGELOG sections, bumps every client manifest from the previous version →X.Y.Z, and regeneratesrelease-metadata.jsonfor every client. All six tags must point at this commit's SHA. - Post-release commit — bumps
PROTOCOL_VERSIONintypes/version/registry.tsto the next planned version, prepends it toSUPPORTED_PROTOCOL_VERSIONS, regenerates eachVersion.generated.{rs,kt,swift,go}, and adds a## [X.Y+1.0] — Unreleasedplaceholder in the root specCHANGELOG.md.
Step-by-step
0. Capture the inputs
Before touching anything, confirm with the user:
- Release version (
X.Y.Z) — the version to use when consumingdocs/.changes/*.jsoninto the six changelogs. - Next development version (default: bump minor, i.e.
X.(Y+1).0). - Release scope (default: all six artifacts; rare to release one in isolation).
1. Branch + commit 1 (release commit)
Create release/ahp-<version> off main. Then in a single commit:
- CHANGELOGs — run
npm run changelog:release -- --version X.Y.Z --date <today YYYY-MM-DD>to collapsedocs/.changes/*.jsoninto the six changelogs. This creates or replaces each## [X.Y.Z] — <today YYYY-MM-DD>section and adds theSpec version/Implements AHP X.Y.Z.line automatically. - Manifests — bump every native version file to
X.Y.Z:clients/rust/Cargo.toml[workspace.package].versionand theversion = "X.Y.Z"pins onahp-types/ahpinside[workspace.dependencies].clients/kotlin/gradle.propertiesVERSION_NAME.clients/typescript/package.jsonversion.clients/swift/VERSION(bare semver, novprefix, trailing newline).clients/go/VERSION(bare semver, novprefix, trailing newline).
- Lockfiles — refresh after the manifest bump:
- In
clients/typescript/:npm install --no-audit --no-fund(no-op if already up to date but writes the version intopackage-lock.json). - In
clients/rust/:cargo update -w(rewrites only the workspace crates inCargo.lock— outside crates stay pinned).
- In
- Metadata — at repo root:
npm run generate:metadata. - Verify — at repo root:
npm test. This runsverify:change-fragments,verify:release-metadata, andverify:changelog, which together gate the release: malformed fragments, a metadata drift, or a missing CHANGELOG heading will fail here and not at tag-push time.
Do not bump
PROTOCOL_VERSIONin this commit. The tag-push workflows validate that the registry version matches the tag's version, so commit 1 must still havePROTOCOL_VERSION = X.Y.Z.
Commit message:
release: AHP X.Y.ZRecord this commit's SHA. Every release tag points at it.
2. Commit 2 (post-release bump)
On the same branch, in a second commit:
types/version/registry.ts:PROTOCOL_VERSION = 'X.(Y+1).0'.SUPPORTED_PROTOCOL_VERSIONS = ['X.(Y+1).0', 'X.Y.Z', ...](newest first; keep any older entries the previous list had).
- Run
npm run generateat repo root — this regenerates every client'sVersion.generated.*and everyrelease-metadata.json. - In the root spec
CHANGELOG.md, add a## [X.(Y+1).0] — Unreleasedplaceholder (with aSpec version: \X.(Y+1).0`line) below the existing## [Unreleased]section. Per-client changelogs already keep their empty## [Unreleased]` section after fragment consumption. - Run
npm testagain.
Commit message:
chore: bump PROTOCOL_VERSION to X.(Y+1).0 for ongoing development3. Open the PR with auto-merge
git push -u origin release/ahp-X.Y.Z
gh pr create --base main --head release/ahp-X.Y.Z \
--title "release: AHP X.Y.Z" \
--body-file <(...)
gh pr merge <num> --auto --mergeUse --merge, not --squash — the tags need commit 1's SHA to
survive the merge. A squash collapses both commits into a new SHA on
main, and the workflows' PROTOCOL_VERSION check would then fail
because post-merge HEAD is on the next-dev version. A merge commit
preserves both original commits as reachable parents.
If the repo's branch protection forces squash, fall back to either:
- Tag the SHA before the squash-merge completes (the commit stays retained once tagged), or
- Use the "Rebase and merge" strategy (also preserves both SHAs).
Always confirm before merging which strategy preserves commit 1's SHA on
main, and resolve any ambiguity with the user.
The PR body should include:
- The release SHA in a copy-pastable variable assignment.
- The six tag-push commands (see step 5 below).
- A note that Kotlin and TypeScript publish via Azure DevOps pipelines (they appear under agent-host-protocol pipelines in vscode-engineering), not GitHub Actions.
4. After merge — verify the release SHA is reachable
git checkout main
git pull --ff-only origin main
git cat-file -t <RELEASE_SHA> # must print "commit"If it doesn't exist (squash happened despite intent), open a follow-up
discussion with the user before tagging. Do not tag the squashed
commit on main — its registry shows the post-release version, and
every publish workflow will reject the tag.
5. Push the six tags
RELEASE_SHA=<sha from step 1>
git tag spec/v<X.Y.Z> $RELEASE_SHA
git tag rust/v<X.Y.Z> $RELEASE_SHA
git tag kotlin/v<X.Y.Z> $RELEASE_SHA
git tag typescript/v<X.Y.Z> $RELEASE_SHA
git tag v<X.Y.Z> $RELEASE_SHA # Swift — bare per RELEASING.md
git tag clients/go/v<X.Y.Z> $RELEASE_SHA
git push origin \
spec/v<X.Y.Z> rust/v<X.Y.Z> kotlin/v<X.Y.Z> \
typescript/v<X.Y.Z> v<X.Y.Z> clients/go/v<X.Y.Z>The six tag schemes are deliberate and not interchangeable. Bare
vX.Y.Z is reserved for Swift (SwiftPM only resolves root-level tags);
clients/go/vX.Y.Z is required by the Go module proxy's sub-module
resolution.
- After pushing the tags, prepend
X.Y.ZtoSTABLE_DOC_VERSIONSindocs/.vitepress/versions.tsand merge that change tomainso it becomes the default documentation version.
6. Confirm publish runs started
For each tag, verify the corresponding workflow run is queued or in progress:
GH_PAGER=cat gh run list --limit 10 \
--json databaseId,event,headBranch,status,conclusion,workflowName,displayTitleExpect to see four GH Actions runs (one per tag below) within seconds:
| Tag | Workflow | Publishes to |
spec/vX.Y.Z | Publish Spec | GitHub Release (schema assets) |
rust/vX.Y.Z | Publish Rust Crates | crates.io (ahp-types, ahp, ahp-ws) |
vX.Y.Z | Publish Swift Package | SwiftPM (tag-resolved) |
clients/go/vX.Y.Z | Publish Go Module | Go module proxy (tag-resolved) |
The remaining two tags trigger Azure DevOps pipelines that don't appear
in gh run list:
| Tag | ADO Pipeline | Publishes to |
kotlin/vX.Y.Z | clients/kotlin/pipeline.yml | Maven Central via ESRP |
typescript/vX.Y.Z | clients/typescript/pipeline.yml | npm via ESRP |
For Kotlin/TypeScript, link the user to the AHP pipelines in ADO
(vscode-engineering tenant) to confirm the runs started. Both
pipelines can also be triggered manually from the ADO UI as a hotfix
escape hatch — the validation steps inside each pipeline are identical
to the tag-triggered path.
Recovery — tag pushed but no publish run fired
This has happened. Symptom: tag exists on origin but gh run list
shows no corresponding workflow run.
None of the four GH Actions publish workflows currently declare
workflow_dispatch, so manual dispatch is not available. The recovery
is to delete the remote tag and re-push it at the same SHA — this
emits a fresh push event without changing the tagged commit:
git push origin --delete <tag>
git push origin <tag>Do not include the --deleted tag in the same git push command as
the re-push — push them in separate git push invocations so each tag
emits its own push event. Re-pushing several tags in a single command
sometimes coalesces into a single event and only one workflow fires.
Once recovery is verified, suggest a follow-up PR adding
workflow_dispatch: to the four publish workflows so the next missed
trigger can be re-run from the Actions UI without tag thrash.
Common foot-guns
- GPG signing lock during
git commit— if you seegpg: keydb_search failed: Operation timed out, rungpgconf --kill all && rm -f ~/.gnupg/public-keys.d/pubring.db.lockand retry the commit. - Bumping
PROTOCOL_VERSIONin commit 1 — the publish workflows re-validate the tag against the tagged commit'sPROTOCOL_VERSION, so a release tag pointing at the post-release commit fails the "Verify tag matches" step. Always keep the bump in commit 2. - Forgetting the Rust
[workspace.dependencies]pins — bumping just[workspace.package].versionleaves the cross-crateahp-types/ahppins on the old version.verify-release-metadatadoes not catch this butcargo publish --dry-runwill. - Forgetting
cargo update -w— without it,Cargo.lockkeeps the old version for ahp-types/ahp/ahp-ws and the resulting commit is partially-bumped. CI's per-language drift check catches it. - Forgetting the Swift/Go trailing newline in
VERSION— theread*PackageVersionhelpers trim, so functionally it's fine, but the convention is0.3.0\n. - Mixing up the Swift tag namespace — Swift uses bare
vX.Y.Z(no prefix). Every other artifact has a prefix. Puttingswift/vX.Y.Zon Swift's tag silently breaks SwiftPM resolution.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

