--- name: bump description: Release Pneuma Skills when the user requests a version bump or release. Updates versions and release notes, validates, pushes main, and verifies publishing. --- # /bump — Version Bump & Release Perform a full version bump: sync main, write changelog, refresh top-level docs, bump version, and push. Read `references/release-process.md` before executing the steps; it owns the detailed release checklist and recovery notes. Paths in this procedure are repository-relative unless marked as skill-relative. ## Steps ### 1. Sync main Inspect the branch, status, and diff first. Preserve unrelated work. Include the current task's authorized changes in the release; do not ask the user to resolve your own pending edits. Fetch origin and compare the intended release with `origin/main`. Fast-forward when possible; use an isolated checkout if unrelated edits prevent a safe update. Resolve routine integration issues within scope and ask only when including or changing unrelated work requires a decision. ### 2. Determine version bump Review all commits since the last version tag to decide the bump level per [Semantic Versioning](https://semver.org): - **patch** (x.y.Z): bug fixes, minor improvements, doc updates - **minor** (x.Y.0): new features, new modes, new API endpoints, new viewer capabilities - **major** (X.0.0): breaking changes to contracts, CLI interface, or manifest format Read the current version from `package.json`. Compute the new version. If unsure, ask the user. ### 3. Write CHANGELOG entry Read `CHANGELOG.md` and the git log since the last version bump commit. Write a new version section at the top following the existing format: ```markdown ## [X.Y.Z] - YYYY-MM-DD ### Added - ... ### Fixed - ... ### Improved - ... ``` Rules: - Group changes by category (Added / Fixed / Improved / Changed / Removed) - Each bullet should be a concise, user-facing description — not a commit message copy - Bold the feature name, then describe what it does - Omit categories with no entries - Do NOT include chore/CI/version-bump commits ### 4. Refresh top-level docs Review `README.md`, `README.zh.md`, `AGENTS.md`, and `docs/reference/project-guide.md` against the current codebase state. Fix any contradictions, outdated info, or missing features. This is a **holistic review**, not just appending — trim stale content, update tables, fix version numbers. > `AGENTS.md` is the single source of agent instructions; `CLAUDE.md` is a one-line `@AGENTS.md` import — never write content into it. Specifically check: - `AGENTS.md` `**Version:**` line → update to new version - `AGENTS.md` mode-catalog link → resolves to the maintained README catalog; public entries match registered manifests and hidden modes stay out - `docs/reference/project-guide.md` tech stack table → matches `package.json` dependencies - `docs/reference/project-guide.md` project structure tree → reflects any new/moved directories - `docs/reference/project-guide.md` server API reference → includes any new endpoints - `.claude/rules/*.md` → keep current constraints and topic routing concise; place longer evidence in linked references and correct or retire stale guidance - `README.md` mode table → matches manifest descriptions - `README.md` CLI help section → matches actual CLI output - `README.md` feature list / roadmap → reflects current state Do NOT bloat these files — keep them concise and accurate. Remove outdated entries rather than accumulating. ### 4b. Update mode `changelog` for any mode whose skill version moved If this release bumps any mode's `manifest.ts` `version` field, you MUST also update that manifest's `changelog` map with a matching entry — the launcher's skill-update prompt extracts these bullets to tell the user what changed in the skill they're about to reinstall. Skip this step when no mode skill version changed. For each touched mode: - Add a key under `changelog` matching the new `version` (e.g. `"1.3.0": [ ... ]`). - Each bullet is a one-line user-visible summary, no markdown, no trailing period — they render as `· bullet` in a small UI surface. - Keep at most ~6 bullets per version. The full prose lives in the project `CHANGELOG.md`. - Don't backfill old versions you didn't ship — only annotate the version you're releasing now (and leave any pre-existing entries untouched). **Also grep for the old literal before bumping**, in case a test hardcodes it. Tests under `server/__tests__/` and the `backends/*/[__tests__]/` lifecycle harnesses sometimes pin `webcraftManifest.version`, `slideManifest.version`, etc. with a string equality. Before the commit: ```bash # e.g. webcraft going 1.3.0 → 1.4.0 rg -n '"1\.3\.0"' core server backends modes --glob '*.ts' --glob '*.tsx' ``` Any test hit needs the new string. A miss here is silent locally but fails CI's `Release > Test, Build & Release` step on push and forces a follow-up commit. The desktop auto-updater also surfaces highlights in its "Update Available" / "Update Ready" dialogs, but it parses them straight from the project `CHANGELOG.md` you wrote in step 3 — so a well-formed `- **Bold headline** — description` bullet there is enough; no extra wiring needed. ### 5. Bump version Update all four files in a single commit: 1. `package.json` — `"version": "X.Y.Z"` 2. `desktop/package.json` — the same version 3. `AGENTS.md` — `**Version:** X.Y.Z` 4. `CHANGELOG.md` — new version section (from step 3) Plus any doc changes from step 4. Commit message format: ``` chore: bump version to X.Y.Z — ``` ### 5b. Pre-push sanity — run the test suite Before pushing, run typecheck, the **full** test suite, and the production build: ``` bun run check:guidance bun run typecheck bun run test:all --timeout 60000 bun run build ``` The 60-second per-test timeout matches `release.yml`; media-processing tests can legitimately exceed Bun's default five seconds. Day-to-day work runs `bun run test`; `test:all` is the superset, and the extra time is the backend lifecycle harness spawning real `claude` / `codex` / `kimi acp` processes. Run it here anyway: a release is exactly when "the backends still boot" is worth the wait. `.claude/rules/testing.md` owns the suite table, timings, and how to read a backend lifecycle failure. CI runs the same suite as the gate before tagging + publishing — so a local pass is the cheapest way to avoid burning a CI cycle on a hardcoded-version mismatch or a typing slip that only manifests when something downstream re-imports the manifest. Expected output: ``` NNNN pass NN skip 0 fail ``` A non-zero `fail` count means stop and fix before pushing. The backend lifecycle suites under `backends/*/[__tests__]/` count their `(skip) ... binary not available` lines toward `skip`, not `fail`; those are fine. A `fail` for a hardcoded version expectation usually points back at step 4b's grep — re-run that grep with the previous version string and patch every hit. ### 5c. Publish the catalog modes for this version **Before the push, and after the version in `package.json` is the new one.** Catalog modes — every `modes//` that `modes/distribution.json` does not list under `bundled` — do not travel inside the package. They are downloaded from the CDN from URLs pinned in a generated `modes/catalog.json`, and a prebuilt viewer bundle only runs on the core that built it. So every release republishes every catalog mode from this commit: ``` bun run publish:modes --version X.Y.Z --dry-run # sizes first, uploads nothing bun run publish:modes --version X.Y.Z # build, pack, upload ``` Needs `~/.pneuma/r2.json` (the credentials snapshot publishing already uses). CI holds no R2 credentials and uploads nothing — its `Verify mode catalog` step downloads `official/vX.Y.Z/catalog.json` and HEAD-checks every archive **before the tag and before npm**, so a release whose archives never went up stops there. Pushing before this runs is what makes that step fail. Rules worth knowing before you re-run it: - A key that already holds the same bytes is skipped. - A key whose bytes differ is overwritten **only while `pneuma-skills@X.Y.Z` is not yet on npm** — the "failed gate → fix commit → same version" path. - Once that version is on npm the script refuses: its users resolve those exact URLs. Bump the version instead. - Re-run the whole script, not `--only`: every archive in a release comes from one commit. `references/release-process.md` has the recovery notes. ### 6. Push ``` git push origin main ``` Do NOT create or push tags — CI handles that automatically. ### 6b. Deploy the online player when the release touched it **Automatic — do this on every release whose diff touches the player, without being asked.** CI never deploys the player; it only tags, releases and publishes to npm. The hosted player at `pneuma.deepaste.ai` is a separate Cloudflare Pages surface, and viewers are compiled **into its bundle at build time** — so "the mode is in the whitelist" is not the same as "the online player can play it", and a viewer fix that shipped in npm is still absent from every shared link until this runs. Decide by looking at what actually changed since the previous tag: ```bash PREV=$(git describe --tags --abbrev=0 HEAD^) git diff --name-only "$PREV"...HEAD -- \ core/player-support.ts 'src/player/**' web/ 'modes/*/viewer/**' 'modes/*/domain.ts' 'modes/*/pneuma-mode.ts' \ player.html src/index.css src/fonts.css 'public/fonts/**' scripts/deploy-player.sh ``` Any output at all means deploy. (`domain.ts` and `pneuma-mode.ts` are on the list because a mode's viewer bundle imports them, so a change there reaches the player even when no `viewer/` file moved. `player.html` is the player's own entry, and it imports the same `src/index.css` as the app — which is where the bundled fonts in `public/fonts/` are declared — so those reach the player too. `scripts/deploy-player.sh` stages an explicit file list, not all of `dist-player/`; a change to it only takes effect by running it.) ```bash bash scripts/deploy-player.sh ``` Needs wrangler already logged in on this machine (`npx wrangler whoami`); if it is not, say so and hand the command to the user rather than skipping in silence. The script builds `dist-player/`, then deploys it plus the landing page to the `pneuma-landing` Pages project on the `production` branch. Success ends with `Deployment complete!` and a `*.pages.dev` preview URL; the custom domain `pneuma.deepaste.ai` follows. Two failure shapes worth knowing: - **A whitelisted mode with no viewer in the deployed bundle is a hard error, not a degradation.** The exporter stamps a package `supported: true` from the whitelist in the repo, and the live player's `loadMode()` throws on a mode it was not built with — the user sees "This shared link could not be loaded". - **A stale viewer degrades quietly instead.** The mode loads, but renders with the old build — a new construct comes out as raw markdown, which reads as broken without saying so. ### 7. Report Print a summary: - Previous version → new version - Bump type (patch/minor/major) - Key changes included - How many catalog modes were published and how many bytes of archives - Whether the online player was redeployed, and why or why not - Verify the workflow for the pushed commit, npm version, and expected desktop assets; distinguish a published release from a still-running or failed job