| name | adversarial-rust |
| description | Use this skill when reviewing or refactoring existing Rust code that carries an alien mental model — OO/enterprise ceremony from Java/C#, garbage-collected object graphs, exception-style control flow, or imperative loops ported onto the borrow checker. It is the adversarial, architecture-level counterpart to greenfield idiom advice — it names the paradigm the code betrays and prescribes the deep refactor that collapses it, up to deleting whole layers (single-impl DI traits, Deref inheritance, Manager/Service structs, reflexive builders, Rc<RefCell> webs, clone-until-it-compiles, bool/String state machines, sentinel returns, catch_unwind try/catch, reflexive Box<dyn>, blocking calls inside async, fire-and-forget spawns). Every rule is grounded in the codex-rs production workspace (openai/codex) — the prescriptions are what that codebase actually does and lint-enforces. Applies whenever the work is "make this Rust actually Rust", "flatten this architecture", or a pedantic review of code fighting the language. |
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/*Service structs, 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
Option fields, raw primitives carrying domain meaning, god-structs of Options escaping the serde boundary
- Removing exception-style flow —
unwrap on expected failures, sentinel returns, catch_unwind as try/catch, anyhow on library API surfaces
- Collapsing habitual indirection —
Box<dyn Trait> for closed sets, boxed callback parameters, index loops and per-step collect() chains
- Repairing imported concurrency habits — blocking calls inside
async fn, guards held across .await, async task fan-out for CPU-bound work, fire-and-forget tokio::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
2. Ownership Fought, Not Used
3. Anemic & Stringly Data
4. Exception-Style Control Flow
5. Dynamic Dispatch by Habit
6. Imperative Iteration
7. Concurrency From Another Runtime
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).
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 → its errors- rules, flow-result-over-unwrap-expected → defensive-deny-unwrap-workspace-wide, arch-drop-di-trait-single-impl → its testing seams).
Reference Files