| name | release |
| description | Cut a release of Otto - the one streamlined runbook. Default is a stable patch. Use when the user says "release", "release otto", "ship", "ship stable", "cut a release", "new version", "release:patch", "promote", "release beta", or "/release". Handles stable-patch (default), beta, and promote in one place. |
| user-invocable | true |
Release
The self-contained release runbook. Follow this skill directly - do not re-read docs/release.md for a normal release. docs/release.md is the exhaustive reference; come back to it only for the edge cases flagged below (rollout tuning, retrying a failed build). This keeps a release token-light.
Default = stable patch. "Release", "ship", "ship stable", "release otto" all mean a patch bump from the previous stable. Only run the beta path when the user explicitly says "beta". Never bump minor/major to trigger or retry a build - that needs an explicit "minor"/"major" from the user.
The two-step safety gate (applies always)
- Preparation (agent does this - local, reversible): pre-flight checks, draft changelog, sanity check. Show findings, wait.
- Go-ahead (only after the user says "go ahead" / "ship it"): commit the changelog, run the release command.
Invoking this skill is intent to start, not authorization to publish. If the user asks for a preview, show the prospective changelog and answer questions - do not commit, tag, or run any release:* command until they explicitly authorize. Last-minute changes always need approval. A sanity-check finding is information, not a directive - surface it, the user decides.
Stable patch (the 95% path)
1. Pre-flight (agent, reversible)
Run from a clean tree on main, on the exact commit to be released:
npm run format && npm run lint && npm run typecheck
npm run acp:version-drift:check
npm run release:prepare
Why release:prepare first: it runs npm install --workspaces, which can churn package-lock.json. version:all:* aborts on a dirty tree, and the pre-commit hook rejects a lockfile-only commit. Absorbing the churn now avoids a mid-release mess.
2. Draft the changelog (agent writes it - never hand it off)
Show the drafted entry to the user and wait for approval. Do not commit it yet.
3. Pre-release sanity check (stable only)
Review git diff <latest-release-tag>..HEAD as a last line of defence. Focus on: protocol breaks (WebSocket / agent lifecycle / server↔client), old app client vs. new daemon back-compat (users update daemon first, keep the old app), and regressions. Surface anything risky; the user decides.
4. Go-ahead → commit + release
Only after explicit go-ahead:
git commit -m "docs(changelog): add X.Y.Z release notes"
npm whoami
npm run release:patch
release:patch bumps every workspace, publishes the six @otto-code/* packages, and pushes HEAD + tag. The tag push triggers CI (see step 5).
npm run release:publish needs 2FA - the user always runs it, never the agent. It hits npm's interactive one-time-password/browser-auth gate (EOTP) for each of the six @otto-code/* packages. NEVER attempt the publish or OTP step yourself - don't pass --otp=, don't run the browser auth, don't ask for or enter a code. This is a hard standing rule, not a fallback for when something goes wrong.
Expect npm run release:patch to run through release:check and version:all:patch (bump+commit+tag) and then stop at the EOTP prompt on release:publish - that's the normal, expected outcome, not a failure to work around. When it stops there: tell the user the version commit + tag are ready, and have them run npm run release:publish themselves in their own terminal. Once they confirm all six packages published, resume with the non-credentialed npm run release:push (pushes HEAD + tag, triggers CI).
If the chain fails before publish (e.g. a dirty tree from a stray build artifact, an auth/registry hiccup unrelated to 2FA): fix the underlying cause, then resume - don't re-run the full chain from release:patch. If the version commit + tag already exist, resume at npm run release:publish (user-run) then npm run release:push. If they don't exist yet, resume at npm run version:all:patch.
5. Done - release:push is the last step
Do NOT watch the builds. No background polling loop, no gh run list heartbeat, no scheduled re-check, no "I'll report back when they settle." The user watches CI themselves and has ruled the monitoring a waste of tokens. Report what shipped and end the turn.
The v* tag push triggers, in your repo: Desktop Release, Android APK Release, Android Play Release (AAB → Play internal track), Docker, Deploy App (web app), Release Notes Sync. Deploy Website runs when the GitHub release publishes (stable only).
gh defaults to upstream Otto here - always pass --repo Draek2077/otto-code - for the one-off checks below, or when the user asks about a specific failure later.
- macOS desktop jobs run and produce unsigned artifacts (they no longer skip for want of Apple signing - changed as of 0.6.6). A red mac job is a real failure, not an expected skip. Unsigned means a Gatekeeper warning on first open; that is the known trade, not a defect.
- Spot-check once, if at all:
npm view @otto-code/cli version shows the new version on latest.
Stable rollout is a 36h staged ramp by default; nothing extra needed. To admit everyone immediately or tune the ramp, see docs/release.md → "Staged rollout".
Beta path (only when the user says "beta")
Betas are fast release candidates on the beta channel: npm publishes on the beta dist-tag only, the website download target does not move, and the sanity check is skipped (the beta is the smoke test).
npm run release:beta:patch
npm run release:beta:next
npm run release:promote
Beta changelog: keep one in-place ## X.Y.Z-beta.N - YYYY-MM-DD entry that always covers the full previous-stable→HEAD delta. Each beta bumps that same heading; promotion overwrites it in place (heading → X.Y.Z, date → promotion day). Never leave a stale -beta.N heading or append a new per-beta entry. Verify npm: npm view @otto-code/cli dist-tags (version under beta, not latest).
Promotion runs the stable completion checklist, including the sanity check.
Hard rules
- Never run
npm run release:publish or enter an npm OTP/2FA code yourself. That step is always the user's to run, in their own terminal. See step 4.
- Never bump minor/major to fix or retrigger a build. Build/CI failures are fixed on the current version. To rebuild a target, push a retry tag - see
docs/release.md → "Fixing a failed release build" (Docker-only retries use docker.yml dispatch, never a re-pushed v* tag).
- No code in the changelog commit or the release commit. Code shims are their own reviewed commit.
- "Stable" means stable - don't offer a beta first when the user said stable.
- Releases are always patch unless the user explicitly says "minor"/"major".
When to open docs/release.md
Only for these - everything else is above:
- Staged rollout tuning: instant-admit,
desktop-rollout.yml, custom ramps, releasing during an active rollout.
- Fixing a failed build: retry-tag patterns (
desktop-vX.Y.Z, android-vX.Y.Z, per-platform), Docker dispatch, why workflow_dispatch won't pick up tagged code fixes.
- Watching EAS builds from the terminal; the full completion checklists.