shipper is a publishing reliability layer for Rust workspaces.
Cargo packages and uploads. The workflow around it — planning a multi-crate release, surviving rate limits, recovering when CI dies, knowing what actually shipped when the upload was ambiguous — is where things tend to break. Shipper makes a workspace publish safe to start and safe to re-run.
The single test: you can start a release train, stop staring at the terminal, and still trust the outcome.
Why this exists: see MISSION.md for mission, vision, audience, and the convictions that shape every default.
v0.3.0-rc.1 shipped 2026-04-16 — first real-world crates.io publish, 12 crates live, driven by Shipper itself. The publish absorbed 41 retries silently across a 69-minute run. See ROADMAP.md for the post-rc.1 product thesis (nine competencies) and master tracking issue #109.
| Audience | Start here |
|---|---|
| New user | This README → docs/release-runbook.md |
| Operator | docs/release-runbook.md, docs/configuration.md |
| Contributor | MISSION.md → ROADMAP.md → CONTRIBUTING.md → an issue from #100–#109 |
| AI assistant | CLAUDE.md or GEMINI.md |
| Auditing receipts/events | docs/INVARIANTS.md |
From crates.io:
cargo install shipper-cli --lockedThe binary is named
shipperbut the published crate isshipper-cli. #95 tracks makingcargo install shipperwork.
From this repository:
cargo install --path crates/shipper-cli --lockedshipper plan # preview the publish order
shipper preflight # verify everything is ready
shipper publish # execute the plan
shipper resume # if interrupted, continue from the last stateshipper --help and shipper <subcommand> --help are the canonical command/flag reference.
For a walkthrough, see the first-publish tutorial. For the full docs tree (tutorials / how-to / reference / explanation), see docs/README.md.
The core flow is plan → preflight → publish → (resume if interrupted).
- Plan. Reads the workspace via
cargo_metadata, filters publishable crates, topologically sorts them by intra-workspace dependencies, and computes a SHA256-basedplan_id. Same workspace state always produces the sameplan_id. - Preflight. Validates git cleanliness, registry reachability, performs a workspace dry-run, checks version-not-taken, optionally verifies ownership. Produces a
Finishabilityassessment (Proven / NotProven / Failed). - Publish. Executes the plan one crate at a time with retry/backoff. After each
cargo publish, verifies registry visibility (sparse index and/or API) before advancing to a dependent crate. Persists state to disk after every step. - Resume. Reloads
.shipper/state.json, validates theplan_idmatches the current workspace, skips already-published packages, continues from the first pending crate.
State lives in .shipper/:
events.jsonl— append-only event stream. The authoritative record.state.json— projection over events for fast resume.receipt.json— end-of-run summary with evidence.lock— concurrent-publish guard.
The truth/projection/summary contract is documented in docs/INVARIANTS.md. Use --state-dir <path> to redirect (e.g. into a CI artifacts directory).
- Deterministic, dependency-ordered publish plan.
- Pre-flight checks (git, registry, dry-run, version, ownership).
- Per-crate publish with retry/backoff for retryable failures.
- Post-publish readiness verification before advancing to dependents.
- Resumable state after every step.
- Append-only audit event log + machine-readable receipt with evidence (stdout/stderr, exit codes, git context, environment fingerprint).
- Multi-registry orchestration in a single run (state segregated per registry).
- Parallel publishing for independent crates within the dependency graph.
- Configurable safety/speed tradeoff via publish policies (
safe,balanced,fast).
- Bump versions, generate changelogs, create git tags, or write release notes. Use cargo-release or release-plz for those. Shipper picks up after the version is decided.
Publishing itself is performed by Cargo. Shipper resolves a registry token from the same places Cargo does:
CARGO_REGISTRY_TOKEN(crates.io)CARGO_REGISTRIES_<NAME>_TOKEN(alternative registries;<NAME>uppercased,-replaced with_)$CARGO_HOME/credentials.toml
The token is opaque, never logged, sanitized from receipts.
shipper doctor reports auth_type:
token— Cargo token detectedtrusted— GitHub OIDC trusted-publishing env detectedunknown— partial auth env detected-— none
Trusted Publishing detection exists today; making it the default (with OIDC token exchange) is tracked at #96.
Project-specific configuration via .shipper.toml in the workspace root. CLI flags always take precedence.
shipper config init # generate a default config file
shipper config validate # validate a configuration fileSee docs/configuration.md for the full reference.
Generate a workflow snippet for your platform:
shipper ci github-actions
shipper ci gitlab
shipper ci circleci
shipper ci azure-devopsOr browse templates/ for reference workflows.
shipper publish --policy safe # default: verify every step
shipper publish --policy balanced # verify when needed
shipper publish --policy fast # skip verification (with caution)shipper publish --readiness-method api # fast (default)
shipper publish --readiness-method index # more accurate
shipper publish --readiness-method both # most reliableshipper publish --registries crates-io,internal-mirror
shipper publish --all-registriesshipper inspect-events # human-readable event log
shipper inspect-receipt --format json # JSON receipt for CI consumption
shipper status # compare local versions to the registryshipper resume
shipper resume --force-resume # if the workspace plan has changed
shipper publish --resume-from my-crate # restart from a specific crateshipper-cli— installs theshipperbinary.shipper— reusable library: planning, preflight, publish, resume, receipts.
The full crate map is in docs/structure.md.
The full docs tree is organized by reader purpose (Diátaxis): tutorials, how-to guides, reference, explanation. Start at docs/README.md.
Top of the repo:
- MISSION.md — mission, vision, audience, beliefs
- ROADMAP.md — five pillars, nine-competency scorecard, now/next/later
- docs/README.md — documentation index
Quick links:
- Learn: First publish tutorial • Recover from interruption
- Do: Run in GitHub Actions • Inspect state & receipts • Inspect a stalled run
- Look up: CLI reference • State files cheat sheet •
.shipper.toml• Failure modes - Understand: Why Shipper •
not_provenexplained • Architecture • Invariants
Licensed under either of:
- Apache License, Version 2.0
- MIT license
at your option.