# npm Publishing

**Package**: `amicus` on npm (public)
**Repo**: `github.com/BourbonDog/amicus`

## How to Publish a New Version

```bash
npm version patch   # or minor/major (bumps version + creates git tag)
git push origin main --tags
```

The `.github/workflows/publish.yml` workflow triggers on `v*` tags and publishes automatically.

## What the Workflow Does

1. `npm ci` — install dependencies
2. `npm publish --access public --provenance` — publish with Sigstore attestation (requires `id-token: write` permission)
3. Create a GitHub Release with auto-generated notes
4. Call the Anthropic API to write richer release notes and update the release

**Publish auth: npm Trusted Publishing (OIDC).** Configured on npm for
`BourbonDog/amicus` + `publish.yml` (2026-06-11). The workflow authenticates via
GitHub's OIDC token (`id-token: write`) — no npm token is used. The runner
upgrades npm first (OIDC publishing needs npm ≥ 11.5; Node 22 bundles 10.x).
Provenance is implied under trusted publishing.

**Secrets:**
| Secret | Purpose |
|--------|---------|
| `ANTHROPIC_API_KEY` | Used in the "Generate release notes with Claude" step (direct `/v1/messages` call). Without it the step exits 0 with a warning and keeps the default GitHub release notes. **As of v1.0.0 this secret exists but is empty — set a real key to get Claude-written notes.** |
| `NPM_TOKEN` | **Legacy — no longer read by the workflow.** Kept only until the first successful OIDC publish confirms trusted publishing end-to-end; then delete the secret and revoke the token on npmjs.com. |

## Publishing history / notes

- v1.0.0 (2026-06-11) was published with `NPM_TOKEN` (granular, bypass-2FA). First
  attempt failed `EOTP` because the original token lacked 2FA bypass.
- Trusted Publishing was configured immediately after launch; the next tagged
  release is the first OIDC publish. If it fails, re-add a bypass-2FA granular
  token as `NPM_TOKEN` and restore the `NODE_AUTH_TOKEN` env on the publish step
  (see git history of `publish.yml`).
- After the first successful OIDC publish, optionally tighten the package's
  publishing access on npmjs.com to require trusted publishing.
- The upstream `jrenaldi79/sidecar` repo had its own npm trusted-publisher
  config; it never applied to this repository.

## Release checklist

Run top-to-bottom before `npm version`:

1. **MODEL-NOTES fold-back:** diff the machine-local ledger (`~/.claude/skills/second-opinion/MODEL-NOTES.md`) against the shipped seed (`skills/second-opinion/MODEL-NOTES.md`); cherry-pick generalizable lessons from the local ledger into the shipped seed — **per-section judgment, both directions, never a bulk copy** (the divergence is two-directional: adopt seed-side corrections back into the local ledger too). Merge/prune, keep it tight — no run-ledger numbers, those live in `amicus council stats`. Standing practice per the owner's ruling, 2026-08-03: shipped = curated seed, local = lab notebook.
2. `npm test` green; `npm run lint` clean.
3. **Integration tier, both rails:**
   - `npm run test:integration` (keyless) — must be **0 failures**. This is the same thing the `integration` job in `ci.yml` runs on every push, so it should already be green.
   - `npm run test:integration:live` **with real keys** — must be **0 failures**. This is the only step in the whole release that exercises the paid E2E suites (real CLI/MCP sessions against a real LLM), so it is the only thing that catches a break in the spawn/session/MCP lifecycle or a dead model alias. **It spends money — expect that, and do not skip it because the keyless run was green:** keyless *skips* those suites entirely, so a green keyless run says nothing about them. Locally: `npm run test:integration:live` with `OPENROUTER_API_KEY` set (or a key in `~/.config/amicus/.env`). In CI: dispatch `.github/workflows/integration-live.yml` from the Actions tab. The script carries `--runInBand` as of v4.4.1 (REL-1) and the CI job runs the same script, so **no extra flag is needed on either surface** — if you find an older note telling you to append `-- --runInBand`, it is stale. Expect ~2 minutes rather than ~40 s; that is the serialization, not a hang (see [testing.md](testing.md#which-gate-runs-which-tier)).
   - A suite that reports *skipped* here means the key was not picked up. That is a misconfigured run, not a pass — fix it and re-run.
4. `npm run generate-docs:check` passes (CLAUDE.md markers + cross-links).
5. Bump `.claude-plugin/plugin.json` `version` to match `package.json` (no script syncs it). Also bump `server.json` — both `.version` and `.packages[0].version` — to the same value (no script syncs this either). Also bump the `status --json` **example blocks** in `README.md` and `docs/usage.md` (`"version": "x.y.z"`) — they are drift-test-pinned to `package.json` by `tests/docs-quick-sync.test.js` and have now missed the cut twice (v2.1.0 and v2.2.0).
6. Update `CHANGELOG.md` (move Unreleased → the new version).
7. `npm version <x.y.z> --no-git-tag-version` + plugin.json lockstep + server.json lockstep (`.version` and `.packages[0].version`), single `chore(release): vX.Y.Z` commit, then push main + tag (publish.yml does the rest — see the canonical ritual in Phase 2 of the 2026-07-01 review-execution plan). If you forget the server.json bump, `tests/scripts/package-manifest.test.js` fails the suite (`server.json versions stay in lockstep with package.json`) — that's your safety net, but don't rely on it; do the bump.

- [ ] **Prune the rev's plan docs.** Delete `docs/superpowers/plans/*` belonging to this release in the release-cut commit. Specs in `docs/superpowers/specs/` are permanent and stay. Plans are working documents — they are committed on-branch so they cannot be silently rewritten mid-build, and removed at the cut so `main` never accumulates prescriptions that are false the moment they ship. Git history remains the audit trail. `npx jest tests/docs-plan-refs.test.js` fails if anything still cites a specific plan.
