---
name: wyrm-release-workflow
description: |
  Ship a Wyrm release end-to-end: feature branch → PR → squash-merge →
  version bump → tag → GitHub Release → npm publish (with 2FA handling).
  Codifies the exact sequence Ryan and Claude ran to ship 5.2.1, 5.2.2,
  and 5.3.0 so future releases don't re-discover the gotchas (granular
  access tokens, --otp doesn't help with token auth, etc.).
argument-hint: "[patch|minor|major] <one-line release summary>"
user-invocable: true
---

# Wyrm Release Workflow

End-to-end release of `wyrm-mcp` (and its sibling packages in the
monorepo). Follow in order. Skips are not free.

## Pre-flight

1. **Working tree clean** on `feat/<name>` branch with all your changes
   committed.
2. **`npm run build` green** locally — `tsc` clean + dist/ executable
   bits set (the build script handles `chmod +x dist/*.js`).
3. **No console.log left in source** — Wyrm uses stderr for diagnostics
   (`process.stderr.write`) and the MCP stdio protocol owns stdout.
4. **CHANGELOG.md drafted** under `## [Unreleased]` (or move to the
   target version section).
5. **README badges and feature counts updated** if applicable
   (`MCP_tools` badge, capability counts).

## Branch + PR + merge

```bash
cd ~/repos/personal/Wyrm
git push -u origin <your-feat-branch>
git fetch origin                                # makes gh see the remote ref
gh pr create --head <your-feat-branch> \
  --title "<conventional commit subject>" \
  --body "<summary, why, test plan>"
gh pr merge <num> --squash --delete-branch
git checkout main && git pull --ff-only
```

**Note:** `gh pr create` may error with "you must first push the
current branch to a remote, or use the --head flag" even after a
successful push, until you run `git fetch origin`. Always include
`--head <branch>` to dodge this.

## Bump version + CHANGELOG

Decide between patch / minor / major using semver:

- **Patch** (5.x.y → 5.x.y+1): bug fixes, additive compatible changes,
  docs, internal refactors with no surface change
- **Minor** (5.x.0 → 5.x+1.0): new MCP tools, new optional features,
  backward-compatible parameter additions
- **Major** (5.x → 6.0): breaking schema changes, removed tools,
  renamed inputs

```bash
sed -i 's/"version": "X.Y.Z"/"version": "X.Y.Z+1"/' packages/mcp-server/package.json
# Bump CHANGELOG: move ## [Unreleased] to ## [X.Y.Z+1] — YYYY-MM-DD
npm install --no-audit --no-fund --no-progress     # syncs lockfile
cd packages/mcp-server && npm run build && cd -
git add packages/mcp-server/package.json packages/mcp-server/package-lock.json CHANGELOG.md
git commit -m "release: wyrm-mcp X.Y.Z+1

<2-3 sentence summary of what's in the release>

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>"
```

## Tag + GitHub Release

```bash
git tag -a vX.Y.Z+1 -m "wyrm-mcp X.Y.Z+1 — <subject>"
git push origin main
git push origin vX.Y.Z+1
gh release create vX.Y.Z+1 \
  --title "wyrm-mcp X.Y.Z+1 — <subject>" \
  --notes "<release notes — pull from CHANGELOG, add 'Full diff:' link to compare/...>"
```

## npm publish

**The 2FA gotcha.** `npm publish` with a *classic* access token will fail
with `E403 — Two-factor authentication or granular access token with
bypass 2fa enabled is required to publish packages.` Adding `--otp=NNNNNN`
to the command **does NOT help** when authenticated via token (only when
using password auth).

The fix:

1. Open https://www.npmjs.com/settings/<user>/tokens
2. Generate New Token → **Granular Access Token**
3. Name: `wyrm-publish` (or per-machine)
4. Expiration: 30+ days
5. Packages and scopes → select `wyrm-mcp` (or all-of-scope) → "Read and write"
6. **Critical:** toggle **"Bypass two-factor authentication"** ON
7. Generate. Paste the `npm_...` string.

Wire it in:

```bash
printf '//registry.npmjs.org/:_authToken=npm_XXXX\n' > ~/.npmrc
chmod 600 ~/.npmrc
npm whoami       # should print your npm user
```

Then publish:

```bash
cd packages/mcp-server
npm pack --dry-run | tail -5    # confirm version + filename
npm publish
npm view wyrm-mcp version       # should equal what you just shipped
npm view wyrm-mcp dist-tags     # latest: X.Y.Z+1
```

## Post-publish

1. **Close the related Wyrm quest** via `wyrm_quest_complete`.
2. **Update relevant spec status** if this ships a dragon-platform spec
   — flip the README table row to `✅ shipped YYYY-MM-DD · Wyrm@<sha>`.
3. **Verify the postinstall hook fires** on a fresh `npm install -g`
   (the first-install pitch only shows once per `~/.wyrm/.first-install-shown`
   marker).
4. **Rotate any tokens** you pasted in an AI chat log. Granular tokens
   are cheap to recreate.

## Common failures

- `npm error code E403 ... Two-factor authentication required` →
  granular token with bypass 2FA not yet generated (see above).
- `gyp ERR! ... -flto=4` during install on a fresh box → preinstall fix
  shipped in 5.2.1 should handle this automatically.
- `prebuild-install warn install Request timed out` → preinstall hint
  in 5.2.2 should print the right per-distro install command.
- `npm pack` doesn't include `scripts/preinstall.cjs` →
  `packages/mcp-server/package.json` `files:` array is missing the
  entry; without it the script doesn't ship in the tarball.

## When to skip

- **Pre-release / canary**: use `npm publish --tag next` instead of the
  default `latest` tag. Test installs via `npm install -g wyrm-mcp@next`.
- **Major bump that needs testing**: don't publish to `latest` until
  you've verified on a clean install on at least one non-Termux host.
