بنقرة واحدة
release
Cut a Tandem release — six-surface version bump, changelog, tag, GitHub Release publish, smoke checklist
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Cut a Tandem release — six-surface version bump, changelog, tag, GitHub Release publish, smoke checklist
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Use when tandem_* MCP tools are available, the user asks about Tandem document editing, or iterating on text collaboratively. Provides workflow guidance, annotation strategy, and tool usage patterns for the Tandem collaborative editor.
Start Tandem dev environment (server + client) and verify MCP connection
Generate a Keep a Changelog entry from git log since the last tag
Capture README screenshots of the Tandem editor UI via Playwright + MCP
Debug Playwright E2E test failures — port conflicts, server startup, test isolation, and post-mortem analysis
Run Playwright E2E tests safely (warns about dev server conflicts)
| name | release |
| description | Cut a Tandem release — six-surface version bump, changelog, tag, GitHub Release publish, smoke checklist |
| disable-model-invocation | true |
Codifies the release sequence used for v0.14.3 / v0.15.0 / v0.16.0. The version
bump has SIX surfaces, none of which bump automatically. Surfaces 1–4 are
CI-guarded by tests/plugin/plugin-version-pin.test.ts (any divergence from
package.json fails CI); surfaces 5–6 are not guarded — this skill is what
prevents them drifting.
package.json — version (the reference value the CI guard compares against)
.claude-plugin/plugin.json — FOUR values in one file: the top-level
version, plus the tandem-editor@<version> npx pins in
mcpServers.tandem.args, mcpServers.tandem-channel.args, AND the
experimental.monitors[].command shell string
(npx -y tandem-editor@<version> monitor — added #1201; it lives in a
command string, invisible to the args-array walker, so it has its own
guard case in plugin-version-pin.test.ts. Miss it and the plugin monitor
stays pinned to the previous, dormant version)
src-tauri/Cargo.toml — [package].version (the Cowork installer pins its
npx spec via env!("CARGO_PKG_VERSION"); stale = ships a build pinning the
WRONG published npm version)
src-tauri/tauri.conf.json — version (drives desktop artifact names
Tandem_<version>_x64.dmg, … AND the tauri-action __VERSION__ that
names/targets the GitHub release; stale = installers uploaded onto the
PREVIOUS release — this bit v0.15.0, clobbering v0.14.3's published
artifacts before the guard was added)
package-lock.json — regenerate, never hand-edit:
npm install --package-lock-only
Unguarded, and nothing in CI catches it — npm ci will not. Its
lockfile-sync check covers dependencies only: with the lock left stale,
bumping the root version exits 0, and even changing the root name exits
0 (verified on npm 11.12.0; only an unlocked dependency makes it fail).
Regenerate anyway — the lock's root version is committed, so skipping it
ships a lockfile disagreeing with package.json and leaves the next local
npm install to rewrite the file and dirty the tree.
src-tauri/Cargo.lock — refresh and commit:
cargo update --manifest-path src-tauri/Cargo.toml -p tandem-desktop
Do not add --precise <version>. tandem-desktop is a local package,
and for a local/workspace package --precise is silently ignored: asking
for a version the manifest doesn't have exits 0 and changes nothing. The
version comes from Cargo.toml, so bump the manifest (surface 3) and let
plain -p relock it.
Hygiene only, NOT a breakage surface: nothing verifies this lockfile —
ci.yml runs a bare cargo test --manifest-path src-tauri/Cargo.toml with
no --locked, so cargo silently regenerates a stale lock and CI stays
green. (tauri-webdriver.yml does pass --locked, but only to
cargo install for its own tooling — unrelated to src-tauri/Cargo.lock.)
The tree still goes dirty on the next local build if you skip this.
Bump all six surfaces (above), then run the catch-all: grep the tree for the OUTGOING version and confirm zero source stragglers remain:
git grep -F <old-version> -- ':!CHANGELOG.md' ':!*.lock' ':!package-lock.json' ':!tests/**' ':!docs/**'
-F is load-bearing: unescaped, the dots are regex wildcards, so a
version like 0.15.0 also matches oklch(0.15 0.01 …) in index.html — a
pure false positive. On the most recent release, -F plus ':!docs/**'
took this from 33 matching lines down to 9. (CHANGELOG keeps history;
lockfiles carry dep versions; test fixtures and docs cite versions as
prose — all expected.)
Read the survivors, don't just count them — they are not all bugs.
Expect three kinds: the six surfaces themselves (before you bump them);
deliberate prose naming the outgoing version as history (this skill's
header, CLAUDE.md's Status); and source comments, which the exclusions do
NOT hide — src/server/license/gate-flag.ts carries a
Default: false (v<version>) marker. Judge each one; a straggler is a hit
that still pins the old version rather than describing it.
Ask Bryan to run /changelog to generate the Keep a Changelog entry, then
finalize the ## [<version>] section in CHANGELOG.md (the in-app View
Changelog button serves this file). You cannot invoke it yourself — the
changelog skill sets disable-model-invocation: true, which makes it
user-invocable only.
Verify the full test suite is green — plugin-version-pin.test.ts proves
surfaces 1–4 agree (it also checks plugin.json's pinned npx specs);
tests/plugin-manifest.test.ts additionally fails if package.json and
plugin.json diverge — treat either failure as "you bumped some, not all":
npm run typecheck && npm test -- --run
Pass --run. The test script is bare vitest, whose watch default is
!isCI && process.stdin.isTTY && !isAgent — so it exits on its own in CI,
when piped, and for an agent, but sits in watch mode in Bryan's interactive
terminal. --run makes that unconditional; ci.yml and .husky/pre-push
both pass it.
Ship the bump through the normal flow: branch → PR → CI green → merge → verify master CI green on the merge commit.
Tag the release on the master tip and push the tag:
git tag -a v<version> -m "Tandem v<version>" && git push origin v<version>
Use -a (annotated). Bare git tag v<version> creates a lightweight tag
— git cat-file -t reports commit, not tag — which would break the
pattern: every release tag since v0.11.1 is annotated. (Older tags are
mostly lightweight; that is history, not the standard to copy.)
The v* tag push triggers .github/workflows/tauri-release.yml: the signed
desktop build matrix plus a release-check summary job, creating a DRAFT
GitHub Release (releaseDraft: true) with artifacts + latest.json. The
tag alone does NOT publish to npm. (HUSKY=0 on the tag push is fine — the
commit is already CI-green.)
Wait for every matrix build and release-check to go green, then publish
the draft:
gh release edit v<version> --draft=false --latest
Publishing is the npm trigger: .github/workflows/publish.yml fires on
release: [published] and runs npm publish --provenance. If macOS
notarization 403s on "agreement missing/expired," that is an Apple
legal-agreement lapse only the Account Holder (Bryan) can clear at
developer.apple.com / App Store Connect — re-run the failed jobs after he
signs.
Walk docs/release-smoke-checklist.md: CI signal first (matrix +
tauri-webdriver.yml + macOS launch smoke), then real installers on real
machines — SmartScreen/Gatekeeper, updater from the previous version,
file associations, npm install -g tandem-editor@<version> + tandem doctor. Record the outcome (platforms covered, anything skipped) on the
release PR or tracking issue — an unstated skip reads as "verified".
Update project memory: the CLAUDE.md Status section (what shipped in this version) and the project memory SHIPPED entry (per the archive rotation discipline).