Prepare Release: $ARGUMENTS

SkillAI & models

Use when cutting, tagging, or publishing a new Reactive Agents version, or when a release/publish run fails and needs resuming. Covers the tag-driven lockstep flow (scripts/release.ts + .github/workflows/publish.yml).

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Prepare Release: $ARGUMENTS skill

What this skill tells your AI

The instructions your AI receives, as published by tylerjrbuell/reactive-agents-ts in .agents/skills/prepare-release/SKILL.md and read by ahel’s review.

Mental model — read this first

Release is tag-driven lockstep. One version number stamps all public packages. The release mechanism is scripts/release.ts, run by .github/workflows/publish.yml when you push a vX.Y.Z tag.

  • Changesets are notes, not the driver. bun run changeset only writes .changeset/*.md prose. release.ts aggregates those into root CHANGELOG.md under ## [<version>] — <date> and deletes them at release time.
  • Do NOT hand-edit CHANGELOG.md. It is generated. Curate the wording in the changeset .md body instead.
  • No docs/releases/. That directory was eliminated. The GitHub Release (auto-created from the CHANGELOG section) is the announcement.
  • publish.yml is the sole GitHub Release author. release-drafter was removed — there is no parallel PR-label draft. The published release body = the ## [<version>] — <date> CHANGELOG section, verbatim.
  • No changesets/action, no "Version Packages" PR. That flow was removed. Pushing the tag is the entire trigger.
  • Drift is impossible by construction — there is nothing to reconcile and no check:versions / check-npm-versions step anymore. Don't look for them.

Step 0: Gather release context (wiki orient)

claude-obsidian:wiki-query "completed plans since <last-release-date>"
claude-obsidian:wiki-query "debriefs <package-or-feature-area>"

High-volume cycle (>20 plans/debriefs): claude-obsidian:wiki-fold wiki/Research/Debriefs first, then draft from the fold.

Sources: wiki/Planning/Planning-Index.md, wiki/Research/Debriefs/, wiki/Decisions/Decision Index.md, wiki/Failure-Modes/, wiki/Issues/Running Issues Log.md.

Step 1: Pre-flight gate — all must pass

bun run build       # all packages, 0 errors
bun test            # 0 failures
bun run typecheck   # 0 errors

Hard stop on any failure. Fix before continuing.

Step 2: Identify changes since last release

git describe --tags --abbrev=0                                   # last tag
git log $(git describe --tags --abbrev=0)..HEAD --oneline        # commits
git diff $(git describe --tags --abbrev=0)..HEAD --name-only | grep '^packages/' | cut -d/ -f2 | sort -u

Step 3: Audit documentation

Run the update-docs skill against changes since last release. Verify AGENTS.md / README.md test-count and package-count claims still match reality. Verify changed public APIs (git diff <lasttag>..HEAD -- packages/*/src/index.ts | grep '^+export') are documented. Fix stale docs before proceeding.

Step 4: Author the change notes (changeset)

bun run changeset

Choose the bump for the note's semver intent:

Change typeBump
Bug fix, internal refactor, perfpatch
New feature / package / builder methodminor
Breaking API change, removed exportmajor

The changeset .md body becomes the public changelog text verbatim (its frontmatter is stripped). Write it as the user-facing note: what changed, which package, migration if breaking. This is the only place you curate prose.

Lockstep note: every public package ships at the same tag version regardless of per-changeset bump. The bump type informs the note; it does not produce independent package versions.

Step 5: Decide the version number

You choose the explicit version — it is the git tag, the single source of truth. There is no tool that computes it for you (by design).

Step 6: Dry-run gate (no mutation, no npm)

bun run release:dry <version>          # e.g. bun run release:dry 0.11.0

Confirms package discovery (expect ~35 public), topological publish order, already-published classification, and changeset note count. Mutates nothing.

Optional full local confirm (stamps + builds, stops before npm):

bun scripts/release.ts <version> --no-publish
git restore .            # revert stamped versions + CHANGELOG + consumed changesets

Step 7: Push main, then tag and push — this triggers the release

Push main first, always — even if this repo's convention is normally "push at release/tag time." publish.yml's post-publish sync step resets to origin/main and reapplies only VERSION/CHANGELOG/package.json on top of it (git checkout -f -B main origin/main, not the tag's own ancestry). If origin/main is behind the tagged commit when the tag is pushed, that reset discards every local commit made since the last push, and the sync commit lands on stale history — a divergent-history mess to reconcile by hand (2026-09-05 incident, v0.16.0). Confirm before tagging:

git push origin main
git merge-base --is-ancestor origin/main HEAD && echo "OK: origin/main is caught up"
git tag v<version>
git push origin v<version>          # e.g. git push origin v0.11.0

publish.yml then: install → build → test → clean-install smoke → release:dry gate → release.ts <version> (aggregate CHANGELOG, consume changesets, stamp all packages + root, build, publish in dependency order, fail-fast) → create GitHub Release from the ## [<version>] — <date> CHANGELOG section.

Manual fallback / resume: GitHub → Actions → "Publish to npm" → workflow_dispatch, enter the version. Re-running is safe — already-published packages are skipped (idempotent), so a partial failure resumes cleanly after you fix the cause.

If npm published but the GitHub Release is missing (GH-release step flaked after publish): GitHub → Actions → "Backfill GitHub Releases" → workflow_dispatch. It recreates releases for every tag from its CHANGELOG section. Idempotent (skips/updates existing).

Step 8: Post-release — update memory

## Current Status (<Month> <Day>, <Year>)
- **v<version> released** — <one-line summary>

Update .agents/MEMORY.md AND Claude project memory under ~/.claude/projects/*/memory/ (keep both in sync — other agents read .agents/MEMORY.md).

Final checklist

  • Build / test / typecheck green (Step 1)
  • Docs audited, AGENTS.md & README counts current (Step 3)
  • Changeset authored with user-facing prose (Step 4)
  • release:dry <version> clean (Step 6)
  • main pushed and origin/main confirmed caught up (Step 7, before tagging)
  • Tag pushed; "Publish to npm" workflow green (Step 7)
  • GitHub Release present with notes
  • .agents/MEMORY.md + Claude memory updated (Step 8)

Common mistakes

MistakeReality
Hand-editing CHANGELOG.mdrelease.ts generates it; manual edits collide. Edit the changeset .md instead.
Creating docs/releases/vX.Y.Z.mddocs/ was eliminated — that's an orphan file. The GitHub Release is the announcement.
Tagging before pushing mainThe post-publish sync resets to origin/main, discarding any local commits main doesn't have yet. Push main first — see Step 7.
Waiting for a "Version Packages" PRchangesets/action was removed. Pushing the tag is the whole trigger.
Looking for a release-drafter draftrelease-drafter was removed. publish.yml is the sole GitHub Release author.
git tag without git push origin <tag>The tag push is what fires CI. A local tag releases nothing.
Looking for check:versions / drift scriptsDeleted — drift is structurally impossible in lockstep.
Running release.ts with no version argIt requires an explicit semver and exits otherwise.

Signals

GitHub stars
27
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
prepare-release-tylerjrbuell
Source
github.com/tylerjrbuell/reactive-agents-ts