Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 210 additions & 0 deletions .agents/skills/release-maintainer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
---
name: release-maintainer
description: Internal maintainer SOP for version bumps, release PRs, tagging, publishing, and post-publish verification in this repository.
advertise: false
---

# agent-tty release maintainer SOP

This is a project-local maintainer skill for `agent-tty` releases. The canonical human policy lives in [`docs/RELEASE-PROCESS.md`](../../../docs/RELEASE-PROCESS.md); use this skill as the execution checklist when an agent is asked to cut or publish a release from this repository.

## When to use this skill

Use this skill when you are asked to:

- bump the package version for a stable release or prerelease,
- create or manage the release PR,
- wait for CI and merge the release PR,
- tag and publish a release,
- or verify the published npm package and GitHub Release assets.

## Core guardrails

- Do **not** release from an unmerged branch. The release tag must reference a commit already merged into `main`.
- Keep the version bump minimal unless the user explicitly asks for additional release-related changes.
- Follow the repo's PR body/footer requirements from `AGENTS.md` when creating the release PR.
- Treat `gh auth status` as advisory only. When access looks suspicious, verify with a real API call instead.
- Run post-publish verification under Node 24. If the ambient shell is older, point `NODE_BIN` at an explicit Node 24 binary.
- For `doctor --json`, the health signal is `.result.ok`; the outer `.ok` field only says the CLI command envelope succeeded.

## Preflight

1. Re-read `RELEASE.md`, `ROADMAP.md`, and `docs/RELEASE-PROCESS.md`.
2. Confirm the workspace is clean and based on up-to-date `main`.
3. Verify GitHub CLI access with a real API call:

```bash
gh api graphql -f query='query { viewer { login } }'
```

4. Prefer `mise run ci` when `mise` is available; otherwise use `npm run verify`.

## Prepare the version bump

Start from fresh `main`:

```bash
git checkout main
git pull origin main
```

Create a release branch and bump without tagging.

Stable patch release example:

```bash
git switch -c release/0.1.1
npm version patch --no-git-tag-version
```

First beta on the next patch line:

```bash
git switch -c release/0.1.1-beta.0
npm version prepatch --preid beta --no-git-tag-version
```

Next beta on the same line:

```bash
npm version prerelease --preid beta --no-git-tag-version
```

Then validate and commit the pure version bump:

```bash
npm run verify
npm run version:json
git add package.json package-lock.json
git commit -m "chore(release): <version>"
```

## Create the release PR

```bash
git push -u origin <release-branch>
gh pr create --base main --head <release-branch> --title "chore(release): <version>"
```

Before creating the PR, check whether one already exists for the release branch:

```bash
gh pr list --head <release-branch> --state all
```

## Wait for CI and merge the PR

Interactive waiting is fine with:

```bash
gh pr checks <pr-number> --watch
```

For automation or agent-driven waiting, prefer structured workflow inspection:

```bash
gh pr checks <pr-number>
gh run list --branch <release-branch> --event pull_request --limit 5
gh run view <run-id> --json status,conclusion,jobs
```

Merge the PR only after the required checks succeed.

Normal merge path:

```bash
gh pr merge <pr-number> --squash --delete-branch
```

If branch policy still blocks the merge after checks pass and an authorized releaser is allowed to override it:

```bash
gh pr merge <pr-number> --squash --admin --delete-branch
```

If remote refs look stale after the merge, refresh them before checking `origin/main` or deleted release branches:

```bash
git fetch origin --prune
```

## Tag and publish the release

Default to the documented tag flow unless the user explicitly asks for the GitHub CLI shortcut.

Documented flow:

```bash
git checkout main
git pull origin main
git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z
```

If you are explicitly asked to create the tag and GitHub Release with `gh`, use the merged `main` commit SHA:

```bash
MERGED_SHA=<merge-commit-on-main>
gh release create vX.Y.Z \
--target "$MERGED_SHA" \
--title vX.Y.Z \
--notes-file <notes-file>
```

For prereleases, also add:

```bash
--prerelease --latest=false
```

The release workflow should publish the verified tarball to both GitHub Releases and npm.

## Verify the published npm package

Run the installed CLI under Node 24:

```bash
PACKAGE_NAME='agent-tty'
PACKAGE_VERSION='<version>'
NODE_BIN=${NODE_BIN:-node}
INSTALL_PREFIX=$(mktemp -d)
AGENT_TTY_HOME=$(mktemp -d)

npm view "$PACKAGE_NAME" dist-tags --json
npm install -g --prefix "$INSTALL_PREFIX" "$PACKAGE_NAME@$PACKAGE_VERSION"
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" version --json | jq -r '.result.cliVersion'
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" --home "$AGENT_TTY_HOME" doctor --json | jq '.result.ok'
```

For prereleases, also confirm the expected dist-tag points at the exact version.

## Verify the published GitHub Release assets

```bash
VERSION=<version>
RELEASE_TAG="v${VERSION}"
RELEASE_TGZ="agent-tty-${VERSION}.tgz"
NODE_BIN=${NODE_BIN:-node}

DOWNLOAD_DIR=$(mktemp -d)
INSTALL_PREFIX=$(mktemp -d)
AGENT_TTY_HOME=$(mktemp -d)

gh release download "$RELEASE_TAG" --repo coder/agent-tty --dir "$DOWNLOAD_DIR" --pattern "$RELEASE_TGZ"
gh release download "$RELEASE_TAG" --repo coder/agent-tty --dir "$DOWNLOAD_DIR" --pattern "${RELEASE_TGZ}.sha256"
(
cd "$DOWNLOAD_DIR"
sha256sum -c "${RELEASE_TGZ}.sha256"
)

npm install -g --prefix "$INSTALL_PREFIX" "$DOWNLOAD_DIR/$RELEASE_TGZ"
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" version --json | jq -r '.result.cliVersion'
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" --home "$AGENT_TTY_HOME" doctor --json | jq '.result.ok'
```

## Failure recovery checklist

- If a release tag was pushed before the PR merged, cancel the workflow run, delete the remote tag, delete the local tag, and redo the release through the PR-first flow.
- If the GitHub Release exists but assets or npm publish are missing, inspect the `Release` workflow run before attempting any manual repair.
- If `gh auth status` looks broken but the real API calls succeed, keep using real `gh` command results as the source of truth.
- If installation succeeds with an `EBADENGINE` warning because `npm` itself is running under an older Node, rerun the installed CLI under Node 24 before deciding whether the release is healthy.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Use this directory when you need project workflow guidance rather than product-f
- [`../design/README.md`](../design/README.md) — architecture and design references.
- [`CONTRIBUTING.md`](./CONTRIBUTING.md) — setup, validation, and day-to-day contribution flow.
- [`RELEASE-PROCESS.md`](./RELEASE-PROCESS.md) — maintainer release checklist and proof expectations.
- [`../.agents/skills/release-maintainer/SKILL.md`](../.agents/skills/release-maintainer/SKILL.md) — internal agent SOP for version bumps, release PRs, tagging, and publish verification.
- [`../dogfood/CATALOG.md`](../dogfood/CATALOG.md) — curated proof bundles for review.
69 changes: 62 additions & 7 deletions docs/RELEASE-PROCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@
5. Confirm the published package metadata still points at `agent-tty` and the public GitHub repository.
6. Remember that `main` is protected: release changes must land through a pull request, and the release tag must be created only after that PR is merged.

## GitHub CLI readiness

This flow assumes `gh` can create PRs, inspect checks, merge, and create releases. `gh auth status` is useful for a quick summary, but in some environments it can report a stale or misleading state even when real GitHub API calls still work.

Before treating release automation as blocked, verify with a real API call such as:

```bash
gh api graphql -f query='query { viewer { login } }'
```

If that succeeds, prefer the result of the real `gh` operation over the status summary.

## Validation bar

Preferred local validation uses `mise`:
Expand Down Expand Up @@ -138,6 +150,26 @@ gh pr create --base main --head <release-branch> --title "chore(release): <versi

Run the normal PR checks, get approval as needed, and merge the PR.

## Wait for CI and merge the release PR

For interactive use, `gh pr checks <pr-number> --watch` is fine. For automation or agent-driven release work, prefer inspecting the workflow run directly so you can wait on structured `status` and `conclusion` fields instead of parsing live terminal refresh output.

Typical sequence:

```bash
gh pr checks <pr-number>
gh run list --branch <release-branch> --event pull_request --limit 5
gh run view <run-id> --json status,conclusion,jobs
```

If the PR still cannot be merged after every required check passes, inspect the base-branch policy first. When normal merge and `--auto` are unavailable but an authorized releaser is allowed to override the policy, use:

```bash
gh pr merge <pr-number> --squash --admin --delete-branch
```

Use `--admin` sparingly and only after confirming the required release checks succeeded.

## Tag the merged `main` commit

After the release PR has merged:
Expand Down Expand Up @@ -166,6 +198,22 @@ or:
- `package.json`: `0.1.1-beta.0`
- tag: `v0.1.1-beta.0`

### GitHub CLI alternative: create the tag and release in one step

If you already know the merged `main` commit SHA and want GitHub to create the tag and release together, this also works:

```bash
MERGED_SHA=<merge-commit-on-main>
gh release create v0.1.1-beta.0 \
--target "$MERGED_SHA" \
--prerelease \
--latest=false \
--title v0.1.1-beta.0 \
--notes-file <notes-file>
```

`gh release create` creates the tag on the specified merged commit and still triggers the `Release` workflow via the pushed `v*` tag. Use the prerelease flags only for prerelease versions; omit them for stable releases.

## Publish the GitHub Release and npm package

The hand-curated workflow lives at [`.github/workflows/release.yml`](../.github/workflows/release.yml).
Expand All @@ -187,20 +235,23 @@ Prerelease versions publish with the prerelease identifier as the dist-tag, so `

## Verify the published npm package

After the workflow succeeds, verify the exact npm package version before announcing the release:
After the workflow succeeds, verify the exact npm package version before announcing the release. Run these checks under Node 24; if your interactive shell is older, point `NODE_BIN` at an explicit Node 24 binary first.

```bash
PACKAGE_NAME='agent-tty'
PACKAGE_VERSION='<version>'
NODE_BIN=${NODE_BIN:-node}
INSTALL_PREFIX=$(mktemp -d)
AGENT_TTY_HOME=$(mktemp -d)

npm view "$PACKAGE_NAME" dist-tags --json
npm install -g --prefix "$INSTALL_PREFIX" "$PACKAGE_NAME@$PACKAGE_VERSION"
"$INSTALL_PREFIX"/bin/agent-tty version --json
"$INSTALL_PREFIX"/bin/agent-tty --home "$AGENT_TTY_HOME" doctor --json
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" version --json | jq -r '.result.cliVersion'
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" --home "$AGENT_TTY_HOME" doctor --json | jq '.result.ok'
```

`doctor --json` uses the outer `ok` field for command-envelope success; the release-health signal is `.result.ok`.

If the release is a prerelease, also confirm the intended dist-tag points at the exact published version:

```bash
Expand All @@ -227,24 +278,28 @@ printf 'expected dist-tag %s for %s\n' "$DIST_TAG" "$PACKAGE_VERSION"

## Verify the published GitHub Release assets

Also verify the hosted tarball fallback before announcing the release:
Also verify the hosted tarball fallback before announcing the release. Run these checks under Node 24 for the same reason as the npm verification above.

```bash
VERSION=<version>
RELEASE_TAG="v${VERSION}"
RELEASE_TGZ="agent-tty-${VERSION}.tgz"
NODE_BIN=${NODE_BIN:-node}

DOWNLOAD_DIR=$(mktemp -d)
INSTALL_PREFIX=$(mktemp -d)
AGENT_TTY_HOME=$(mktemp -d)

gh release download "$RELEASE_TAG" --repo coder/agent-tty --dir "$DOWNLOAD_DIR" --pattern "$RELEASE_TGZ"
gh release download "$RELEASE_TAG" --repo coder/agent-tty --dir "$DOWNLOAD_DIR" --pattern "${RELEASE_TGZ}.sha256"
sha256sum -c "$DOWNLOAD_DIR/${RELEASE_TGZ}.sha256"
(
cd "$DOWNLOAD_DIR"
sha256sum -c "${RELEASE_TGZ}.sha256"
)

npm install -g --prefix "$INSTALL_PREFIX" "$DOWNLOAD_DIR/$RELEASE_TGZ"
"$INSTALL_PREFIX"/bin/agent-tty version --json
"$INSTALL_PREFIX"/bin/agent-tty --home "$AGENT_TTY_HOME" doctor --json
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" version --json | jq -r '.result.cliVersion'
"$NODE_BIN" "$INSTALL_PREFIX/bin/agent-tty" --home "$AGENT_TTY_HOME" doctor --json | jq '.result.ok'
```

For private releases, authenticated download is the expected verification route.
Expand Down
Loading