Getting Started with Rust Tool Base¶
Rust Tool Base (RTB) provides a batteries-included scaffolding for building robust CLI applications in Rust.
This page wires a tool by hand, which is the fastest way to see the moving parts. To have the same tool generated for you instead, follow Build your first tool.
Status: the workspace is at 0.9.0 and pre-1.0, so the public API may still change between minor versions — but the crates are shipped, not stubs. What is not implemented is listed in What RTB does not do.
Quick Start Example¶
A working end-to-end example lives at examples/minimal in the repository. You can run it directly from the source tree:
$ cargo run -p rtb-example-minimal -- version
$ cargo run -p rtb-example-minimal -- greet
$ cargo run -p rtb-example-minimal -- doctor
$ cargo run -p rtb-example-minimal -- --help
Anatomy of an RTB Tool¶
A minimal RTB-based tool requires three core parts:
1. A custom Command implementation.
2. A linkme registration that inserts the command into the framework's command slice.
3. An Application::builder() call in your main function.
Requirements¶
Downstream tools must declare the following direct dependencies in Cargo.toml:
* rtb
* tokio
* miette
* async-trait
* linkme (Must be a direct dependency because its #[distributed_slice] attribute expands to ::linkme::… paths).
Minimal Example Code¶
use async_trait::async_trait;
use linkme::distributed_slice;
use rtb::core::app::App;
use rtb::core::command::{BUILTIN_COMMANDS, Command, CommandSpec};
use rtb::prelude::*;
// 1. Implement the Command trait.
struct Greet;
#[async_trait]
impl Command for Greet {
fn spec(&self) -> &CommandSpec {
static SPEC: CommandSpec = CommandSpec {
name: "greet",
about: "Print a friendly greeting",
aliases: &["hi"],
feature: None,
};
&SPEC
}
async fn run(&self, app: App) -> miette::Result<()> {
println!("hello from {}", app.metadata.name);
Ok(())
}
}
// 2. Register into the framework's command slice at link time.
#[distributed_slice(BUILTIN_COMMANDS)]
fn register_greet() -> Box<dyn Command> { Box::new(Greet) }
// 3. Wire the Application.
#[tokio::main]
async fn main() -> miette::Result<()> {
rtb::cli::Application::builder()
.metadata(
ToolMetadata::builder()
.name("mytool")
.summary("my CLI tool")
.build(),
)
.version(version_info!())
.build()?
.run()
.await
}
version_info!() is a macro so that env!("CARGO_PKG_VERSION") expands
at your call site and reports your tool's version. This matters beyond
display: rtb update verifies a freshly staged binary by checking the
version it reports against the release tag it came from, so a tool that
misreports its version cannot update itself.
What's Next?¶
Once your basic CLI scaffold is running, you can explore adding more complex capabilities: