openai-codex-rust-patterns
Installation
SKILL.md
OpenAI Codex Rust Best Practices
Distilled from openai/codex codex-rs/ — a 72-crate, 1,418-file Rust workspace that ships the Codex CLI coding agent. Contains 60 rules across 10 categories, each citing the exact file in codex-rs where the pattern lives, so you can write Rust the way its top contributors (Michael Bolin, jif-oai, Ahmed Ibrahim, Eric Traut, Pavel Krymets) actually ship it.
When to Apply
Reference these guidelines when:
- Writing or reviewing async Rust code that spawns tokio tasks, owns cancellation tokens, or manages long-lived background workers.
- Designing error enums,
Resultflows, retry loops, or layer boundaries in a library or service. - Building a CLI tool that spawns subprocesses, enforces sandboxing, or runs LLM-generated code safely.
- Architecting a Cargo workspace with more than ~5 crates, deciding what to split out, and how to manage shared dependencies.
- Adding tests to a Rust codebase where existing tests are inline
mod tests { ... }blocks and scaling is becoming painful. - Implementing a JSON-RPC or custom wire protocol with serde — especially one that must evolve without breaking clients.
- Wiring OpenTelemetry traces, logs, or metrics into a service that has privacy constraints around PII.
- Building a Ratatui-based TUI that streams LLM output, handles paste bursts, or manages raw-mode terminal state.
- Hardening a binary against debugger attach, LD_PRELOAD, or environment-variable tampering.
- Any time you find yourself reaching for
.unwrap(),anyhow::Result<()>, or#[cfg(feature = "test")]— this skill explains what codex does instead.
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Defensive Coding & Panic Discipline | CRITICAL | defensive- |
| 2 | Error Handling & Result Discipline | CRITICAL | errors- |
| 3 | Async, Concurrency & Cancellation | HIGH | async- |
| 4 | Sandboxing & Process Isolation | HIGH | sandbox- |
| 5 | Type Design & Invariants | HIGH | types- |
| 6 | Testing Architecture | MEDIUM-HIGH | testing- |
| 7 | Protocol & Serde Design | MEDIUM-HIGH | proto- |
| 8 | Workspace & Crate Organization | MEDIUM | workspace- |
| 9 | Observability & Tracing | MEDIUM | otel- |
| 10 | TUI (Ratatui) Rendering | MEDIUM | tui- |
Quick Reference
1. Defensive Coding & Panic Discipline (CRITICAL)
defensive-deny-unwrap-workspace-wide— Deny unwrap and expect at the workspace level, opt in locally.defensive-debug-assert-with-early-return— Use debug_assert(false) with a safe fallback on unreachable branches.defensive-banned-interpreter-prefixes— Avoid learning allowlist rules for general-purpose interpreters.defensive-head-tail-output-buffer— Cap subprocess output with a head-and-tail ring buffer.defensive-io-drain-timeout-grandchildren— Time out the I/O drain task separately from the child process.defensive-canonicalize-approval-cache-key— Canonicalize shell wrappers before hashing approval keys.defensive-refuse-to-run-unsandboxed— Refuse to run when the sandbox cannot enforce the requested policy.
2. Error Handling & Result Discipline (CRITICAL)
errors-exhaustive-retryable-match— Classify retryable errors with an exhaustive match on every variant.errors-transient-permanent-type-split— Encode transient vs permanent outcomes as two enum variants.errors-carry-retry-delay-in-variant— Carry the server-requested retry delay inside the error variant.errors-boundary-error-translator— Translate errors at the layer boundary in a single function.errors-struct-display-payload— Put display-relevant error state in a struct, not a preformatted string.errors-tool-call-respond-vs-fatal— Split tool errors into respond-to-model and fatal variants.errors-io-error-with-context-struct— Wrap io::Error in a struct with a context field instead of anyhow.
3. Async, Concurrency & Cancellation (HIGH)
async-abort-on-drop-handle— Use Arc so dropped owners auto-cancel tasks.async-graceful-then-forceful-cancel— Cancel cooperatively first, then abort after a grace deadline.async-biased-select-for-cancellation— Use biased select to make cancellation always win race ties.async-bounded-vs-unbounded-channel-split— Bound the submission channel but leave the event channel unbounded.async-child-cancellation-tokens— Give spawned sub-tasks child tokens, not clones of the parent.async-shared-boxfuture-joinhandle— Wrap a background JoinHandle in Shared for multi-waiter joins.
4. Sandboxing & Process Isolation (HIGH)
sandbox-shared-policy-data-model— Keep sandbox policy as shared data, not per-platform code.sandbox-staged-restrictions-re-exec— Stage incompatible restrictions by re-executing the same binary.sandbox-argv0-multiplex-binary— Multiplex helper binaries via argv[0] and symlinks.sandbox-dev-null-first-missing-mount— Mount /dev/null over the first missing path to block mkdir escapes.sandbox-three-layer-network-isolation— Stack env vars, seccomp, and namespaces for network isolation.sandbox-env-clear-pre-exec— Clear the env and tether children via pre_exec before every spawn.
5. Type Design & Invariants (HIGH)
types-thread-local-raii-serde— Pass deserializer context via a thread-local RAII guard.types-dyn-safe-adapter-trait— Pair an ergonomic trait with a private dyn-safe adapter trait.types-try-from-newtype-validation— Use serde try_from on a newtype to run validation on every parse.types-full-reference-hierarchy— Implement Borrow, AsRef, and Deref on every public ID newtype.types-non-exhaustive-public-enums— Mark every public wire-level enum non_exhaustive from the start.types-unknown-variant-forward-compat— Preserve unrecognized values in an Unknown variant.
6. Testing Architecture (MEDIUM-HIGH)
testing-path-attribute-sibling-tests— Attach tests as sibling files via #[path] instead of inline mod tests.testing-wiremock-sse-fakes— Fake the network with wiremock and small SSE event constructors.testing-atomic-bool-test-opt-in— Gate test-only behavior with an AtomicBool, not a cargo feature.testing-config-closure-builder— Configure test fixtures with a closure builder.testing-insta-snapshot-tui-rendering— Snapshot terminal rendering with insta for stable UI diffs.testing-paused-runtime-advance— Use start_paused and advance to make timing-dependent tests deterministic.
7. Protocol & Serde Design (MEDIUM-HIGH)
proto-internally-tagged-rpc-dispatch— Dispatch JSON-RPC by an internally tagged enum with a macro.proto-double-option-tri-state— Use Option<Option> to distinguish absent, null, and set.proto-rename-alias-wire-migration— Pair rename and alias to migrate wire names without breaking clients.proto-experimental-runtime-gate— Gate experimental fields by runtime presence, not capability flags.proto-sse-idle-timeout-terminator— Treat SSE streams as idle-timeout with required terminator.proto-internal-vs-wire-error-split— Split internal error enums from wire error enums.
8. Workspace & Crate Organization (MEDIUM)
workspace-ban-per-crate-features— Avoid per-crate features; use target-cfg or separate crates instead.workspace-single-source-dependencies— Declare every dependency version once in workspace.dependencies.workspace-layered-transport-api-core— Stack HTTP layers as transport, api, and core crates.workspace-test-support-as-member-crates— Register shared test helpers as workspace member crates.workspace-utils-microcrate-fanout— Place shared utilities in single-purpose microcrates under utils/.workspace-lint-config-package— Encode policy in workspace.lints and clippy.toml.
9. Observability & Tracing (MEDIUM)
otel-log-only-vs-trace-safe-targets— Route PII to log-only targets and keep traces cardinality-safe.otel-field-empty-then-record— Declare span fields as field::Empty, then record them when known.otel-layered-subscribers-env-filter— Build per-layer EnvFilter instances with boxed fmt layers.otel-w3c-traceparent-propagation— Propagate W3C traceparent via env vars, JSON-RPC, and HTTP headers.otel-instrument-at-trace-level— Default #[instrument] to trace level, reserve info for network calls.
10. TUI (Ratatui) Rendering (MEDIUM)
tui-two-gear-hysteresis-chunking— Replace fixed throttles with hysteresis-gated smooth and catch-up modes.tui-schedule-frame-coalescer— Coalesce redraws through a FrameRequester actor and rate limiter.tui-drop-guard-panic-hook-chain— Restore terminal state via a Drop guard and a chained panic hook.tui-paste-burst-state-machine— Detect unbracketed paste bursts via a character timing state machine.tui-event-broker-pause-resume— Pause the event stream by dropping it before a subprocess handoff.
How to Use
Read individual reference files for detailed explanations and code examples cited from codex-rs/:
- Section definitions — Category structure, impact levels, and prefixes
- AGENTS.md — Auto-generated navigation document compiling every rule
Each rule file contains:
- Imperative title matching its frontmatter
- 2–4 sentence explanation of the WHY
- Incorrect example showing the naive approach
- Correct example from codex-rs with the file path cited
Reference Files
| File | Description |
|---|---|
| AGENTS.md | Auto-built TOC document compiling every rule |
| README.md | Skill repository docs — contribution, structure, commands |
| references/_sections.md | Category definitions and ordering |
| gotchas.md | Failure points discovered while applying these rules |
| metadata.json | Version, discipline, references to codex-rs |