---
name: prepare-release
description: "Use this skill whenever preparing agentsmesh for an npm release — whether first publish, patch, minor, or major. Triggers on: 'prepare release', 'ready to publish', 'ship version', 'release prep', 'get this to npm', 'bump version', 'cut a release', 'what's needed to publish'. Runs a strict ordered checklist: test suite health → timing hardening → CI/CD presence → community health files → changeset entry → package contents → README badges → final gate → generate to targets. Releases are driven by changesets — never hand-edit `package.json` `version` or `CHANGELOG.md`. Do not skip phases or work from memory; execute every phase in order and fix gaps before moving on."
---

## Purpose

# Prepare Release

You are acting as the release engineer for agentsmesh. Your job is to get the repo into a state that is safe, honest, and ready for `npm publish`. Work through each phase in order. Do not mark a phase complete until you have verified it, not just assumed it.

## Releases are changesets-driven — read this first

Every user-facing change ships through a changeset. **Do not** hand-edit `package.json` `version` or `CHANGELOG.md` — both are generated by `changeset version` and any manual edit will be silently overwritten the next time the release PR rebases. The skill exists to make sure the changeset is honest, the CI gates are green, and the publish workflow is actually wired up.

The flow:

1. All gates below pass locally.
2. A `.changeset/<slug>.md` file describes the change with a `patch | minor | major` bump and a user-facing summary. Commit it.
3. Push to `master` (or merge a feature branch into `master`).
4. `publish.yml` triggers — `changesets/action` detects the pending changeset and **opens a "chore: version packages" PR** that bumps `package.json` and rewrites `CHANGELOG.md`.
5. Review the version PR — confirm the bump and the rendered CHANGELOG section match intent. Edit the changeset summary or add a new changeset (then re-push) if the rendered output is wrong; never edit `package.json`/`CHANGELOG.md` directly on the version PR.
6. Merge the version PR → `publish.yml` runs again, sees no pending changesets, executes `pnpm release` (`pnpm build && changeset publish`), and publishes to npm via npm trusted publishing. GitHub creates the Release and tag automatically.

Prerequisites in repo settings:

- **Settings → Actions → General → Workflow permissions**: enable "Allow GitHub Actions to create and approve pull requests".
- **npm package settings → Trusted publishers**: this repository + `.github/workflows/publish.yml` must be listed for the `agentsmesh` package so OIDC can publish without `NPM_TOKEN`.
- **Secrets**: `CODECOV_TOKEN` for the coverage badge.

If any of those are missing, fix them now — a green local gate cannot rescue a misconfigured publish workflow.

---

## Phase 1 — Test Suite Health

Run the full suite and confirm everything is green before touching anything else.

```bash
pnpm test
```

If there are failures, fix them first. Do not proceed with a red suite.

Then run typecheck and lint:

```bash
pnpm typecheck
pnpm lint
```

All three must be clean.

### Watch test timing (known CI risk)

The watch tests are timing-sensitive and reliably flake on CI runners slower than a developer laptop. Before declaring the suite healthy, check these specific timeouts in the watch tests:

| File | What to check | Safe CI value |
|------|--------------|---------------|
| `tests/unit/cli/commands/watch.test.ts` | `vi.waitFor` timeout args | ≥ 3000 ms |
| `tests/unit/cli/commands/watch.test.ts` | idle stability `setTimeout` | ≥ 2000 ms |
| `tests/integration/watch.integration.test.ts` | startup `waitForFile` timeout | ≥ 15000 ms |
| `tests/integration/watch.integration.test.ts` | post-change `setTimeout` | ≥ 1500 ms |
| `tests/e2e/watch.e2e.test.ts` | startup `setTimeout` | ≥ 3000 ms |
| `tests/e2e/watch.e2e.test.ts` | post-change `setTimeout` | ≥ 1500 ms |

Also verify `vitest.config.ts` has global guards:

```ts
testTimeout: 15_000,
hookTimeout: 10_000,
```

If any of these are missing or too low, update them now. The watch debounce is 300 ms plus generate time; tight timeouts that work on a fast local machine will fail on a 2-core CI runner.

---

## Phase 2 — CI/CD Workflows

Check that both workflow files exist and are correct:

- `.github/workflows/ci.yml` — runs on every push and PR to `master`.
- `.github/workflows/publish.yml` — runs the changesets release flow on push to `master`.

### ci.yml must include these steps in order

1. `pnpm install --frozen-lockfile`
2. `pnpm audit --prod --audit-level=high` — catches high/critical vulns in production deps only.
3. `pnpm lint`
4. `pnpm typecheck`
5. `pnpm build` — must come **before** any test job that includes integration files which exec `dist/cli.js` (e.g. `import.integration.test.ts`, `watch.integration.test.ts`, `generate-process-lock.integration.test.ts`).
6. `pnpm test` — full unit + integration suite.
7. `pnpm test:e2e` — must come after build (it self-builds via `pnpm build && vitest run --config vitest.e2e.config.ts`); never run e2e in parallel with another build because they share `dist/`.
8. Coverage job (separate matrix entry): `pnpm test:coverage` with Codecov upload (`fail_ci_if_error: false` so fork PRs don't break).

The quality matrix must include `ubuntu-latest` × Node 20/22/24, `macos-latest` × Node 22, and `windows-latest` × Node 22. Use pnpm 10 + `cache: pnpm` in `setup-node`. Both workflows must set `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true` at the job level to suppress the Node 20 deprecation warning.

### publish.yml must use changesets/action@v1 and trigger on push to master

```yaml
on:
  push:
    branches: [master]

concurrency:
  group: release
  cancel-in-progress: false

jobs:
  release:
    runs-on: ubuntu-latest
    env:
      FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
    permissions:
      contents: write
      pull-requests: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@v4
        with:
          version: 10
      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: pnpm
          registry-url: "https://registry.npmjs.org"
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      - name: Create release PR or publish
        uses: changesets/action@v1
        with:
          publish: pnpm release
          title: "chore: version packages"
          commit: "chore: version packages"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

The job needs `id-token: write` for npm trusted publishing/provenance and `pull-requests: write` to create the version PR. If either workflow file is missing or malformed, fix it now.

---

## Phase 3 — Community Health Files

These must exist. Check each one:

| File | Minimum content |
|------|----------------|
| `SECURITY.md` | Supported versions table, private advisory link, response SLA |
| `CONTRIBUTING.md` | Prerequisites, dev commands, TDD rule, commit format, **changeset requirement**, PR checklist |
| `.github/ISSUE_TEMPLATE/bug_report.yml` | version, node, repro, expected behavior fields |
| `.github/ISSUE_TEMPLATE/feature_request.yml` | problem + solution fields |
| `.github/ISSUE_TEMPLATE/config.yml` | `blank_issues_enabled: false`, security advisory link |
| `.github/pull_request_template.md` | type-of-change checklist; **must include a "changeset added" checkbox** alongside TDD + CI |

If any are missing, create them. Keep them short and factual — no marketing copy.

---

## Phase 4 — Changeset Entry (the only place release notes are authored)

Verify changesets is wired:

1. `.changeset/config.json` exists with `"access": "public"` and `"baseBranch": "master"`.
2. `@changesets/cli` is in `devDependencies`.
3. `package.json` has these scripts:
   ```json
   "changeset": "changeset",
   "version": "changeset version",
   "release": "pnpm build && changeset publish"
   ```
4. Lockfile is current (`pnpm install` has been run).

### Author the changeset for this release

Run:

```bash
pnpm changeset
```

Or write the file directly at `.changeset/<slug>.md` using this format:

```markdown
---
'agentsmesh': minor
---

<one-paragraph user-facing summary, then optional follow-up paragraphs grouping
Added / Changed / Fixed / Removed material if the release spans many themes>
```

**Bump rules**:

- `major` — breaking changes to the CLI flags, canonical schema, public API surface, or generated artifact contract that an existing user could rely on. Write a migration paragraph.
- `minor` — new targets, new canonical features, new public exports, new commands, new flags that are additive. New runtime platform support also goes here.
- `patch` — bug fixes, doc-only changes, internal refactors with no user-visible behavior change, dependency bumps that don't change behavior.

**Quality bar for the summary** (this paragraph becomes the CHANGELOG entry, so write it like a CHANGELOG entry, not like a commit message):

- Lead with the capability, not the file path. `Native Windows support is now first-class.` not `Added windows-path-safety.ts.`
- Quote the user-visible artifact (`agentsmesh import --from windsurf`, `installs.yaml`, `.changeset/<slug>.md`) so the entry is greppable.
- If multiple themes ship together, group them as separate paragraphs — Added / Changed / Fixed / Removed framing inside one summary is fine, headings inside the changeset body are not (they'd nest inside `### Minor Changes` after rendering).
- If the change is purely internal, state that explicitly (`Internal-only:` prefix) and use `patch`.

### Verify before commit

```bash
pnpm exec changeset status
```

Confirm the bump type and the package list match intent. Then `git add .changeset/<slug>.md` and commit alongside the work it describes (one PR, one or more changesets, no orphan changesets and no orphan code).

**Do not** edit `package.json` `version` or `CHANGELOG.md` in this commit. Both are generated by the version PR.

---

## Phase 5 — Package Contents

Run a dry-run pack and inspect what would be published:

```bash
pnpm pack --dry-run
```

The tarball must contain only what `package.json` `files` declares plus the always-included files (`package.json`, `README.md`, `LICENSE` if present alongside). Source files, test files, fixtures, `.agentsmesh/`, `docs/`, `tasks/`, and `tsconfig.json` must not appear. The `files` field should be:

```json
"files": ["dist", "schemas", "README.md", "CHANGELOG.md", "LICENSE"]
```

If unexpected files appear, tighten `files` or add a `.npmignore` entry. Re-run `pnpm pack --dry-run` until the manifest is clean.

---

## Phase 6 — README Badges

The README must have these four badges immediately after the `# AgentsMesh` heading:

```markdown
[![CI](https://github.com/sampleXbro/agentsmesh/actions/workflows/ci.yml/badge.svg)](https://github.com/sampleXbro/agentsmesh/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/agentsmesh.svg)](https://www.npmjs.com/package/agentsmesh)
[![Coverage](https://codecov.io/gh/sampleXbro/agentsmesh/branch/master/graph/badge.svg)](https://codecov.io/gh/sampleXbro/agentsmesh)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
```

The npm version badge will pick up the new tag once `changeset publish` runs. Coverage requires `CODECOV_TOKEN` to be set as a repo secret.

---

## Phase 7 — Final Gate

Run the full test suite one more time with coverage to confirm nothing broke since Phase 1:

```bash
pnpm test
pnpm typecheck
pnpm lint
pnpm test:coverage
pnpm build
```

Coverage thresholds are set in `vitest.config.ts`:

```
lines: 90%, functions: 90%, branches: 84%
```

If coverage drops below threshold, the CI run will fail. Either add missing tests or, if coverage dropped because of legitimately untestable I/O code, add the file to the `coverage.exclude` list in `vitest.config.ts` with a comment explaining why.

---

## Phase 8 — Generate to All Targets

Once all phases pass, sync the canonical config to every configured target:

```bash
node dist/cli.js generate
```

Then verify the lock file is in sync:

```bash
node dist/cli.js generate --check
```

If `generate --check` reports drift, commit it as part of the changeset commit (or as a separate `chore(generate): refresh target artifacts` commit, whichever the repo's recent history prefers). Never push a release with a dirty lock.

---

## Output

After all phases, produce a release readiness report:

```markdown
## Release Readiness — agentsmesh (changeset: <slug>, bump: patch|minor|major)

| Phase | Status | Notes |
|-------|--------|-------|
| Test suite | ✓/✗ | |
| Watch timing | ✓/✗ | |
| CI workflows | ✓/✗ | |
| Community files | ✓/✗ | |
| Changeset entry | ✓/✗ | |
| Package contents | ✓/✗ | |
| README badges | ✓/✗ | |
| Final gate | ✓/✗ | |
| Generated to targets | ✓/✗ | |

### Remaining actions before publish
- [ ] "Allow GitHub Actions to create and approve pull requests" enabled in repo Settings → Actions → General
- [ ] npm trusted-publisher mapping points at this repository and `.github/workflows/publish.yml`
- [ ] `CODECOV_TOKEN` repo secret is set
- [ ] Push the changeset commit → action opens the "chore: version packages" PR
- [ ] Review the rendered CHANGELOG section + bump in the version PR; merge → action publishes to npm
```

---

## Principles

- **Changesets are the only release-notes authoring surface.** If you find yourself opening `CHANGELOG.md` or bumping `package.json` `version`, stop — write a changeset instead.
- **Fix, don't skip.** If a phase has a gap, close it before moving on. A partial release prep is worse than no prep.
- **Verify, don't assume.** Read the actual files. Run the actual commands. Don't report a phase as done because you think it was done earlier.
- **Users first.** Changeset summaries describe what users can now do, not what commits were merged.
- **Lockfile is truth.** `generate --check` must report in sync before the changeset commit. If it is dirty, there is a mismatch between canonical and generated — investigate before shipping.