Adversarial Rust
An adversarial, architecture-level review-and-refactor pass for Rust. Where a greenfield idiom skill answers "which tool should I reach for now?", this skill takes code that already exists and imported the wrong mental model — objects and interfaces from Java/C#, shared-everything graphs from garbage-collected languages, exceptions, C-style loops and sentinels, detached-promise concurrency — names the paradigm it betrays, and prescribes the refactor that collapses it back to idiomatic Rust.
Every rule is grounded in a single production codebase: the codex-rs workspace (github.com/openai/codex, codex-rs/ at commit f1affbac5e, ~125 crates / ~2,500 Rust files). The Correct side of each rule is what that codebase actually does, the enforcement evidence is its workspace lint config (unwrap_used, redundant_clone, needless_collect, await_holding_lock and ~30 more denied), and the carve-outs are the real exceptions it keeps — so "when NOT to apply" is never hypothetical. There is no rule for things a capable model already gets right.
When to Apply
- Reviewing or refactoring existing Rust for architecture, not just style — "make this actually idiomatic", "why does this feel like Java in Rust"
- Flattening ported ceremony — dependency-injection traits with one implementation,
Deref-simulated inheritance, stateless*Manager/*Servicestructs, getter/setter boilerplate, a builder for every struct - Untangling fought ownership —
.clone()sprinkled until it compiles,Rc<RefCell<T>>object graphs, self-referential struct attempts - Fixing anemic data — boolean/string state machines, parallel
Optionfields, raw primitives carrying domain meaning, god-structs ofOptions escaping the serde boundary - Removing exception-style flow —
unwrapon expected failures, sentinel returns,catch_unwindas try/catch,anyhowon library API surfaces - Collapsing habitual indirection —
Box<dyn Trait>for closed sets, boxed callback parameters, index loops and per-stepcollect()chains - Repairing imported concurrency habits — blocking calls inside
async fn, guards held across.await, async task fan-out for CPU-bound work, fire-and-forgettokio::spawn
For greenfield "which pattern, which crate, which discipline" decisions while writing new Rust — async cancellation, error enum design, sandboxing, testing architecture — use openai-codex-rust-patterns instead; this skill is its diagnostic, layer-flattening counterpart drawn from the same codebase.
Rule Categories
| # | Category | Prefix | The alien model it rips out |
|---|---|---|---|
| 1 | Enterprise Ceremony & Fake OO | arch- |
DI traits, Deref inheritance, Manager structs, getter ceremony, reflexive builders → concrete types, delegation, module functions, public fields, struct literals |
| 2 | Ownership Fought, Not Used | own- |
clone-to-compile, Rc graphs, self-referential structs → designed clones, owning ID-keyed maps, single owners |
| 3 | Anemic & Stringly Data | type- |
bool/String states, parallel Options, raw primitives, escaped god-structs → data-carrying enums, newtypes, one wire-to-domain resolve |
| 4 | Exception-Style Control Flow | flow- |
unwrap-as-handling, sentinels, catch_unwind, opaque library errors → Result + ?, Option, thiserror enums, anyhow at the rim |
| 5 | Dynamic Dispatch by Habit | dyn- |
Box for closed sets, boxed callback params → tagged enums, generic Fn at the API, channels over listeners |
| 6 | Imperative Iteration | iter- |
index loops, mut accumulators, collect-per-step → named combinators, one lazy chain, collect into Result |
| 7 | Concurrency From Another Runtime | conc- |
blocking in async, guards across await, async CPU fan-out, orphan spawns → spawn_blocking, narrowed locks, bounded thread pools, owned handles |
Quick Reference
1. Enterprise Ceremony & Fake OO
arch-drop-di-trait-single-impl— delete the DI trait with one implementation; codex-rs shipsModelClientandSessionconcretearch-no-deref-inheritance— all 18 codex-rsDerefimpls are newtypes or smart pointers; zero simulate a hierarchyarch-free-functions-over-manager-struct— stateless capability = module functions (git-utils,apply-patch); a*Managerearns its name by owning statearch-public-fields-over-getter-ceremony—Configand every protocol type are all-pub; accessors exist only where an invariant livesarch-default-literal-over-builder— 1,787 struct literals with..Default::default()vs 16 builders; a builder needs staged construction to earn itself
2. Ownership Fought, Not Used
own-restructure-over-clone— surviving clones are designed (Copy IDs, Arc bumps, lock snapshots); a compile-fixing clone forks dataown-no-rc-refcell-object-graph— zeroRc<RefCell>in ~2,500 files; narrow Mutex fields, channels, or ID maps insteadown-id-map-over-self-referential— graphs live inHashMap<ThreadId, Arc<CodexThread>>; cross-references are IDs, never references
3. Anemic & Stringly Data
type-enum-over-bool-string-state— variants own their fields (SandboxPolicy); its external-sandbox variant types even yes/no asNetworkAccess, notbooltype-result-over-parallel-options— oneOptionper shape isCodexAuthin denial; found/missing/failed isResult<Option<T>, E>type-newtype-parse-dont-validate— parse once intoThreadId/AgentPath; model names stayStringbecause no invariant existstype-split-option-god-struct—ConfigToml(91 of 97 fields are Options) is fine on the wire; resolve it once into richConfig
4. Exception-Style Control Flow
flow-result-over-unwrap-expected—unwrap_used/expect_useddenied workspace-wide; escapes carry#[expect]+ a written invariantflow-option-over-sentinel-values— lookups returnOption;-1exists only at the OS exit-code boundaryflow-no-catch-unwind-try-catch— every codex-rs production use supervises a foreign fault domain; none catch expected failuresflow-thiserror-library-anyhow-application—CodexErr/ApiError/TransportErrorper layer;anyhowatmain()
5. Dynamic Dispatch by Habit
dyn-enum-over-box-dyn-closed-set—Op/EventMsg/TurnItemare enums;dynis the tool registry others extend at runtimedyn-generics-over-boxed-callbacks— genericF: Fnat the API, box only for storage, channels instead of listener registration
6. Imperative Iteration
iter-combinator-over-index-loop— 13manual_*lints denied;forsurvives for awaits, side effects, index-as-data, FFIiter-stay-lazy-single-collect— one lazy chain;collect::<Result<Vec<_>, _>>()is the fallible-pipeline idiom (49 production uses)
7. Concurrency From Another Runtime
conc-spawn-blocking-over-blocking-async— ~50spawn_blockingsites: git, file locks, zstd, OAuth serversconc-narrow-locks-before-await— even tokio guards may not cross.await; snapshot out or#[expect]with an atomicity reasonconc-blocking-pool-over-async-cpu-fanout— no rayon; CPU fan-out on bounded OS threads behind onespawn_blockingconc-own-spawned-task-handles—AbortOnDropHandle+ childCancellationToken; interrupt is cancel → grace window → abort
How to Use
Read a reference file when its smell shows up in the code under review. Each rule names the alien pattern, explains why Rust rejects it, and shows the refactor with real codex-rs names and a permalink into the codebase at the pinned commit. Prefer the deepest refactor the change budget allows — redesigning ownership beats sprinkling clone; deleting the DI trait beats mocking through it. Every example compiles on Rust 1.86 (2021 edition).
- Section definitions — category structure and ordering
- Rule template — for adding new rules
- AGENTS.md — auto-built table of contents across all rules
Related Skills
openai-codex-rust-patterns— the greenfield counterpart distilled from the same codex-rs workspace: which pattern to reach for while writing production Rust (async cancellation, error enum design, sandboxing, testing, workspace layout). Use it for authoring decisions; use this skill for adversarial review and ceremony-flattening refactors. Several rules here hand off to it once the flatten is done (flow-thiserror-library-anyhow-application→ itserrors-rules,flow-result-over-unwrap-expected→defensive-deny-unwrap-workspace-wide,arch-drop-di-trait-single-impl→ its testing seams).
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and source references |