The gate between "code is merged on main" and "vX.Y.Z tag exists".
- Tests green.
npm testandnpm run test:coverageboth pass at the candidate HEAD. Per-file thresholds in vitest.config.ts are enforced, not advisory. - Typecheck green.
npm run typecheckpasses across all four packages. - No uncommitted work.
git statusis clean. Pending changes either land before the release commit or defer to the next version. - CHANGELOG entry present. A
## [X.Y.Z] — YYYY-MM-DD — <title>section for the candidate version exists in CHANGELOG.md with Added / Changed / Removed / Security / Tests / Release gate sub-sections in the style of the 0.7.x and 0.8.x entries. - Secret-leak gate clean.
node scripts/assert-no-secret-leak.mjs .test-artifacts/vitest.logexits 0. Zero matches for known bearer / token / OAuth-code shapes.
A phase-scoped manual checklist lives in docs/smoke-tests.md. Every versioned release is gated on a three-platform pass (Windows 11, macOS 14+, Ubuntu 22+) OR a recorded waiver per platform.
Three-platform pass — preferred path:
- Create three dated evidence files under docs/smoke-evidence/ in the form
YYYY-MM-DD-vX.Y.Z-<os>.md, one per target OS. Skeletons for 0.8.6 already exist at2026-04-XX-v0.8.6-{win11,macos14,ubuntu22}.md— renameXXto the actual day. - Run the checklist on each OS. Check every applicable box in the evidence file; paste terminal output / screenshots for items that require it.
- Sign-off field filled in on every file.
Waiver path — acceptable but must be explicit:
- One fully-green platform is still required. You cannot ship with every platform waived.
- Each waived platform carries a distinct reason in its evidence file AND in the release commit body. Acceptable reasons: hardware unavailability, upstream dependency breakage (e.g. cloudflared auth server down), environment-specific blocker (no Cloudflare zone → can't smoke cf-named). NOT acceptable: "no time", "unit tests passed so it's probably fine".
- For external-API smokes (Phase 8.4 cf-named, tunnel providers), the waiver language in the release commit body must be stronger than code-only waivers because the risk is external and can't be regression-caught by CI.
Consolidated smokes — when multiple versions defer:
Releases 0.8.2 → 0.8.5 all deferred their smokes per the Phase 8 completion execution design. The smoke for 0.8.6 is therefore a consolidated pass covering Phase 8.5 → 8.8 in a single session. Always prefer a per-release smoke; fall back to a consolidated one only when the accumulated scope is manageable in one sitting.
npm run package:vsixThis runs npm run build (shared → mcp-server → webview → extension) followed by prepare-package-deps (copies externals into dist/node_modules/) and vsce package. Verify the output is at packages/extension/perplexity-vscode-X.Y.Z.vsix.
Before signing off on the VSIX, spot-check the invariants:
- Express 4.x. VS Code extensions depend on the bundled daemon; express 5.x changes middleware promise semantics and breaks the OAuth routes.
Expect a string starting with
unzip -p packages/extension/perplexity-vscode-X.Y.Z.vsix \ extension/dist/node_modules/express/package.json | jq -r .version4.. If it starts with5., halt the release, revert the offending dependency bump, and re-pack. dist/mcp/server.mjscontainsattachToDaemon(re-export from 0.8.0 — proves the stdio launcher's daemon-proxy path reached the bundle).- Size is in the ~11-12 MB band (significantly larger usually means a new native binary was inadvertently bundled; significantly smaller usually means an external went missing).
Both packages share a version number and must be bumped together.
packages/extension/package.json—versionpackages/mcp-server/package.json—version
Extension's emit-version.mjs script copies the version into the bundle at build time, so the bump must land before npm run package:vsix for the version stamp to be correct.
Use a single commit that carries the CHANGELOG entry + version bumps + any smoke-evidence files. Commit message form:
release(X.Y.Z): <short title matching CHANGELOG heading>
<1-3 lines on what shipped + any waivers>
If any platform is waived, include a ## Smoke waivers section in the commit body listing each waived platform with its reason:
## Smoke waivers
- ubuntu22: hardware unavailable this cycle; covered by CI integration tests on ubuntu-latest runner.
- macos14: skipped (no macOS hardware available); covered by hermetic unit tests on darwin-arm64 runner.
git tag vX.Y.Z
git push origin main
git push origin vX.Y.ZStandard workflow: feature branches + PRs + squash-merge, with the release commit + tag driven from the PR landing.
- Verify the tag appears in the remote.
- If the release is for the npm-published
perplexity-user-mcppackage (not just the VSIX), runnpm publish --workspace packages/mcp-serverfrom a cleannpm install && npm run buildstate. The VSIX and npm package version must match. - Paste the release commit SHA back into each evidence file's "Release commit SHA" field.
- Close any phase-scoped planning docs under docs/superpowers/plans/ that are fully delivered by this release.
- Regressions discovered during smoke ship as the next patch version (e.g. 0.8.3 → 0.8.4 hotfix). Do NOT tag the failed candidate.
- If the failed candidate was already tagged (e.g. you ran the tag before the smoke pass — don't do this), the recovery is: land the fix on main, bump patch, re-run smoke, tag the new patch. Never force-push or delete tags on shared remotes.
- Document the regression + fix in the next version's CHANGELOG
### Fixedor### Changedsection so the git history reads clearly.
- docs/smoke-tests.md — the per-phase manual checklist.
- docs/smoke-evidence/ — dated evidence files from prior smokes.
- CLAUDE.md "Repo-specific working rules" — the canonical per-release policy statement.
- CHANGELOG.md — the release notes.