Rust Architecture Review
Review Rust architecture for deep modules: small, honest interfaces with useful
behavior behind them. The default output is a chat-only Markdown report. Do not
edit files, create tasks, create Linear issues, write reports to disk, or open
browser artifacts unless the user separately asks.
Vocabulary
Use these words consistently in findings:
- Module: anything with an interface and an implementation. In Rust this can
be a crate,
mod, type, trait, function, or vertical slice.
- Interface: everything callers must know to use the module correctly. In
Rust this includes
pub items, trait bounds, feature-gated APIs, error
contracts, ownership and lifetime obligations, async and Send/Sync
expectations, allocation behavior, and panic behavior.
- Implementation: the code behind the interface.
- Depth: leverage at the interface. A deep module hides meaningful
behavior behind a small interface. A shallow module exposes nearly as much
complexity as it contains.
- Seam: where behavior can vary without editing callers.
- Adapter: concrete code that satisfies an interface at a seam.
- Leverage: what callers get from depth.
- Locality: what maintainers get from depth: changes, bugs, and verification
concentrated in one place.
Principles:
- Deletion test: if deleting a module makes complexity disappear, it was
pass-through. If complexity reappears across callers, the module was earning
its keep.
- The interface is the test surface: tests should prove behavior through the
same surface callers use.
- One adapter is hypothetical. Two adapters are real: avoid trait seams when
only one concrete implementation exists, unless a test or platform adapter is
genuinely different.
Explore
Start by reading project rules and architectural context when present:
AGENTS.md, CLAUDE.md, TARGET.md, CONTEXT.md
docs/adr/, architecture docs, design notes
Cargo.toml, workspace manifests, crate manifests
rust-toolchain.toml, .cargo/config.toml
clippy.toml, deny.toml
justfile, Makefile, CI workflows
Then inspect the Rust shape:
- discover workspace members and binary/library crates
- map important
src/lib.rs, src/main.rs, mod.rs, and top-level modules
- inspect
pub, pub(crate), re-exports, feature gates, and trait surfaces
- trace callers for suspected shallow modules with
rg
- inspect tests and integration-test entry points
- note semver constraints for library crates and deployment constraints for
binary/internal crates
Do not mutate repository state during review.
Rust Review Lens
Look for architecture friction that Rust makes visible:
- Public surface sprawl: too many exported types, helpers, or re-exports for
callers to assemble correctly.
- Trait overuse: traits created for one implementation, mocking only, or
speculative extension.
- Concrete-type leakage: callers forced to know storage, transport,
allocation, locking, or serialization details.
- Ownership leakage: awkward lifetimes, borrowed data, clones, or
Arc
usage pushed onto callers because the module shape is wrong.
- Concurrency leakage:
Arc<Mutex<_>>, channels, task handles, or lock
ordering escaping into call sites.
- Async leakage: async boundaries chosen because internals are async, not
because callers need an async interface.
- Error leakage: callers matching internal error details, using
anyhow
where typed errors are part of the contract, or exposing typed errors where
callers cannot act on them.
- Panic contracts: production or library paths using
unwrap, expect, or
panic where callers need recoverable errors.
- Unsafe spread:
unsafe code not isolated behind a narrow checked module,
or missing SAFETY comments at the operation.
- Feature-flag coupling: callers forced to mirror internal feature
combinations or conditional types.
- Test-only extraction: small functions/modules created only so tests can
reach internals while the real behavior remains untested at the interface.
- Hot-path cost leakage: clones, allocations, boxing, dynamic dispatch, or
serialization forced by a shallow interface.
Apply the deletion test to each suspect module. Prefer recommendations that
delete shallow wrappers or absorb scattered logic into one deeper module.
Deepening Guidance
Choose the smallest refactor that improves leverage and locality.
- For in-process logic, collapse shallow modules and test through the new public
or
pub(crate) interface.
- For local-substitutable dependencies, keep the external interface concrete and
test with the local substitute when available.
- For owned remote dependencies, use a port only when the production adapter and
test adapter differ in real behavior.
- For third-party dependencies, hide the vendor contract behind a narrow module
that returns domain-level outcomes.
- For binary/internal crates, prefer aggressive
pub(crate) cleanup.
- For public library crates, preserve semver or explicitly mark proposed
breaking changes.
- Prefer concrete types until real variation justifies a trait.
- Keep internal seams private to the implementation unless callers genuinely
need variation.
Do not recommend broad rewrites. Recommend staged refactors that can be proven
with tests and reviewed incrementally.
Report Format
Return a concise Markdown report in chat:
If no findings are found, say that clearly and omit empty sections.
## Summary
- <one to three bullets on the architecture shape>
## Findings
### [<Severity>] <Title>
Confidence: <High|Medium|Low>
Files: `<path>`, `<path>`
Problem:
<what hurts and where complexity leaks>
Proposed refactor:
<specific module/interface change>
Rust notes:
<ownership, errors, async, traits, unsafe, semver, allocation, or test impact>
Tests:
- <behavior to prove through the interface>
Depth/locality:
<why the result hides more behavior or concentrates change>
## Speculative Candidates
- <only low-confidence ideas worth later exploration>
## Top Recommendation
<the first change to make and why>
## Optional Follow-up Plan
- <small ordered implementation steps if useful>
Severity:
Critical: correctness, data loss, security, undefined behavior, or production
panic/unwrap risk caused by architecture.
Major: coupling, testability, public surface, error, async, or ownership
problems likely to slow or break future work.
Minor: cleanup that improves locality or clarity but is not urgent.
Confidence:
High: directly supported by code and callers.
Medium: supported by patterns but needs implementer confirmation.
Low: plausible but not enough evidence for a finding; put these under
Speculative Candidates.
Guardrails
- Do not propose trait extraction just for mocking.
- Do not add a seam with one real adapter unless a second adapter is justified.
- Do not treat a Rust trait as the only form of interface.
- Do not recommend changing public library APIs without calling out semver
impact.
- Do not delete shallow unit tests until replacement behavior tests exist.
- Do not present style preferences as architecture findings.
- Do not re-litigate ADRs unless current friction is strong enough to justify
reopening the decision.
- Do not invent domain names when
CONTEXT.md or docs already define them.
When Asked To Design The Refactor
If the user picks a finding and asks for an implementation design, produce two
or three alternative Rust interfaces before recommending one:
- minimal interface: few entry points, maximum leverage
- caller-optimized interface: common case is trivial
- adapter-based interface: only when real variation exists
For each alternative, show:
- proposed types/functions/traits
- caller example
- hidden implementation details
- error and panic contract
- testing strategy
- semver or migration impact
1---2name: rust-architecture-review3description: Review Rust codebase architecture and recommend improvements. Use when the user asks to assess Rust crate or module structure, public surfaces, trait/interface depth, coupling, testability, ownership leaks, async boundaries, unsafe isolation, or refactoring opportunities that make Rust code easier to reason about and verify.4---56# Rust Architecture Review78Review Rust architecture for deep modules: small, honest interfaces with useful9behavior behind them. The default output is a chat-only Markdown report. Do not10edit files, create tasks, create Linear issues, write reports to disk, or open11browser artifacts unless the user separately asks.1213## Vocabulary1415Use these words consistently in findings:1617- **Module**: anything with an interface and an implementation. In Rust this can18 be a crate, `mod`, type, trait, function, or vertical slice.19- **Interface**: everything callers must know to use the module correctly. In20 Rust this includes `pub` items, trait bounds, feature-gated APIs, error21 contracts, ownership and lifetime obligations, async and `Send`/`Sync`22 expectations, allocation behavior, and panic behavior.23- **Implementation**: the code behind the interface.24- **Depth**: leverage at the interface. A **deep** module hides meaningful25 behavior behind a small interface. A **shallow** module exposes nearly as much26 complexity as it contains.27- **Seam**: where behavior can vary without editing callers.28- **Adapter**: concrete code that satisfies an interface at a seam.29- **Leverage**: what callers get from depth.30- **Locality**: what maintainers get from depth: changes, bugs, and verification31 concentrated in one place.3233Principles:3435- **Deletion test**: if deleting a module makes complexity disappear, it was36 pass-through. If complexity reappears across callers, the module was earning37 its keep.38- **The interface is the test surface**: tests should prove behavior through the39 same surface callers use.40- **One adapter is hypothetical. Two adapters are real**: avoid trait seams when41 only one concrete implementation exists, unless a test or platform adapter is42 genuinely different.4344## Explore4546Start by reading project rules and architectural context when present:4748- `AGENTS.md`, `CLAUDE.md`, `TARGET.md`, `CONTEXT.md`49- `docs/adr/`, architecture docs, design notes50- `Cargo.toml`, workspace manifests, crate manifests51- `rust-toolchain.toml`, `.cargo/config.toml`52- `clippy.toml`, `deny.toml`53- `justfile`, `Makefile`, CI workflows5455Then inspect the Rust shape:5657- discover workspace members and binary/library crates58- map important `src/lib.rs`, `src/main.rs`, `mod.rs`, and top-level modules59- inspect `pub`, `pub(crate)`, re-exports, feature gates, and trait surfaces60- trace callers for suspected shallow modules with `rg`61- inspect tests and integration-test entry points62- note semver constraints for library crates and deployment constraints for63 binary/internal crates6465Do not mutate repository state during review.6667## Rust Review Lens6869Look for architecture friction that Rust makes visible:7071- **Public surface sprawl**: too many exported types, helpers, or re-exports for72 callers to assemble correctly.73- **Trait overuse**: traits created for one implementation, mocking only, or74 speculative extension.75- **Concrete-type leakage**: callers forced to know storage, transport,76 allocation, locking, or serialization details.77- **Ownership leakage**: awkward lifetimes, borrowed data, clones, or `Arc`78 usage pushed onto callers because the module shape is wrong.79- **Concurrency leakage**: `Arc<Mutex<_>>`, channels, task handles, or lock80 ordering escaping into call sites.81- **Async leakage**: async boundaries chosen because internals are async, not82 because callers need an async interface.83- **Error leakage**: callers matching internal error details, using `anyhow`84 where typed errors are part of the contract, or exposing typed errors where85 callers cannot act on them.86- **Panic contracts**: production or library paths using `unwrap`, `expect`, or87 panic where callers need recoverable errors.88- **Unsafe spread**: `unsafe` code not isolated behind a narrow checked module,89 or missing `SAFETY` comments at the operation.90- **Feature-flag coupling**: callers forced to mirror internal feature91 combinations or conditional types.92- **Test-only extraction**: small functions/modules created only so tests can93 reach internals while the real behavior remains untested at the interface.94- **Hot-path cost leakage**: clones, allocations, boxing, dynamic dispatch, or95 serialization forced by a shallow interface.9697Apply the deletion test to each suspect module. Prefer recommendations that98delete shallow wrappers or absorb scattered logic into one deeper module.99100## Deepening Guidance101102Choose the smallest refactor that improves leverage and locality.103104- For in-process logic, collapse shallow modules and test through the new public105 or `pub(crate)` interface.106- For local-substitutable dependencies, keep the external interface concrete and107 test with the local substitute when available.108- For owned remote dependencies, use a port only when the production adapter and109 test adapter differ in real behavior.110- For third-party dependencies, hide the vendor contract behind a narrow module111 that returns domain-level outcomes.112- For binary/internal crates, prefer aggressive `pub(crate)` cleanup.113- For public library crates, preserve semver or explicitly mark proposed114 breaking changes.115- Prefer concrete types until real variation justifies a trait.116- Keep internal seams private to the implementation unless callers genuinely117 need variation.118119Do not recommend broad rewrites. Recommend staged refactors that can be proven120with tests and reviewed incrementally.121122## Report Format123124Return a concise Markdown report in chat:125126If no findings are found, say that clearly and omit empty sections.127128```markdown129## Summary130- <one to three bullets on the architecture shape>131132## Findings133134### [<Severity>] <Title>135Confidence: <High|Medium|Low>136Files: `<path>`, `<path>`137138Problem:139<what hurts and where complexity leaks>140141Proposed refactor:142<specific module/interface change>143144Rust notes:145<ownership, errors, async, traits, unsafe, semver, allocation, or test impact>146147Tests:148- <behavior to prove through the interface>149150Depth/locality:151<why the result hides more behavior or concentrates change>152153## Speculative Candidates154- <only low-confidence ideas worth later exploration>155156## Top Recommendation157<the first change to make and why>158159## Optional Follow-up Plan160- <small ordered implementation steps if useful>161```162163Severity:164165- `Critical`: correctness, data loss, security, undefined behavior, or production166 panic/unwrap risk caused by architecture.167- `Major`: coupling, testability, public surface, error, async, or ownership168 problems likely to slow or break future work.169- `Minor`: cleanup that improves locality or clarity but is not urgent.170171Confidence:172173- `High`: directly supported by code and callers.174- `Medium`: supported by patterns but needs implementer confirmation.175- `Low`: plausible but not enough evidence for a finding; put these under176 Speculative Candidates.177178## Guardrails179180- Do not propose trait extraction just for mocking.181- Do not add a seam with one real adapter unless a second adapter is justified.182- Do not treat a Rust trait as the only form of interface.183- Do not recommend changing public library APIs without calling out semver184 impact.185- Do not delete shallow unit tests until replacement behavior tests exist.186- Do not present style preferences as architecture findings.187- Do not re-litigate ADRs unless current friction is strong enough to justify188 reopening the decision.189- Do not invent domain names when `CONTEXT.md` or docs already define them.190191## When Asked To Design The Refactor192193If the user picks a finding and asks for an implementation design, produce two194or three alternative Rust interfaces before recommending one:195196- minimal interface: few entry points, maximum leverage197- caller-optimized interface: common case is trivial198- adapter-based interface: only when real variation exists199200For each alternative, show:201202- proposed types/functions/traits203- caller example204- hidden implementation details205- error and panic contract206- testing strategy207- semver or migration impact