# Release Guardian Sdk Packages

> Version, validate, dry-run, and publish the repository's Rust and TypeScript Guardian SDK packages to crates.io and npm. Use when Codex needs to choose the next coordinated release version, update release manifests and lockfiles, run targeted checks, prepare the Rust publication workflow or npm commands, and minimize the user's work to approval or final irreversible publish confirmation.

- Skill: `openzeppelin/release-guardian-sdk-packages` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add openzeppelin/release-guardian-sdk-packages`
- Raw SKILL.md: https://api.skillmd.com/api/skills/openzeppelin/release-guardian-sdk-packages/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: openzeppelin (https://skillmd.com/u/openzeppelin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/openzeppelin/release-guardian-sdk-packages

---


# Release Guardian SDK Packages

Read the current source of truth at the start of every release task:

- `docs/MULTISIG_SDK.md`
- `Cargo.toml`
- `crates/shared/Cargo.toml`
- `crates/client/Cargo.toml`
- `crates/contracts/Cargo.toml`
- `crates/miden-multisig-client/Cargo.toml`
- `packages/guardian-client/package.json`
- `packages/guardian-evm-client/package.json`
- `packages/miden-multisig-client/package.json`
- `packages/guardian-operator-client/package.json`
- `packages/package-lock.json`
- `references/release-surface.md`

Trust these sources in this order:

1. crate manifests, package manifests, and lockfiles
2. `docs/MULTISIG_SDK.md`
3. `references/release-surface.md`

## Default Behavior

Do as much of the release prep as possible without user intervention:

- check the current git branch before mutating release files
- inspect the current publishable versions
- use the target version provided by the user
- update manifests and lockfiles
- run targeted tests, builds, and dry-runs
- give the user the exact remaining workflow, approval, auth, or publish commands

Before changing versions or preparing publishes:

- if the current branch is not a dedicated release branch, tell the user to move to one first
- prefer a branch name like `release/v<version>` when the target version is known
- do not create, rename, or push the branch unless the user explicitly asks Codex to do it

If the user does not provide a version:

- inspect the current coordinated release version
- propose the next valid version on the active line
- stop for confirmation unless the user explicitly asked Codex to choose the next version automatically

Unless the user explicitly asks Codex to perform the real publish and required
trust/authentication is already valid, stop before an irreversible Rust
workflow dispatch, published GitHub Release, or `npm publish` step.

Normal Rust publication is performed by
`.github/workflows/publish-crates.yml`, not by a maintainer running
`cargo publish` locally. Stop before dispatching a non-dry-run workflow or
publishing a GitHub Release unless the user explicitly approves that
irreversible action.

## Version Policy

- Keep the publishable SDK surface on one coordinated version
- Stay on the active Miden dependency line unless the task is an explicit migration
- Treat the user-provided target version as the source of truth for the release
- If the user has not decided yet, present the current version and the likely next patch version, but do not bump files until the version is confirmed
- If the user asks for "current +1" on the active line, choose the next patch above the highest committed publishable version on that line
- Do not change `crates/server`, `crates/miden-rpc-client`, `crates/miden-keystore`, or example crate versions as part of the SDK release

## Publishable Surface

Rust crates:

- `guardian-shared`
- `guardian-client`
- `miden-confidential-contracts`
- `miden-multisig-client`

TypeScript packages:

- `@openzeppelin/guardian-client`
- `@openzeppelin/guardian-evm-client`
- `@openzeppelin/miden-multisig-client`
- `@openzeppelin/guardian-operator-client`

## Version Bump Rules

For a coordinated release, update all of these:

- `Cargo.toml` `[workspace.package] version`
- `crates/client/Cargo.toml` internal `guardian-shared` dependency version
- `crates/contracts/Cargo.toml` internal `guardian-shared` dependency version
- `crates/miden-multisig-client/Cargo.toml` internal `guardian-client`, `guardian-shared`, and `miden-confidential-contracts` dependency versions
- `packages/guardian-client/package.json` `version`
- `packages/guardian-evm-client/package.json` `version`
- `packages/miden-multisig-client/package.json` `version`
- `packages/miden-multisig-client/package.json` `@openzeppelin/guardian-client` dependency range
- `packages/guardian-operator-client/package.json` `version`

After editing TypeScript versions, refresh the workspace lockfile:

```bash
cd packages
npm install
```

Inspect the resulting lockfile diff. Keep the refresh focused on version and dependency metadata. `@openzeppelin/guardian-client` must remain a workspace link (`resolved: "guardian-client"`, `link: true`), not a registry tarball.

## Validation

Run the smallest release-relevant checks first:

```bash
cargo test -p guardian-shared
cargo test -p guardian-client
cargo test -p miden-confidential-contracts
cargo test -p miden-multisig-client
```

```bash
cd packages
npm ci
npm run build -w @openzeppelin/guardian-client
npm test -w @openzeppelin/guardian-client
npm run build -w @openzeppelin/guardian-evm-client
npm test -w @openzeppelin/guardian-evm-client
npm run build -w @openzeppelin/miden-multisig-client
npm test -w @openzeppelin/miden-multisig-client
npm run build -w @openzeppelin/guardian-operator-client
npm test -w @openzeppelin/guardian-operator-client
```

Then check that each publishable README still matches its shipped surface.
The README is the crates.io / npm landing page, and a config field documented
only under `docs/` never reaches it:

```bash
git diff v<previous-version>..HEAD --stat -- crates/*/src packages/*/src
git diff v<previous-version>..HEAD --stat -- crates/*/README.md packages/*/README.md
```

For every package whose `src` gained a public API, builder option, or config
field with no matching README change, read the new surface and update that
README before publishing. Report any package deliberately left unchanged.

Then run publish dry-runs:

```bash
cargo publish --dry-run --locked \
  -p guardian-shared \
  -p guardian-client \
  -p miden-confidential-contracts \
  -p miden-multisig-client
```

```bash
cd packages
npm publish -w @openzeppelin/guardian-client --access public --dry-run
npm publish -w @openzeppelin/guardian-evm-client --access public --dry-run
npm publish -w @openzeppelin/miden-multisig-client --access public --dry-run
npm publish -w @openzeppelin/guardian-operator-client --access public --dry-run
```

If a dry-run or test fails, stop there and report the failing step, package, and minimal next action.

## Git Workflow

Before any release edits:

- inspect `git branch --show-current`
- inspect `git status --short`
- if the user is still on a feature or work branch, ask them to switch to a release branch before proceeding

Suggested branch commands:

```bash
git checkout -b release/v<version>
```

If the branch already exists:

```bash
git checkout release/v<version>
```

## Rust Publication Workflow

The stable workflow filename is `.github/workflows/publish-crates.yml`.
crates.io must have one trusted-publisher entry per Rust crate with:

```text
GitHub owner: OpenZeppelin
Repository: guardian
Workflow: publish-crates.yml
Environment: release
```

Published releases force-select all four crates and use OIDC trusted
publishing. Manual runs expose `dry-run` and one boolean per crate. Pull
requests changing the workflow force an all-crate credential-free dry run.

Cargo receives the selected packages in the fixed display order below and
publishes dependency-safe topological batches:

1. `guardian-shared`
2. `guardian-client`
3. `miden-confidential-contracts`
4. `miden-multisig-client`

Exact versions already on crates.io are skipped. The selected packages are
passed to one native multi-package Cargo command, which owns dependency
ordering and index polling. A partial repair may select a dependent only when
its unselected prerequisites are already available at the coordinated version.

Trusted-publishing failure must fail closed. The workflow has no long-lived
registry-token fallback.

## TypeScript Publish Order

TypeScript packages must be published in dependency order:

1. `@openzeppelin/guardian-client`
2. `@openzeppelin/guardian-evm-client`
3. `@openzeppelin/miden-multisig-client`
4. `@openzeppelin/guardian-operator-client` (no internal deps — order-independent, listed last for convenience)

## Manual Boundary

The user should usually only need to handle:

- moving to or confirming the release branch
- `npm whoami` or `npm login`
- confirming a Rust workflow dry run
- approving any non-dry-run Rust workflow or published GitHub Release
- cutting the GitHub Release (`gh release create`), which also triggers the server image build

For a normal Rust release, do not request `cargo login` or a local crates.io
token. Verify the four external trusted-publisher entries and use:

```bash
gh workflow run publish-crates.yml \
  --ref <release-ref> \
  -f dry-run=true \
  -f guardian-shared=true \
  -f guardian-client=true \
  -f miden-confidential-contracts=true \
  -f miden-multisig-client=true
```

Continue TypeScript authentication checks with `npm whoami || npm login`.

## Post-Release

After publishing:

- ask the user whether to cut the GitHub Release for the tag
- verify the published versions if the task requires it

Cut the release with `gh`. Prefer `--draft` so the user can review notes and the
tag before anything ships:

```bash
gh release create v<version> --generate-notes --draft
```

A **draft** release does not fire the `release: published` event, so the Docker
Publish workflow stays idle while the draft is reviewed. Publish the draft when
ready, which is what actually triggers the build:

```bash
gh release edit v<version> --draft=false
```

To skip the review step and publish immediately, omit `--draft`:

```bash
gh release create v<version> --generate-notes
```

Publishing a GitHub Release auto-triggers the **Publish Rust Crates**,
**Publish NPM Packages**, and **Docker Publish** workflows. Each retains its own
approval and result flow. The Docker build waits for required-reviewer approval
on the `release` environment before it pushes:

- approve the run when the release should also ship a server image
- decline it for SDK-only releases (the SDK and server share the same `vX.Y.Z`
  tag line, so every release reaches this gate)

A plain `git tag` + `git push` does **not** create a release and will not trigger
the server image build. Use it only when the server image is intentionally not
wanted and no GitHub Release is being cut:

```bash
git tag v<version>
git push origin v<version>
```

## Output Shape

Default to a short release handoff:

- target version
- expected release branch
- files updated
- checks and dry-runs completed
- exact remaining commands for branch, workflow dispatch, approval, npm auth,
  publish, and tagging

If the user asks to publish, separate dry-run commands from real publish commands and keep the final sequence copy-pasteable.

