The problem it exists for
A confession first. rust-tool-base started as a vanity project and a way of learning Rust properly, begun not long after go-tool-base went open source, back when go-tool-base was still a single monolithic project. Since then the Go side of the estate has grown enormously and kept accelerating, and the Rust side couldn’t keep pace, so it’s lagging behind. It isn’t forgotten, though. It’s still very much on the radar, and it’ll get more love as soon as there’s more time (and more runner capacity and AI quota) to give it.
With that said, here’s what it’s for. Rust has superb single-purpose crates and no ready-made way of putting them together into a tool people install and keep updated: configuration, self-update, docs, credentials, AI, MCP and telemetry, all agreeing with each other. That’s the gap go-tool-base fills for Go, and rust-tool-base fills it for Rust.
It isn’t a port, though. “Same idea, different idioms” is the whole point: the same outcomes for a tool’s users, reached the way Rust prefers, which turns out to be quite a different shape. Its spec carries a ten-row table of the places the two part company.
How it works
What’s shared, and what isn’t
The two frameworks share outcomes, names (the forge and chat crates were renamed to match their Go modules), the minisign signature format and the shape of a repository. They don’t share code, a runtime, or even a config format: Go’s tools read YAML and Rust’s read TOML.
Where they differ is where Rust earns its keep. Configuration is typed instead of looked up by string, builders refuse to compile when a required field is missing, commands register themselves at link time, and errors are values you can match on. A tool is its commands, a registration and one call to build the application.
One crate per idea
Each library is its own crate in its own repository under rust, all published to crates.io with the rtb- prefix, and an umbrella crate switches them on with feature flags and pins a set of versions known to work together. It releases with release-plz rather than colophon, for now: colophon#37 is working out what it would take to change that.
Decisions and what they cost
- Twelve small repositories. The framework was split into roughly a dozen repos, one concept each, over about six larger ones or Go’s one-repo-per-plugin layout (spec 0043). Before the split, one merge request’s pipeline ran about 51 minutes of compute. What it cost: a dozen docs sites, more load on the runners, and version skew that shows up as two copies of one crate in a build, which makes automated updates and a duplicate-crate ban part of correctness rather than tidiness.
- Its own config store. Config is moving to a native store of its own, replacing figment, with string getters refused for good (spec 0044). What it cost: a hard break, taken now because there’s nobody downstream to break yet.
- Go’s design, Rust’s wiring. Forge access follows go/forge’s vendor-free design, but providers are passed in explicitly instead of through a global registry (spec 0042). What it cost: splitting the forge and chat crates per provider was deferred, so the forge crate still carries all six backends.
Proof in use
- Every crate is on crates.io, none yanked, with the umbrella at 0.9 and the libraries between 0.6 and 0.9. Its release binaries are signed with minisign through KMS, the same way as everything in Signing and trust.
- 31 posts so far, starting with the same idea, in a language that argues back.
- Nothing outside the family depends on it yet, which is what you’d expect of the part of the estate that’s been waiting its turn.
Use it when, and when not to
Use it if you’re building a command-line tool in Rust and want config, self-update, docs, credentials and AI wired together the way go-tool-base does it for Go, and you’re comfortable being an early adopter.
Don’t use it yet if you need stability: it’s pre-1.0 and the API isn’t frozen, release binaries are Linux x86_64 only, and the limitations page lists seventeen gaps, nested subcommands among them. Like its Go sibling, it’s not a web framework.
Where it’s going
Catching up, as time, runner capacity and AI quota allow. The new config store is approved and still to be built (rust/config#10), and splitting the forge crate per provider comes after that (rust/forge#9).
The crates
- app The application context and command contract for RTB-based CLI tools: App<C>, ToolMetadata, typed config and cancellation.
- assets Embedded-asset overlay filesystem: ship defaults in the binary, override on disk.
- chat A unified AI chat client: Claude, OpenAI, Gemini, Ollama and compatibles behind one interface.
- cli The CLI runtime family: a four-crate workspace on one version line. rtb-cli builds the application; the others each register a built-in command into the same link-time registry.
- config Strongly-typed layered configuration with hot reload.
- credentials User-secret storage behind one seam: env-var reference, OS keychain or literal config.
- error Error types and the miette diagnostic report pipeline for CLI tools.
- forge Forge release providers (GitHub, GitLab, Gitea, Codeberg, Bitbucket), plus git operations over gix.
- redact Strips credential-like content from strings before they reach logs or telemetry.
- telemetry Opt-in, consent-gated anonymous usage telemetry with pluggable sinks.
- tui Reusable terminal-UI widgets: wizards, tables and spinners.
The story in posts
- The repo that downloaded 170 gigabytes
- The CVE that bumped my dependency for me
- Parity means doing the opposite
- The scaffolder that won't hand you code that doesn't compile
- Which CLI library should you start with?
- A flag is not a setting
- Three traps release-plz sets for a Rust workspace
- Same config, two answers
- From allow_failure to blocking
- Pure-Rust Git, no git binary
Last reviewed .
