Skip to content

Getting Started with Rust Tool Base

Rust Tool Base (RTB) provides a batteries-included scaffolding for building robust CLI applications in Rust.

Status: RTB is currently in a pre-0.1 scaffolding phase. Most crates are intentional stubs. This guide demonstrates how to set up the minimal scaffold using the current API.

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(VersionInfo::from_env())
        .build()?
        .run()
        .await
}

What's Next?

Once your basic CLI scaffold is running, you can explore adding more complex capabilities: