Crates, Cargo features and registries¶
The four crates¶
| Crate | Depend on it for | docs.rs |
|---|---|---|
rtb-cli |
Application::builder, clap wiring, version / doctor / init / config / credentials / telemetry |
rtb-cli |
rtb-docs |
The docs command, the TUI browser, the HTTP server, full-text search |
rtb-docs |
rtb-update |
The update command, the Updater API, the pre-run policy hook |
rtb-update |
rtb-mcp |
The mcp command and the MCP server |
rtb-mcp |
All four share one version line and are released together from this repo. Mixing versions across them is not a supported configuration.
Item-level API documentation lives on docs.rs and is generated from the source, so it cannot drift. This site documents behaviour, not signatures.
Cargo features¶
There is exactly one Cargo feature in the family:
| Crate | Feature | Default | Enables |
|---|---|---|---|
rtb-docs |
ai |
off | docs ask and the rtb-chat-backed AiAnswerStream implementation |
rtb-cli, rtb-update and rtb-mcp declare no features of their own.
With ai off, the docs ask subcommand still exists and still parses — it fails at
run time with rtb::docs::ai_disabled and help text telling you to rebuild with
--features ai. That is deliberate: a command that vanishes looks like a typo,
where one that explains itself does not.
Runtime Feature gating is a different mechanism entirely — see
the CLI reference.
Toolchain¶
| Requirement | Value |
|---|---|
rust-version (MSRV) |
1.82 |
| Edition | 2021 |
| Toolchain pinned for development | 1.97.1, via rust-toolchain.toml |
The pin exists because the trybuild compile-fail fixtures compare rustc's
diagnostic output byte for byte, and a floating channel re-renders those on every
stable release. It is a development pin, not a consumer requirement — the MSRV is
what a downstream tool has to satisfy.
Link-time registries¶
Four linkme distributed slices carry everything that self-registers. A crate that
is not linked contributes nothing to any of them, which is why an unused
rtb-docs dependency produces no docs command.
| Slice | Defined in | Element | Consumed by |
|---|---|---|---|
rtb_app::command::BUILTIN_COMMANDS |
rtb-app |
fn() -> Box<dyn Command> |
Application::build, and mcp list |
rtb_app::command::BUILTIN_PRERUN_HOOKS |
rtb-app |
fn(App) -> PreRunFuture |
Application::run_with_args, before dispatch |
rtb_cli::health::HEALTH_CHECKS |
rtb-cli |
fn() -> Box<dyn HealthCheck> |
doctor |
rtb_cli::init::INITIALISERS |
rtb-cli |
fn() -> Box<dyn Initialiser> |
init |
Slice order is decided by the linker and is not stable across compiler versions or dependency-graph changes. Registration order is therefore not something to depend on — commands are sorted by name before clap sees them, and health checks and initialisers run in whatever order the linker produced.
The unsafe_code position¶
Every crate sets unsafe_code = "deny" at the workspace level rather than
forbid. deny is not a weaker guarantee here — it is what allows the modules
that register into a linkme slice to carry a narrowly-scoped
#![allow(unsafe_code)] for the #[link_section] attribute the macro emits. No
hand-written unsafe block exists anywhere in the family.