All jobs

Find Dead Code in a Rust Workspace

Yes. An agent builds your Rust workspace with and without its features, traces every public item to its callers, and reports what can go, with semver impact.

Run this on RushIn a Project that has your repository.

What the agent does

The agent starts from the lints the workspace already enforces, because they decide what the compiler will and will not report. In a workspace like rust-lang/mdBook, the root Cargo.toml lists the mdbook binary crate plus crates/*: mdbook-core, mdbook-driver, mdbook-html, mdbook-markdown, mdbook-preprocessor, mdbook-renderer, mdbook-summary, mdbook-compare and xtask, all on edition 2024 with rust-version = "1.88.0". [workspace.lints.rust] sets unreachable_pub, missing_docs and rust_2018_idioms to warn, and [workspace.lints.clippy] allows everything but correctness and complexity, and .github/workflows/main.yml runs cargo clippy --workspace --all-targets --no-deps -- -D warnings, so an item the compiler can prove unused within one crate is already a CI failure. Dead code here is the kind the compiler cannot see: a pub function in a library crate that no other crate in the workspace calls.

So the agent builds the call graph itself. It runs cargo build --workspace --all-targets and cargo clippy first to confirm the baseline is clean, then cargo test --workspace --no-default-features and cargo build --workspace --no-default-features, because the root crate's default = ["watch", "serve", "search"] features gate notify, axum, tokio and tower-http behind dep: entries, and an item that is only reachable with a feature on is not dead. For every pub and pub(crate) item in the library crates it searches the whole workspace, including tests/testsuite, examples and guide/guide-helper, for a use, and it reads the one existing #[allow(dead_code, reason = "currently only used in search")] in crates/mdbook-html/src/html/tree.rs as a marker the maintainers already left for themselves.

It separates what is removable from what is published. mdbook-core, mdbook-preprocessor and mdbook-renderer are the API that third-party preprocessors and renderers compile against, and CI runs cargo semver-checks --workspace, so an unused public function there is not dead code but a breaking change, and the report says so instead of proposing to delete it. Items that are pub only because a sibling module once needed them get the pub(crate) or private visibility that unreachable_pub would then enforce; test helpers in tests/testsuite that no test calls, example code in examples that nothing references, and dependencies in a crate's Cargo.toml that no use or path mentions, checked with cargo machete, go in their own sections.

The front end is part of the workspace too. package.json runs ESLint over crates/mdbook-html/front-end/*js and the .js.hbs templates, so the agent runs npm run lint with no-unused-vars reported rather than ignored, and looks for theme files under crates/mdbook-html/src/theme that no Handlebars template or include_str! references. The result is dead-code.md with every item, its file and line, the search that found no caller, the feature set it was checked under, and whether removing it is a patch, a minor or a breaking change. The agent changes no code and opens no pull request.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Report the dead code in this Rust workspace without changing anything. Read the root Cargo.toml including its workspace lints and features, every crate's Cargo.toml under crates, .github/workflows/main.yml, package.json and rustfmt.toml first. Run cargo build --workspace --all-targets and cargo clippy --workspace --all-targets --no-deps -- -D warnings to confirm the baseline, then build and test with --no-default-features and record which items are only reachable with the watch, serve or search features on. For every pub and pub(crate) item in the library crates, search the whole workspace including tests, examples and guide for a use and list the ones with none. Mark items in crates that third-party preprocessors or renderers compile against as public API whose removal cargo semver-checks would flag, and propose a visibility reduction or a deprecation instead of deletion for those. Run cargo machete or an equivalent for unused dependencies per crate, run npm run lint over the front-end JavaScript with unused variables reported, and look for theme files nothing references. Write dead-code.md: the commands and their output, then one section each for safely removable items, items to make pub(crate) or private, unused dependencies, unused test and example code, front-end findings, and public API that looks unused but must stay, each entry with file and line, the evidence, and the semver impact. Change no code and open no pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

What comes back is dead-code.md as an artifact on the session, with a download link the session read returns. It opens with the commands the agent ran and what they printed, so a reader knows the workspace built cleanly with the default features and without them before any item was judged, and which items changed status between the two builds.

The body is six sections. Items that can be deleted today, with file and line and the rg search that found no caller. Items that should lose pub so the existing unreachable_pub lint keeps them honest. Dependencies no crate uses. Test helpers and example code nothing runs. Front-end JavaScript and theme files nothing references. And the public API in mdbook-core, mdbook-preprocessor and mdbook-renderer that has no caller inside the workspace but is there for external crates, listed so nobody deletes it by mistake, with the cargo semver-checks consequence spelled out.

A reviewer reads the first two sections against the code, decides which removals to take, and sends a follow-up message to the same session asking for a pull request with those deletions, since the sandbox still has the workspace built and cargo test --workspace --locked ready to run on the result.

Run it on every first morning of the month

In the Project that has your repository, add an automation with this prompt and a schedule trigger, cron set to 0 7 1 * * with your timezone, which fires at seven on the first day of each month. Each run starts in the Project's repository at its default branch, writes a fresh dead-code.md, and the artifact is on the session for the team to read.

Since the automation's run has no key behind it, the report is collected from the session rather than from a key webhook; a team member reads the artifact in the console or a script lists the Project's sessions and downloads it.

The use case this job follows, with its automation and trigger: Produce a report or file, no repo.

Why run it on Rush?

Finding dead code in a Rust workspace is not one command. The compiler reports unused private items, unreachable_pub reports over-exposed ones, and nothing reports a public function that no crate calls, so the search is a build under each feature set plus a grep per item plus a judgment about what is published. On a laptop that work is abandoned halfway. In a Rush sandbox the agent runs every build, keeps the output in the transcript, and finishes the list.

The report is checkable. Each entry carries the search that found no caller and the feature set it was built under, and the public-API section stops a well-meaning cleanup from becoming a breaking release that cargo semver-checks catches only after the fact. The same prompt runs on any Rust workspace without changes.

Frequently asked questions

Why doesn't the compiler already report this?

The dead_code lint works within one crate and treats every pub item of a library as used, because anything outside the crate might call it. In a workspace of nine crates most code is pub for the benefit of a sibling crate, so the compiler is silent about a function whose only caller was removed last year. The agent does the cross-crate search the compiler does not.

Will it propose deleting public API?

No. Items in the crates that third-party preprocessors and renderers depend on are listed separately as public API with no internal caller, with a note that CI's cargo semver-checks would flag their removal as breaking. The report proposes deprecation or a visibility change for those, and deletion only for items the workspace alone can reach.

What about code behind features?

The agent builds and tests twice, with the default watch, serve and search features and with --no-default-features, and records which items are only reachable with a feature on. Those are not dead, and the report says which feature keeps each one alive.

Does it cover the JavaScript and theme files too?

Yes. The workspace's package.json already lints the front-end files under crates/mdbook-html/front-end, so the agent runs that with unused variables reported and checks that each theme file is referenced by a template or an include_str!. Findings there sit in their own section.

Can it make the removals?

Not in this run; the report changes nothing. A follow-up message to the same session naming the sections to apply asks the agent to delete those items, run cargo test --workspace --locked and cargo clippy with warnings denied, and open a pull request.