# Releasing jumperless-mcp
The manual runbook for cutting a new release. CI auto-builds binaries and
creates the GitHub Release page on tag push; **crates.io publish is a
separate manual step** so the irreversible action stays explicit.
## Versioning
- `v0.x.y` (pre-1.0): minor bumps for new tools or breaking API changes;
patch bumps for bug fixes.
- `v1.0.0` and beyond: standard semver.
- Tag the same commit that's on `main`.
## Pre-flight checklist
- [ ] All changes merged to `main`
- [ ] `CHANGELOG.md` has a section for the new version with user-facing notes
- [ ] `Cargo.toml` `version` bumped to match
- [ ] `cargo test` passes locally
- [ ] `cargo fmt --check` clean
- [ ] `cargo clippy --all-targets -- -D warnings` clean
- [ ] README + tutorials still accurate for any new tools / changed signatures
## Step 1: tag + push
```
git checkout main
git pull
git tag vX.Y.Z
git push origin vX.Y.Z
```
The tag push triggers `.github/workflows/release.yml`:
- Builds binaries on `windows-latest` / `macos-latest` / `ubuntu-latest` in parallel
- Attaches the three archives to a new GitHub Release page
- Auto-generates release notes from commits since the previous tag
- Total runtime: ~5–8 min
Watch progress at <https://github.com/LesbianVelociraptor/jumperless-mcp/actions>.
## Step 2: publish to crates.io (manual)
Once the GitHub Release looks correct:
```
# From a clean checkout of the tagged commit
git checkout vX.Y.Z
# Sanity-check what will be uploaded
cargo package --list
# Validate without uploading
cargo publish --dry-run
# Pull the trigger — IRREVERSIBLE for this version
cargo publish
```
Within ~30s, <https://crates.io/crates/jumperless-mcp> shows the new version.
### One-time setup (first publish only)
1. Sign in at <https://crates.io> via GitHub
2. Generate an API token at <https://crates.io/me>
3. `cargo login <token>` saves it to `~/.cargo/credentials.toml`
(`%USERPROFILE%\.cargo\credentials.toml` on Windows)
### Common gotchas
| `description must be no longer than 200 characters` | Trim `Cargo.toml` `description` field |
| `crate version `X.Y.Z` is already uploaded` | Bump version — you can never re-upload the same version |
| `target/` shows up in `cargo package --list` | Add to `.gitignore`; `cargo package` honors it |
| README image links broken on crates.io | Use absolute GitHub URLs (`https://raw.githubusercontent.com/...`) instead of relative paths |
## Step 3: announce
- Update the GitHub Release notes if the auto-generated ones miss anything important
- Ping in the Jumperless Discord with the release link
- If the release closes user-reported issues, comment-close them: `Fixed in vX.Y.Z`
## Yanking a broken release
If a released version has a critical bug:
```
cargo yank --version X.Y.Z
```
Yank hides the version from new `cargo install` / dependency resolution but
keeps it resolvable for existing `Cargo.lock` files (so downstream builds
don't break). Reverse with `cargo yank --version X.Y.Z --undo`.
Yank is the only undo. There is no "delete" — once published, the `.crate`
file lives in the registry permanently.
## Later: automating crates.io publish
When you're comfortable with manual publishes, consider adding a
`.github/workflows/crates-publish.yml` with a `workflow_dispatch` trigger.
That gives you a "Run workflow" button in the Actions UI — still explicit
(never auto-fires on tag), but no local `cargo publish` needed. Until then,
keep this manual.