Skip to content

Tooling

Cargo includes the compiler, the formatter, the linter, the test runner, and the documentation generator, so one short command sequence checks an agent’s change before you read it.

A Java project combines many tools: Maven or Gradle, javac, Checkstyle or Spotless for formatting, SpotBugs or SonarQube for lints, JUnit through Surefire, Javadoc, and the OWASP dependency check. Each has its own configuration. In Rust, the official tools come with the toolchain, and they all run through cargo.

Command What it does Java
cargo check type-check without building a binary: the fastest feedback javac without packaging
cargo build compile (add --release for an optimized build) mvn package
cargo run build and run the binary mvn exec:java
cargo test build and run unit, integration, and doc tests mvn test
cargo fmt format the code (--check to only report) Spotless, google-java-format
cargo clippy lints: more than 800 checks for bugs, style, and performance SpotBugs, Checkstyle, Sonar
cargo doc --open build the API documentation of the crate and all dependencies Javadoc
cargo tree the dependency tree mvn dependency:tree

cargo fmt has almost no options, so all Rust code looks the same. In review, never discuss formatting: ask for cargo fmt.

Rust compiler errors are long, and they are worth reading in full. This is the real output for a value used after a move:

rustc output
error[E0382]: use of moved value: `report`
--> borrow_error.rs:10:23
|
8 | pub fn send_twice(report: String) -> usize {
| ------ move occurs because `report` has type `String`, which does not implement the `Copy` trait
9 | let first = send(report);
| ------ value moved here
10 | let second = send(report);
| ^^^^^^ value used here after move
|
note: consider changing this parameter type in function `send` to borrow instead if owning the value isn't necessary
--> borrow_error.rs:4:21
|
4 | pub fn send(report: String) -> usize {
| ---- ^^^^^^ this parameter takes ownership of the value
| |
| in this function
help: consider cloning the value if the performance cost is acceptable
|
9 | let first = send(report.clone());
| ++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0382`.

Read it from the top:

  1. The error code and the summary: E0382, “use of moved value”. rustc --explain E0382 prints a full explanation with examples. All codes are in the compiler error index.
  2. The labels in the code: where the value was declared, where it moved, and where it was used after the move. The labels tell a story in order.
  3. The note and help lines: suggestions. Here the compiler offers two fixes: borrow in send, or clone. The first is usually right. An agent often takes the second, because it is the last suggestion and the smallest change. See S01: clone() to satisfy the borrow checker.
cargo clippy output
warning: the loop variable `i` is only used to index `prices`
--> clippy_warning.rs:6:14
|
6 | for i in 0..prices.len() {
| ^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.99.0/index.html#needless_range_loop
= note: `-W clippy::needless-range-loop` implied by `-W clippy::all`
= help: to override `-W clippy::all` add `#[allow(clippy::needless_range_loop)]`
help: consider using an iterator
|
6 - for i in 0..prices.len() {
6 + for <item> in &prices {
|
warning: 1 warning emitted
  • The first line says what is wrong.
  • The link goes to the lint’s documentation, with an explanation and examples. The lint name is at the end of the URL: needless_range_loop.
  • The note says why the lint is on: here, it is in the default group.
  • The help with a diff is a suggested fix. Many Clippy fixes can be applied with cargo clippy --fix.
  • “to override … add #[allow(...)]” is how to silence it. That is almost never the right response to a warning in agent code. See S25: #[allow(...)] to silence clippy or compiler warnings.

Both files are captured from the pinned toolchain by examples/tooling/capture.sh, and CI checks that they are current.

Group Default Contains
correctness deny code that is wrong
suspicious, style, complexity, perf warn likely bugs, non-idiomatic code, needless complexity, slow code
pedantic allow strict lints, with some false positives
nursery allow new lints that are still in development
restriction allow lints against specific features, such as unwrap_used. Enable them one by one, never as a group
cargo allow checks on Cargo.toml

A project turns groups and single lints on in Cargo.toml. This is the configuration of the examples on this site:

examples/Cargo.toml
[workspace.lints.rust]
unsafe_code = "deny"
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -1 }
# Exceptions to pedantic. Each one adds noise to short teaching snippets
# without changing what the reader learns. The site discusses these topics
# where they matter instead.
must_use_candidate = "allow" # `#[must_use]` on every pure function
return_self_not_must_use = "allow" # `#[must_use]` on every builder method
missing_errors_doc = "allow" # `# Errors` doc sections in every snippet
missing_panics_doc = "allow" # `# Panics` doc sections in every snippet
implicit_hasher = "allow" # generic `S: BuildHasher` on every `HashMap` parameter

These are installed separately with cargo install <name>. They are well known in the Rust community:

Tool What it does Java
cargo audit checks Cargo.lock against the RustSec database of security advisories OWASP dependency-check
cargo deny rules for licenses, advisories, banned crates, and duplicate versions license and enforcer plugins
cargo outdated lists dependencies with newer versions versions:display-dependency-updates
cargo machete finds dependencies that the code does not use dependency:analyze
cargo expand shows the code after macro expansion (see Macros) (generated sources)
cargo nextest a faster test runner with better output Surefire options
cargo miri runs tests in an interpreter that finds undefined behavior in unsafe code. Needs a nightly toolchain (none)

Use rust-analyzer in your editor. It works in VS Code and most other editors. JetBrains RustRover has its own engine with the same features. For reading agent code, two features help more than any other: hover, which shows the type and documentation of anything, and inlay hints, which show the inferred type of each let and closure parameter. Rust code leaves out many types, and the hints put them back.

A review gate that runs before you read the code. Each step must pass:

review-gate.sh
# Run this in the project before you read an agent's Rust code.
# Each step must pass. Stop at the first failure.
set -euo pipefail
cargo fmt --all --check # formatting: no diff
cargo clippy --workspace --all-targets -- -D warnings # lints: every warning is an error
cargo test --workspace # unit, integration, and doc tests
  • cargo fmt --check: the code is formatted, so the diff shows only real changes.
  • cargo clippy ... -D warnings: no warning is left. --all-targets includes tests and examples.
  • cargo test: all tests pass, including doc tests.

Add cargo audit and cargo deny check in CI for projects with many dependencies.

  • The agent says “it compiles” or “tests pass”, but did not run Clippy. Run the gate yourself.
  • #[allow(...)] added to make Clippy quiet, or a [lints] section that turns lints off. See S25: #[allow(...)] to silence clippy or compiler warnings.
  • A CI job that runs cargo build and cargo test only.
  • Changes to rust-toolchain.toml, or a nightly toolchain, with no reason.
  • New dependencies that cargo tree shows to pull in many more crates. See S28: Too many or unknown dependencies.

The task: the check that runs before a change is reviewed.

Worse
# "It builds and the tests pass."
cargo build
cargo test
Better
# Run this in the project before you read an agent's Rust code.
# Each step must pass. Stop at the first failure.
set -euo pipefail
cargo fmt --all --check # formatting: no diff
cargo clippy --workspace --all-targets -- -D warnings # lints: every warning is an error
cargo test --workspace # unit, integration, and doc tests

The “worse” check misses every Clippy warning, and formatting changes make the diff noisy. Without set -e, a failed build does not even stop the script. The “better” gate stops at the first failure, and treats warnings as errors. It takes a few seconds more, and it removes a whole class of review comments.

  1. Which command gives the fastest feedback on whether code type-checks?

    Show the answer

    cargo check. It runs the compiler’s checks without generating a binary.

  2. The compiler says help: consider cloning the value. Should you accept that fix?

    Show the answer

    Not by default. Read the other suggestions first. Borrowing instead of taking ownership is usually the better fix. A clone is right only when two owners really need their own copy.

  3. Which Clippy groups are on by default?

    Show the answer

    correctness (as errors), and suspicious, style, complexity, and perf (as warnings). pedantic, nursery, restriction, and cargo are off.

  4. What does -D warnings do in cargo clippy -- -D warnings?

    Show the answer

    It turns every warning into an error, so the command fails if any warning is left.