Release procedure
Authoritative checklist for cutting a devboy-tools release. Reflects ADR-022 — the workspace ships through two channels:
- npm —
@devboy-tools/cliand per-platform binary subpackages. Primary user-facing channel; this is whatdevboy onboardand the agent plugins assume. - crates.io — every workspace library + the
devboy-clibinary (cargo install devboy-cli). Secondary channel for downstream Rust projects that want to embed devboy components without vendoring source.
Both channels publish from the same v* git tag, in parallel: pushing the tag fans out to two GitHub Actions workflows (.github/workflows/release.yml for npm, .github/workflows/release-crates-io.yml for crates.io).
CI tokens
Two repo secrets drive the two channels. Set both at https://github.com/meteora-pro/devboy-tools/settings/secrets/actions.
The CARGO_REGISTRY_TOKEN env var is read by cargo publish natively — no cargo login step is needed in CI. Generate the token at https://crates.io/settings/tokens, scope it to "All crates" (or an explicit devboy-* allowlist), pick an expiry you're willing to rotate, and paste it into the repo secret.
Before you start
- Decide the target version (workspace-wide, single bump in
[workspace.package].version). - Confirm
mainis green: CI, tests, plugin manifest drift check, andcargo publish --dry-run -p devboy-coreall passed on the merge commit. - Confirm you have:
- Push access to the
meteora-pro/devboy-toolsgit remote (both release pipelines trigger fromv*tags). - Both
NPM_TOKENandCARGO_REGISTRY_TOKENset as repo secrets (see the table at the top of this doc).
- Push access to the
Step 1 — Bump the version
- Update
[workspace.package].versionin the rootCargo.toml. Every member crate inherits it. - Update every
[workspace.dependencies] devboy-* = { version = "X.Y.Z", path = "..." }to the new version. Local builds keep resolving viapath; published consumers resolve viaversion. - Run
cargo check --workspace --all-targetsandcargo test --workspacelocally. - Commit:
chore(release): bump workspace to X.Y.Z. - Open a PR. Wait for CI. Merge.
Step 2 — Tag
Pushing the tag fans out to two parallel GitHub Actions workflows:
.github/workflows/release.yml→ builds platform binaries, signs them, and publishes the npm package + GitHub Release..github/workflows/release-crates-io.yml→ publishes every workspace crate to crates.io in topological order usingCARGO_REGISTRY_TOKEN.
No further manual steps. The workflows are idempotent on retry-after-failure (re-runs from the failed step), but not on already-published versions — see "Recovery" below.
Step 3 — Verify
Once both workflows are green:
- npm page — new version visible
- GitHub Releases — tag with platform binaries attached
https://crates.io/crates/<name>— every devboy-* crate at the new versionhttps://docs.rs/<name>— docs build green (5–10 min)
If a docs.rs build is red, ship a patch version with the doc fix (you can't re-upload the same version).
Manual fallback (rare)
The first ever crates.io release (0.27.0) was run by hand because each crate had to claim its name. From 0.27.x onwards CI handles it; this section is here for break-glass scenarios.
cargo login once with a token that has publish-new + publish-update (or just rely on CARGO_REGISTRY_TOKEN env var if you'd rather not persist the token).
Recovery
If a step fails partway through the wave, stop and investigate. crates.io rejects re-uploads of the same version, so:
- Fix the underlying issue on
main. - Bump the patch version to
X.Y.(Z+1)in[workspace.package].versionand every[workspace.dependencies]entry. - Retag as
vX.Y.(Z+1)and push. - Re-running CI publishes from the failed crate onwards — the earlier ones already on crates.io are skipped automatically when they hit "no token" or "already exists" with
--no-verify. (If they fail loudly, edit the workflow to comment out the already-published layers temporarily.)
Settling delay. crates.io's index sometimes needs ~30 s before a freshly-published crate becomes resolvable as a dependency. The CI workflow has explicit
sleepcalls between layers to handle this; if you're publishing manually and hitno matching package named …, wait 30 seconds and retry.
Step 4 — Verify the wave landed
For each crate that was just published:
https://crates.io/crates/<name>— version page exists, README rendered.https://docs.rs/<name>— docs build is green (docs.rs typically completes within 5–10 minutes).
If a docs.rs build is red, fix the docs and publish a patch version (you cannot re-upload the same version on crates.io).
Step 5 — Post-release hygiene
- Update the "Use as a library" section of the root
README.mdif new crates joined the wave. - Close the release issue if there is one.
- Open a milestone for the next version.