Why RTB? (and what it explicitly is not)¶
The gap¶
The Rust ecosystem is famously strong on sharp, small crates and
deliberately light on macro-frameworks. clap, figment, tracing,
miette, ratatui, reqwest, tokio are each best-in-class, but wiring
them into a cohesive CLI product — plus self-update, AI, MCP, embedded docs,
credentials, telemetry, scaffolding — is repeated work on every project.
The closest existing Rust neighbours are:
cli-batteries— thin preamble (clap + tracing-subscriber + panic/signal).moonrepo/starbase— session/lifecycle model, but CLI-agnostic and moonrepo-flavoured.cargo-dist/cargo-release— release packaging, not a runtime framework.
None of these fill the "opinionated, full-lifecycle, scaffolded, AI-ready" niche that Go Tool Base occupies in the Go world. RTB fills that gap.
What RTB is¶
- An application framework — construct an
Application, register your commands, ship. - Batteries-included — config, logging, errors, update, docs, AI, MCP, credentials, telemetry are wired by default behind Cargo features.
- Idiomatic Rust — typestate builders,
miettediagnostics,Arc<dyn Trait>for runtime polymorphism, generics for compile-time polymorphism,tokiostructured concurrency. - A scaffolder —
rtb new/rtb generateproduce a working tool.
What RTB is not¶
- Not a GTB port. GTB's
Propsstruct,Containabledynamic config accessors, functional-options API, and package-levelinit()registration are non-idiomatic in Rust. RTB reaches the same outcomes with Rust's mechanisms instead. - Not a web framework. RTB does not compete with
axum/actix. It integratesaxumso your tool can expose aservesubcommand. - Not a TUI library. It uses
ratatuiandinquire; it doesn't compete with them. - Not an async runtime. It picks
tokioand runs. - Not a DI container. The
Appstruct is a plain strongly-typed context passed by cheap clone; there is no service locator, noinject!macro, no global registry.
Guiding principles¶
- Types over strings. Config is a
serde::Deserializestruct, not aGetString(key)bag. - Errors are values. No
ErrorHandler.Check()funnel — returnResult<_, miette::Report>, propagate with?, report at the edge. - Composition over inheritance. Services are composed into
App, not inherited from a base class. - Cargo features gate compile-time concerns.
Features(the runtime enum) gates UX concerns per-invocation. - Borrow the ecosystem. Every crate RTB wraps is a deliberate best-in-class pick (see the Ecosystem Survey).