Kipt

CLAUDE.md for Rust: a copyable template for Cargo projects

A CLAUDE.md template for Rust you can copy: cargo check, test, clippy and fmt commands, workspace layout, error and unsafe rules, plus an AGENTS.md variant.

By the Kipt team · Updated 24 October 2026

What should a CLAUDE.md for Rust include?

A CLAUDE.md for Rust should give Claude Code the cargo commands to check, test, lint and format, how to run one crate or one test, a short map of your workspace, and your rules for errors, unwrap, unsafe and dependencies. Keep it under 200 lines and end it with a "done means" line, so Claude runs Clippy and the tests before it declares a task finished.

The compiler already catches a lot, which is why the most common agent problems in Rust are not build errors. They are code that compiles but does not match your project: unwrap() scattered through library code, clone() to silence the borrow checker, an unsafe block with no justification, or a new crate pulled in for something std already does. CLAUDE.md is where you pin those choices.

The template below targets stable Rust 1.99 (the current release in the Rust release notes as of October 2026) and the 2024 edition, which cargo new uses by default according to the Cargo book. Commands come from the Cargo book and the Clippy documentation. thiserror, anyhow and the crates/ folder layout are common choices, labeled as swappable. Memory behavior comes from Anthropic's CLAUDE.md documentation. For the file format in general, see what a CLAUDE.md file is.

The Rust CLAUDE.md template

Save this as CLAUDE.md at the workspace root, next to the root Cargo.toml. Replace the angle-bracket placeholders and delete any line that does not match your project.

# <Project name>

<One sentence: what this project does and who uses it.>
Stack: Rust stable (pinned in rust-toolchain.toml), edition 2024, Cargo workspace.
MSRV: `rust-version` in Cargo.toml. Do not use std APIs newer than it.

## Commands
- Fast type check: `cargo check --workspace --all-targets`
- Build: `cargo build`. Release: `cargo build --release`
- All tests (includes doc tests): `cargo test --workspace`
- One crate: `cargo test -p <crate>`
- Tests whose name contains a string: `cargo test -p <crate> parse_header`
- Show output of passing tests: `cargo test -p <crate> -- --show-output`
- Doc tests only: `cargo test --doc`
- Lint, warnings fail: `CARGO_BUILD_WARNINGS=deny cargo clippy --workspace --all-targets`
- Apply Clippy fixes: `cargo clippy --fix`
- Format: `cargo fmt --all`. Check only: `cargo fmt --all -- --check`
- Docs: `cargo doc --no-deps`
- Done means: fmt check is clean, Clippy has zero warnings, `cargo test --workspace` passes

## Project structure
- `Cargo.toml` (root): `[workspace]` members, `[workspace.dependencies]`, `[workspace.lints]`
- `crates/<name>/`: one crate per folder (swappable layout)
- Member manifests use `serde.workspace = true` and `[lints] workspace = true`
- `crates/<app>/src/main.rs`: thin binary. Logic lives in library crates
- `crates/<name>/tests/`: integration tests, public API only
- One `Cargo.lock` and one `target/` at the root. Never read or edit `target/`

## Errors
- Functions that can fail return `Result`. Propagate with `?`
- No `unwrap()` or `expect()` outside tests, unless a comment proves it cannot fail
- Library crates: typed error enums with thiserror (swappable)
- Binaries: anyhow with `.context("what we were doing")` (swappable)
- `panic!` only for broken invariants (bugs), never for bad input

## Unsafe
- Do not add `unsafe` without asking
- Every `unsafe` block has a `// SAFETY:` comment on the line above explaining why it is sound
- Edition 2024: unsafe operations inside an `unsafe fn` still need an `unsafe {}` block
- `std::env::set_var` and `remove_var` are unsafe in edition 2024. Avoid them

## Code style
- Borrow before you clone. Take `&str` and `&[T]`, not `&String` and `&Vec<T>`
- Silence a lint only with `#[expect(lint_name, reason = "why")]`, never a bare `allow`
- Public items get doc comments; examples in them run as doc tests

## Testing
- Unit tests in a `#[cfg(test)] mod tests` block at the bottom of the file
- Integration tests in `tests/`, using only the public API
- `unwrap()` and `expect()` are fine in tests
- Every bug fix comes with a test that failed before the fix

## Do not
- Do not add a crate without asking; check std and existing deps first
- Do not run `cargo update` unless the task is a dependency update
- Do not change `edition`, `rust-version` or rust-toolchain.toml unless asked

## Gotchas
- `--all-targets` does not include doc tests. Plain `cargo test` runs them
- Run `cargo fmt`, not bare `rustfmt`: rustfmt alone defaults to edition 2015
- `cargo clippy -- -D warnings` invalidates the build cache; use CARGO_BUILD_WARNINGS
- <Your project's own surprises: features to enable, system libraries, slow tests>

What does each part of the template do?

Header and MSRV. The rust-version field tells Cargo the oldest toolchain your package supports, per the Cargo manifest reference. Without it in CLAUDE.md, Claude may reach for a std API from the newest release. rust-toolchain.toml pins the toolchain for everyone who runs cargo in the folder, as the rustup overrides docs describe.

Commands. cargo check compiles without the final code generation step, so it is the fastest way for Claude to see type errors. The cargo test reference explains that a test name filter and anything after -- go to the test binary, and that --all-targets means lib, bins, tests, benches and examples, with no doc tests. --show-output comes from the Rust Book's testing chapter. The Clippy docs say that since Cargo 1.97 the recommended way to turn warnings into errors is CARGO_BUILD_WARNINGS=deny or build.warnings = "deny" in .cargo/config.toml, and that the older -- -Dwarnings form invalidates build caches. The cargo fmt --all -- --check line comes from the rustfmt README.

Project structure. The workspaces chapter of the Cargo book explains that members share one Cargo.lock and one target directory, and documents [workspace.dependencies] and [workspace.lints] with member opt-in through workspace = true. Listing those keys tells Claude to add a dependency once at the root instead of pinning a different version in each crate.

Errors. The Rust Book's chapter on when to panic says returning Result is a good default for a function that might fail, and that panicking calls like unwrap suit examples, prototypes and tests. The thiserror and anyhow split is a convention, not a rule from the docs, so replace it with whatever your crates use.

Unsafe. The // SAFETY: comment is what Clippy's undocumented_unsafe_blocks lint checks for, and it must sit on the lines right before the block. The Rust 2024 edition guide makes the unsafe_op_in_unsafe_fn lint warn by default and marks std::env::set_var and remove_var as unsafe, because they can be unsound in multithreaded programs. Models trained mostly on 2021 edition code get both wrong.

Code style and testing. Clippy's ptr_arg lint flags &String and &Vec parameters. The #[expect] attribute, described in the Rust Reference, suppresses a lint and warns if the lint stops firing, and every lint attribute accepts a reason. The #[cfg(test)] module and the tests/ folder follow the Book's test organization chapter.

Which agent mistakes does the template prevent?

Without the rule Line in the template that prevents it
unwrap() ends up in library code and panics in production "No unwrap() or expect() outside tests"
Claude clones values to get past the borrow checker "Borrow before you clone"
An unsafe block lands with no reasoning "Every unsafe block has a // SAFETY: comment"
Clippy passes locally but CI fails on warnings "Lint, warnings fail" command
A broken doc example slips through --all-targets runs The doc test gotcha and cargo test --doc
A crate pins its own version of a shared dependency "serde.workspace = true" in the structure section
Claude uses a std API newer than your MSRV "Do not use std APIs newer than it"

When you add a rule later, name the mistake first, then write the shortest line that prevents it.

How do you adapt it to your project?

  • Single crate, no workspace: drop --workspace and -p, and describe src/lib.rs, src/main.rs and tests/ instead of crates/.
  • Older toolchain: below Cargo 1.97, use cargo clippy -- -D warnings instead of CARGO_BUILD_WARNINGS.
  • Stricter linting: enable lints once in [workspace.lints.clippy] rather than in CLAUDE.md. The Clippy docs suggest cherry-picking from the restriction group, such as unwrap_used, instead of enabling it whole. A lint fails the build; a CLAUDE.md line only asks.
  • Async services: add your runtime (for example Tokio) and rules such as never blocking inside async code.
  • Rules for one area: move them into .claude/rules/. A file with paths: ["crates/ffi/**/*.rs"] in its frontmatter loads only when Claude reads or edits a matching file, which keeps FFI rules out of everyday work.
  • Code navigation: Anthropic's code intelligence docs list a rust-analyzer-lsp plugin, so Claude sees compiler diagnostics right after each edit.

For workspaces that also hold JavaScript or other languages, the monorepo template shows how to layer a root file with per-package files. After saving, run /context in a Claude Code session and check the file appears under Memory files. /init can generate a draft from your code that you merge with these sections.

How do you share it with other agents through AGENTS.md?

If your team also uses Codex, Cursor or Copilot, put the template in AGENTS.md and keep CLAUDE.md short. By default, Claude Code reads AGENTS.md only when there is no CLAUDE.md or CLAUDE.local.md in the working directory or above it, and only from v2.1.277, so an import keeps both working:

@AGENTS.md

## Claude Code only
- Use plan mode before touching crates/ffi/ or any unsafe code
- Run `/doctor prompt-audit` after editing AGENTS.md or this file

The AGENTS.md guide lists the tools that read the file, and the CLAUDE.md vs AGENTS.md comparison covers the trade-offs.

How do you keep a Rust CLAUDE.md useful?

Add a line when Claude makes the same mistake twice, and delete lines it follows without being told. When you bump rust-version or the edition, update the header and the edition notes first. /doctor prompt-audit (Claude Code v2.1.283 or later) reports outdated or conflicting instructions with proposed edits and changes nothing until you ask. CLAUDE.md is guidance, so for hard rules use Clippy lints in Cargo.toml or a hook.

If you set up Rust projects often, keep the template where you can reuse it. Kipt stores prompts and Agent Skills as Markdown in a private GitHub repo you own, so you could save this as a prompt with blanks like {{msrv:1.85}} and fill them per project. The Rust prompts collection pairs well with it. Templates for other stacks: Go, Next.js, FastAPI, Django and Rails.

Questions

What should a CLAUDE.md for a Rust project include?

The cargo commands for check, test, clippy and fmt, how to run one crate or one test, a short map of the workspace, your rules for errors, unwrap and unsafe, and the gotchas Claude cannot see from the code. Keep it under 200 lines, as Anthropic's memory docs recommend.

How do I stop Claude Code from using unwrap everywhere in Rust?

Write the rule in CLAUDE.md, for example no unwrap or expect outside tests unless a comment proves the value cannot fail, and say how errors should propagate instead. The Rust Book calls returning Result a good default for functions that might fail and says panicking code fits examples, prototypes and tests. For a hard guarantee, enable Clippy's unwrap_used lint in CI.

How do I make clippy warnings fail the build?

Since Cargo 1.97, the Clippy docs recommend CARGO_BUILD_WARNINGS=deny cargo clippy, or build.warnings = "deny" in .cargo/config.toml. The older cargo clippy -- -D warnings still works, but the Clippy docs note that it invalidates build caches.

Should a Rust CLAUDE.md say thiserror or anyhow?

Say whichever your project uses. A common split is typed error enums in library crates and anyhow with context in binaries, but both are third-party crates, so treat that as a swappable choice. What matters is that Claude follows one pattern instead of mixing styles.

Where do I put rules that apply to one crate in a workspace?

Put a short CLAUDE.md in that crate's folder, which Claude Code loads when it reads or edits files there, or add a file in .claude/rules/ with a paths field such as crates/parser/**/*.rs. Both keep the root file short.

More in Templates

All guides

Keep your prompts and skills in one place, in your own GitHub. Install every skill with one command.

Get started

Kipt is an independent product, not affiliated with or endorsed by Anthropic, OpenAI, Cursor or GitHub. Claude, ChatGPT, Codex, Cursor and GitHub are trademarks of their owners.