Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Rust Tool Base (RTB)
A batteries-included application framework for building Rust CLI tools: idiomatic, composable and AI-ready.
Status: pre-1.0. The crates are implemented and published, but the public API is not frozen, so expect breaking changes within 0.x. The authoritative contract for each subsystem lives in
0008-rust-tool-base.
RTB is a Rust sibling of Go Tool Base (GTB).
It is not a line-for-line port. Go Tool Base leans on Go's idioms
(context.Context, functional options, package-level init(),
interface{}-keyed containers); RTB leans on Rust's (? + miette,
typestate builders, linkme distributed slices, strongly-typed serde
config, tokio structured concurrency).
What RTB gives you
- Opinionated application scaffolding.
Application::builder()is a typestate assembler that wires clap, figment, tracing, miette, tokio and a signal-boundCancellationTokenin one call. - Strongly-typed layered config. Env vars > user files > embedded
defaults, materialised into your
serde::Deserializestruct. Hot-reload (thehot-reloadfeature ofrtb-config) usesnotifyandarc-swap, with awatch::Receiverfor observers. - Embedded assets with overrides.
rtb-assetslayers files compiled in withrust-embed, directories on disk and in-memory maps behind one read-onlyAssetsAPI. A read takes the file from the last-registered layer that has it; YAML and JSON can instead be deep-merged across every layer (RFC 7396 merge-patch). - Diagnostic errors, not error handlers. Every crate derives
thiserror::Error + miette::Diagnostic;main()returnsmiette::Result<()>and a framework-installed hook renders them with labels, help, and severity. - Self-update.
self-replaceplus minisign-signed releases (the prehashedEDvariant,ed25519(BLAKE2b-512(archive))), verified withminisign-verify. That is the cratecargo-binstalluses, so one signature serves both. The staged binary is self-tested before an atomic swap. - Release sources and git.
rtb-forgereads releases from GitHub, GitLab, Bitbucket, Gitea, Codeberg or a bare HTTPS URL, which is wherertb updatelooks for a new version, and itsRepotype runs git operations ongix. - AI.
genaicovers OpenAI, Gemini, Ollama and OpenAI-compatible endpoints; Anthropic goes through a directreqwestclient so prompt caching, extended thinking and citations work. Structured output is validated withjsonschema. - MCP. Built on the official
rmcpSDK. A command opts in by overridingCommand::mcp_exposed()to returntrue, and can describe its arguments to MCP clients throughCommand::mcp_input_schema().mcp serve(stdio by default) andmcp listship as built-in subcommands. - TUI docs browser.
ratatuiwithtui-markdown, plus streaming AI Q&A. - Credentials.
keyringwrapped in aCredentialStoretrait, withsecrecy::SecretStringend-to-end, zeroed on drop. - Telemetry. Opt-in, salted
machine-uid, pluggable sinks (noop, file, HTTP, OTLP).
Workspace layout
Only the umbrella crate and the rtb binary live here. Every other
crate is a standalone module of the
phpboyscout Rust toolkit, consumed here
as an ordinary dependency:
- Foundations:
rtb-error,rtb-redact,rtb-config,rtb-assets,rtb-app,rtb-tui,rtb-credentials,rtb-telemetry,rtb-test-support,rtb-chat(formerlyrtb-ai),rtb-forge(formerlyrtb-vcs). - CLI family:
rtb-cli,rtb-update,rtb-docs,rtb-mcp, inphpboyscout/rust/cli.
rust-tool-base/
├── Cargo.toml # workspace root
├── crates/
│ ├── rtb/ # umbrella crate (public API)
│ └── rtb-cli-bin/ # the `rtb` scaffolder binary
├── examples/
│ └── minimal/ # smoke-test tool
├── docs/ # user-facing documentation
│ # (specs live in the project wiki)
├── .gitlab-ci.yml # CI + the tagged `dist` release stage
├── deny.toml # cargo-deny policy
├── rustfmt.toml
├── rust-toolchain.toml # pinned stable
├── justfile # common tasks
├── LICENSE # MIT
└── SECURITY.md
Quick start
A working end-to-end example lives at
examples/minimal. Run it with:
$ 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
A minimal RTB-based tool has three parts: (1) a custom Command
implementation, (2) a linkme registration that inserts it into the
framework's command slice, and (3) an Application::builder() call
in main.
use async_trait;
use distributed_slice;
use App;
use ;
use *;
// 1. Implement the Command trait.
;
// 2. Register into the framework's command slice at link time.
// 3. Wire the Application.
async
version_info!() has to be a macro: it expands env!("CARGO_PKG_VERSION")
at your call site, so it reports your tool's version. A function
couldn't: its env! would expand inside the framework and report the
framework's version instead.
Downstream tools need the framework, tokio, miette, async-trait and
linkme as direct dependencies. The framework publishes as
rust-tool-base and the examples import it as rtb:
[]
= { = "rust-tool-base", = "0.9" }
linkme must be direct because its #[distributed_slice] attribute
expands to ::linkme::… paths.
Development
just pre-push is the merge-request gate without coverage. AGENTS.md
explains why it needs cargo-nextest.
License
MIT. See LICENSE.