crate-seq
stop skipping versions. publish every patch.
Stop skipping versions. Publish every patch.
crate-seq is a CLI tool that tracks local Rust crate versions (via git tags or snapshots) and publishes them sequentially to crates.io — so your registry history matches your development history.
The problem
You're on 1.0.10 locally. crates.io is still at 1.0.0 because you forgot to publish. Now you either:
- Skip straight to
1.0.10and lose 9 patches of public history, or - Manually reconstruct and publish each version one at a time
Neither option is acceptable. crate-seq automates option 2.
Installation
cargo install crate-seqQuick start
Initialize a single-crate project:
cd my-crate
crate-seq initThis scans your git tags (matching v* pattern) and the crates.io registry, then generates a .crate-seq.toml ledger showing which versions are published, pending, or yanked.
Initialize a workspace (multiple crates):
cd my-workspace
crate-seq initIn a workspace, crate-seq creates a separate .crate-seq.toml in each member crate's directory. Tags use per-crate patterns by default ({crate-name}-v*).
my-workspace/
├── Cargo.toml # workspace root (no ledger here)
├── crates/
│ ├── foo/
│ │ ├── Cargo.toml
│ │ └── .crate-seq.toml # foo's ledger (tags: foo-v*)
│ └── bar/
│ ├── Cargo.toml
│ └── .crate-seq.toml # bar's ledger (tags: bar-v*)Workspace init walkthrough
Initialize all crates in a workspace, then inspect one:
$ crate-seq init
foo: 3 versions
bar: 1 versionsThen check a specific crate to see what is pending:
$ crate-seq check --crate foo
foo @ 1.0.0 (registry latest)
pending: 1.0.1 (foo-v1.0.1)
1.0.2 (foo-v1.0.2)
1.0.3 (foo-v1.0.3)At this point foo has three unpublished versions. Run a dry-run to validate them before committing to a live publish:
$ crate-seq publish --crate foo
foo:
ok 1.0.1
ok 1.0.2
ok 1.0.3
Dry run complete — pass --execute to publish.Workflow
crate-seq is tag-first: the git tag is the snapshot. What exists at the tagged commit is exactly what gets published — no more, no less.
The lifecycle for every new version:
- Make all changes for the version (code,
README.md, metadata, version bump inCargo.toml). - Commit everything.
- Run
crate-seq tag <version>(orgit tagmanually). This records apendingentry in the ledger. - Run
crate-seq publish --executeto publish all pending versions in SemVer order.
Key invariants:
- Commits made after a tag are invisible to that version. If you add a
README.mdafter tagging1.0.0, the published1.0.0package on crates.io will have no README. - Version bump,
readmefield, metadata, andCargo.tomlcontents must all be in their final state before you tag. - Per-crate
README.mdfiles must exist at tag time to appear on crates.io.
For patch releases:
Bump the version in Cargo.toml, commit, then crate-seq tag <patch-version>. The ledger entry is added as pending; the next publish --execute picks it up.
Resuming an interrupted publish:
If a publish run is interrupted mid-way, re-run crate-seq publish --execute. Versions already on crates.io are detected and skipped automatically; the run resumes from the first pending entry.
Terminal output examples
crate-seq init
Scans git tags and crates.io, then prints each crate and the number of version entries written to its ledger:
$ crate-seq init
my-crate: 10 versionsFor a workspace:
$ crate-seq init
foo: 3 versions
bar: 1 versionscrate-seq check
Diffs the ledger against the registry. Up-to-date crates print a green confirmation; crates with pending work list each version grouped by state:
$ crate-seq check
my-crate @ 1.0.0 (registry latest)
pending: 1.0.1 (v1.0.1)
1.0.2 (v1.0.2)
1.0.3 (v1.0.3)When a crate is already up to date:
$ crate-seq check
my-crate @ 1.0.3 — up to dateOrphaned entries (ledger entry whose git ref no longer exists) appear in red:
orphaned: 1.0.2 <- ref missingcrate-seq publish (dry-run)
Validates every pending version can be packaged. No network writes occur. Each version prints ok or FAIL with a reason:
$ crate-seq publish
my-crate:
ok 1.0.1
ok 1.0.2
ok 1.0.3
Dry run complete — pass --execute to publish.A packaging failure looks like:
FAIL 1.0.2 — path deps found: my-internal-libcrate-seq publish --execute
Publishes all pending versions sequentially. A progress bar advances while publishing; a summary is printed after:
$ crate-seq publish --execute
[██████████████████████████████] 3/3 1.0.3
✓ 1.0.1
✓ 1.0.2
✓ 1.0.3Versions already present on crates.io are skipped automatically (idempotent resume):
→ 1.0.1 (already on crates.io)
✓ 1.0.2
✓ 1.0.3crate-seq status
Prints the full ledger table for each crate with columns for version, source, ref, and status:
$ crate-seq status
my-crate
version source ref status
────────────────────────────────────────────────────────
1.0.0 git-tag v1.0.0 published
1.0.1 git-tag v1.0.1 published
1.0.2 git-tag v1.0.2 pending
1.0.3 git-tag v1.0.3 pending
────────────────────────────────────────────────────────
4 total 2 published 2 pendingcrate-seq tag <version>
Creates a git tag and a matching ledger entry atomically. Rolls back the tag if the ledger write fails:
$ crate-seq tag 1.0.4
created tag v1.0.4 and ledger entry for 1.0.4crate-seq skip <version>
Marks a version as skipped so it is excluded from future publish runs:
$ crate-seq skip 1.0.2
skipped 1.0.2crate-seq snapshot <version>
Captures the current crate directory as a versioned gzip tarball and records its SHA-256:
$ crate-seq snapshot 1.0.5
snapshot created: a3f8d2...c91b (version 1.0.5)Commands
| Command | Description |
|---|---|
crate-seq init |
Initialize ledger from git tags + crates.io state |
crate-seq check |
Show diff between local versions and registry |
crate-seq tag <version> |
Create a git tag and add to ledger |
crate-seq publish |
Dry-run publish all pending versions |
crate-seq publish --execute |
Publish all pending versions to crates.io |
crate-seq skip <version> |
Mark a version as skipped (won't publish) |
crate-seq status |
Show full ledger state |
crate-seq snapshot <version> |
Capture current directory as a versioned snapshot |
Configuration
Each crate gets its own .crate-seq.toml ledger file, alongside that crate's Cargo.toml. In a single-crate repo, it lives at the project root.
[crate]
name = "my-crate"
registry = "crates.io"
[settings]
mode = "git-tag" # or "snapshot"
tag_pattern = "v*" # "v*" for single-crate, "{name}-v*" for workspaces
dry_run_default = true # --execute to override
backoff_base_ms = 1000 # rate limit backoff
[auth] # optional — all fields are optional
token_env = "CRATE_SEQ_TOKEN" # read token from this env var
# token_cmd = "op read 'op://Vault/crates-io/token'" # OR shell out to secret manager
[[versions]]
version = "1.0.1"
source = "git-tag"
ref = "v1.0.1"
status = "pending"
[[versions]]
version = "1.0.2"
source = "git-tag"
ref = "v1.0.2"
status = "pending"Authentication
crate-seq resolves tokens in this order (first match wins):
--token <value>flagtoken_envortoken_cmdfrom.crate-seq.toml[auth]section- Cargo's own credentials (
~/.cargo/credentials.tomlorcredential-process)
If no valid token is found, the tool exits with a clear error and setup instructions. It never prompts interactively.
token_cmd supports any secret manager: 1Password (op), AWS Secrets Manager, HashiCorp Vault, or custom scripts.
How it works
- Scan — reads git tags matching the configured per-crate pattern and queries the crates.io API for the current published state (including yanked versions).
- Diff — compares local tags against registry state, identifies unpublished versions.
- Sequence — sorts unpublished versions in strict SemVer order.
- Verify — before each publish, queries crates.io to check if the version already exists (idempotent resume after crashes).
- Publish — for each version: checks out the tag in a temp directory, unconditionally rewrites
Cargo.tomlversion to match, runscargo package, thencargo publish. Handles rate limits with exponential backoff (base 1s, cap 60s, 5 retries, jitter up to 1s). - Record — updates the ledger with publish status after each version.
Requirements
- Rust 1.88+ (MSRV). The
gix0.79 dependency pulls inhuman_format, which uses let-chains — a feature stabilized in Rust 1.87.crate-seqpins to 1.88.0 viarust-toolchain.toml. - Git (for git-tag mode)
- A valid crates.io API token (via
cargo login,--tokenflag, env var, or secret manager)
License
MIT OR Apache-2.0
documentation
- cli reference
- crate-seq-core
- crate-seq-git
- crate-seq-ledger
- crate-seq-manifest
- crate-seq-registry
- crate-seq-snapshot
architecture
changelog
- 0.2.0 3 entries
- 0.1.2 1 entry
- 0.1.1 2 entries