TL;DR: Rust’s memory safety is a default, not a guarantee. Any crate, any module, can write unsafe and opt out of it. So “written in Rust” does not by itself mean “contains no unsafe code.” rust-tool-base makes the stronger promise for its own code: every crate root carries #![forbid(unsafe_code)], which the compiler enforces and which a module cannot quietly undo. The result is that a whole class of memory bug is off the table for first-party code by construction.
Safe by default is not the same as safe
People reach for Rust because of memory safety, and the reputation is earned. Write ordinary Rust and the compiler will not let you have a use-after-free, a data race, or a buffer overrun. That’s the default, and it’s a very good default.
But it is a default, and defaults can be turned off. Rust has an unsafe keyword precisely so that, when you genuinely need to, you can dereference a raw pointer, call into C, or tell the compiler you’ve upheld an invariant it can’t check itself. Inside an unsafe block, the guarantees are yours to maintain, not the compiler’s to enforce.
That keyword has to exist. Some of the most foundational crates in the ecosystem are built on it, carefully. But it means a fact worth being precise about: a project being “written in Rust” tells you its code is mostly safe. It does not tell you the project’s own code contains no unsafe. Those are different claims, and only the second one is a guarantee.
rust-tool-base makes the second claim about its own code, and has the compiler back it up.
forbid, not just deny
The mechanism is one line at the top of every crate:
#![forbid(unsafe_code)]
unsafe_code is a lint, and Rust lints have levels. The interesting choice is forbid rather than deny, because the two are not the same strength.
deny makes the lint an error. But it’s an error a downstream module can locally override. Anyone can write #[allow(unsafe_code)] on a function or a block and the deny is lifted right there. As a policy, deny is “don’t do this unless you really mean to,” and “unless you really mean to” is a door.
forbid is the strict one. It makes the lint an error and it makes that error impossible to override from inside the crate. A module cannot #[allow] its way back out. Once a crate root says #![forbid(unsafe_code)], there is no unsafe anywhere in that crate, and no local exception can be carved out. The compiler simply refuses.
So every rust-tool-base crate that ships in a built tool forbids unsafe at its root. Not “discourages.” Cannot contain it.
The one honest subtlety
There’s a wrinkle, and it’s worth showing rather than hiding, because it’s where the design got specific.
The workspace sets unsafe_code = "deny" as the baseline for everything, including test files. But test code occasionally has a real need for unsafe. In the 2024 edition, std::env::set_var became unsafe, because mutating the process environment isn’t thread-safe, and a test that exercises environment-driven configuration has to call it.
So the split is deliberate. The workspace-wide level is deny, which a test file can locally #[allow] when it genuinely needs that one environment call. But every production lib.rs and main.rs additionally carries #![forbid(unsafe_code)], and forbid cannot be relaxed. Test scaffolding gets a controlled, visible exception for a specific standard-library call. Shipping code gets none. The guarantee that matters, “the code in the binary contains no unsafe,” holds, and the place it’s slightly loosened is exactly the place that never reaches a user.
What the guarantee is actually worth
Two things, one for users and one for reviewers.
For users: an entire family of bug is ruled out of first-party code mechanically. Use-after-free, double-free, data races on shared memory, reading off the end of a buffer. These are the classic memory-safety vulnerabilities, and in a crate that forbids unsafe they cannot originate, because the constructs that produce them cannot be written. That’s not careful coding. It’s the compiler refusing to build anything else.
For reviewers: the cost of an unsafe block is mostly the review burden it carries. Every one is a spot where a human has to check, by hand, that an invariant holds, and has to re-check it whenever nearby code changes. A crate that forbids unsafe has zero of those. There is no unsafe block to audit, ever, because the compiler guarantees there isn’t one.
I’ll be straight about the boundary: this is a promise about rust-tool-base’s own code. Its dependencies are another matter, and some of them do contain unsafe, correctly. Keeping that side honest is a different job, done by vetting the dependency tree and gating it in CI, which is its own post. Within first-party code, though, the guarantee is real, and there is no Go equivalent to it. Go has an unsafe package, but nothing that lets a codebase prove, to the compiler, that it never touches it.
The bottom line
Rust is memory-safe by default, but the unsafe keyword exists so that default can be set aside. “Written in Rust” therefore does not by itself mean a project’s own code contains no unsafe.
rust-tool-base makes that the stronger claim. Every crate root carries #![forbid(unsafe_code)], and forbid, unlike deny, cannot be overridden from inside the crate. Test files get a narrow, visible deny-level exception for the one standard-library call that needs it; shipping code gets none. The payoff is a whole class of memory-safety bug ruled out of first-party code by construction, and not one unsafe block for a reviewer to audit.