Goal
Port Leo's automated publishing flow to snarkVM so that merging a version-bump PR into staging automatically publishes the workspace crates to crates.io and cuts a GitHub release — no manual cargo publish, no long-lived crates.io tokens.
Key difference from Leo: snarkVM is lockstep-versioned (all 64 crates carry the same literal version, currently 4.7.3). We want one git tag (v4.7.4) and one GitHub release per workspace version — not Leo's per-crate tags (leo-lsp-v4.0.2). release-plz is package-centric, so this needs explicit config (see step 1).
Reference (Leo)
snarkVM specifics to account for
- 64 workspace crates, lockstep-versioned — every crate has a literal
version = "4.7.3" (no version.workspace, no [workspace.package] block). Published as snarkvm-*; the root crate is snarkvm.
- Default branch is
staging (Leo uses master). All workflow triggers/refs below must target staging.
- Library workspace — no binary artifact releases — so Leo's
release-crate.yml binary-dispatch half is out of scope. We only need crates.io publishing + a single GitHub release/tag.
- Owner org on GitHub and crates.io:
ProvableHQ.
Steps
1. Add release-plz.toml — configure single tag + lockstep
release-plz defaults to one tag/release per package in a multi-crate workspace. To get a single unified tag/release:
- Disable tags + releases workspace-wide, then re-enable them on one umbrella crate (the root
snarkvm):
[workspace]
git_tag_enable = false
git_release_enable = false
[[package]]
name = "snarkvm"
git_tag_enable = true
git_tag_name = "v{{ version }}"
git_release_enable = true
git_release_name = "v{{ version }}"
- Keep all crates in lockstep with
version_group (assign every workspace member to the same group so they always bump to the same version together).
- release-plz still publishes all crates to crates.io regardless of tag config; tags/releases are only created for the umbrella crate.
- Decide changelog strategy (single workspace changelog vs. none) — release-plz generates per-crate changelogs by default; may want to disable or consolidate.
2. Add .github/workflows/publish-crates.yml
Port from Leo's publish-crates.yml, adjusted for snarkVM:
- Trigger on
push to staging (paths: Cargo.toml, **/Cargo.toml, release-plz.toml, the workflow file), plus workflow_dispatch with a dry_run input.
concurrency group to prevent overlapping publishes.
dry-run job: release-plz/action@v0.5, command: release, dry_run: true.
publish job permissions: contents: write (tag + release) and id-token: write (OIDC for Trusted Publishing).
- Guard manual dispatches so they only run from
staging.
- Drop Leo's "Dispatch Binary Release Workflows" step (no binary crates here).
3. Configure crates.io Trusted Publishing (required, per crate, one-time)
Trusted Publishing uses GitHub OIDC instead of a crates.io API token. It is inherently per-crate — there's no workspace-wide setting — so it must be configured once for every already-published snarkvm-* crate. This is unavoidable but is a one-time, scriptable setup (it does not mean per-crate tags at release time).
For each crate, on crates.io → crate Settings → Trusted Publishing → Add:
- Owner:
ProvableHQ
- Repository:
snarkVM
- Workflow filename:
publish-crates.yml
- Environment: (leave blank unless we add a GitHub Environment to the publish job)
64 crates — script this against the crates.io API and track which are done. Requires crates.io owner permissions on every snarkvm-* crate.
4. Bootstrap any brand-new crates
crates.io Trusted Publishing can only be configured on a crate name that already exists. Any new snarkvm-* crate needs one initial manual cargo publish (with a token) to reserve the name, after which Trusted Publishing can be set up and the workflow takes over. Document this.
5. Single GitHub release / tag
- The umbrella-crate config in step 1 yields one tag
v{version} and one GitHub release per workspace version, with generated notes.
- Skip Leo's compatibility-metadata job unless we specifically want machine-readable release metadata.
6. Documentation
- Add/extend a
RELEASING.md: the normal path (bump workspace version PR → merge to staging → auto-publish all crates + single release), how to dry-run (workflow_dispatch), how to backfill, the Trusted Publisher setup, and the new-crate bootstrap.
7. Validation
actionlint on the new workflow.
workflow_dispatch with dry_run: true → confirm release-plz reports the expected unpublished crates and a single planned tag, without publishing.
Open questions
- Confirm the umbrella-crate (
snarkvm) single-tag pattern works end-to-end with release-plz, and that version_group keeps all 64 crates locked to one version.
- Changelog: single consolidated changelog, or disable release-plz changelogs entirely?
- Do we want a GitHub Environment gate on the publish job for a manual approval before crates.io publishing?
- Migrate the manual version-bump step to release-plz's release-PR, or keep bumping versions by hand and let the workflow only publish?
Goal
Port Leo's automated publishing flow to snarkVM so that merging a version-bump PR into
stagingautomatically publishes the workspace crates to crates.io and cuts a GitHub release — no manualcargo publish, no long-lived crates.io tokens.Key difference from Leo: snarkVM is lockstep-versioned (all 64 crates carry the same literal
version, currently4.7.3). We want one git tag (v4.7.4) and one GitHub release per workspace version — not Leo's per-crate tags (leo-lsp-v4.0.2). release-plz is package-centric, so this needs explicit config (see step 1).Reference (Leo)
snarkVM specifics to account for
version = "4.7.3"(noversion.workspace, no[workspace.package]block). Published assnarkvm-*; the root crate issnarkvm.staging(Leo usesmaster). All workflow triggers/refs below must targetstaging.release-crate.ymlbinary-dispatch half is out of scope. We only need crates.io publishing + a single GitHub release/tag.ProvableHQ.Steps
1. Add
release-plz.toml— configure single tag + locksteprelease-plz defaults to one tag/release per package in a multi-crate workspace. To get a single unified tag/release:
snarkvm):version_group(assign every workspace member to the same group so they always bump to the same version together).2. Add
.github/workflows/publish-crates.ymlPort from Leo's
publish-crates.yml, adjusted for snarkVM:pushtostaging(paths:Cargo.toml,**/Cargo.toml,release-plz.toml, the workflow file), plusworkflow_dispatchwith adry_runinput.concurrencygroup to prevent overlapping publishes.dry-runjob:release-plz/action@v0.5,command: release,dry_run: true.publishjob permissions:contents: write(tag + release) andid-token: write(OIDC for Trusted Publishing).staging.3. Configure crates.io Trusted Publishing (required, per crate, one-time)
Trusted Publishing uses GitHub OIDC instead of a crates.io API token. It is inherently per-crate — there's no workspace-wide setting — so it must be configured once for every already-published
snarkvm-*crate. This is unavoidable but is a one-time, scriptable setup (it does not mean per-crate tags at release time).For each crate, on crates.io → crate Settings → Trusted Publishing → Add:
ProvableHQsnarkVMpublish-crates.yml4. Bootstrap any brand-new crates
crates.io Trusted Publishing can only be configured on a crate name that already exists. Any new
snarkvm-*crate needs one initial manualcargo publish(with a token) to reserve the name, after which Trusted Publishing can be set up and the workflow takes over. Document this.5. Single GitHub release / tag
v{version}and one GitHub release per workspace version, with generated notes.6. Documentation
RELEASING.md: the normal path (bump workspace version PR → merge tostaging→ auto-publish all crates + single release), how to dry-run (workflow_dispatch), how to backfill, the Trusted Publisher setup, and the new-crate bootstrap.7. Validation
actionlinton the new workflow.workflow_dispatchwithdry_run: true→ confirm release-plz reports the expected unpublished crates and a single planned tag, without publishing.Open questions
snarkvm) single-tag pattern works end-to-end with release-plz, and thatversion_groupkeeps all 64 crates locked to one version.