File contents OpenAI Codex Rust CLI Agent Best Practices
This skill teaches you to write Rust code in the style of the OpenAI Codex codebase - a production CLI/agent system with 50 crates and 787 Rust files.
Key Characteristics
Edition 2024 with strict Clippy configuration
Zero unwrap/expect in non-test code (enforced at workspace level)
Tokio async runtime with proper Send + Sync bounds
thiserror for library errors, anyhow for application code
Flat workspace structure with centralized dependencies
When to Apply
Apply this skill when:
Building CLI tools or agent systems in Rust
Writing async Rust with Tokio
Designing Rust workspace organization
Implementing error handling patterns
Working on production Rust codebases
Quick Reference
Critical Rules (Must Follow)
Rule
Description
err-no-unwrap
Never use unwrap() in non-test code
err-no-expect
Avoid expect() in library code
err-thiserror-domain
Use thiserror for domain errors
err-context-chain
Add context to errors with .context()
Error Handling
Rule
Description
err-anyhow-application
Use anyhow::Result for entry points
err-from-derive
Use #[from] for error conversion
err-transparent
Use #[error(transparent)] for wrapped errors
err-structured-variants
Include relevant data in error variants
err-io-result
Use std::io::Result for I/O functions
err-map-err-conversion
Use map_err for error conversion
err-doc-errors
Document error conditions
Organization
Rule
Description
org-workspace-flat
Flat workspace with utils subdirectory
org-crate-naming
kebab-case directories, project prefix
org-module-visibility
Use pub(crate) for internal APIs
org-test-common-crate
Shared test utilities crate
org-integration-tests-suite
Tests in suite directory
org-feature-modules
Feature-based module organization
org-handlers-subdir
Handlers in dedicated subdirectory
org-errors-file
Errors in dedicated file
Component Patterns
Rule
Description
mod-derive-order
Consistent derive macro ordering
mod-async-trait-macro
Use #[async_trait] for async traits
mod-trait-bounds
Send + Sync + 'static for concurrent traits
mod-extension-trait-suffix
Ext suffix for extension traits
mod-builder-pattern
Builder pattern for complex config
mod-type-alias-complex
Type aliases for complex generics
mod-impl-block-order
Consistent impl block ordering
mod-generic-constraints
Where clauses for complex bounds
mod-newtype-pattern
Newtypes for type safety
mod-struct-visibility
Private fields with public constructor
mod-serde-rename
Serde rename for wire format
mod-jsonschema-derive
JsonSchema for API types
Naming Conventions
Rule
Description
name-async-no-suffix
No _async suffix for async functions
name-try-prefix-fallible
try_ prefix for fallible constructors
name-with-prefix-builder
with_ prefix for builder methods
name-handler-suffix
Handler suffix for handlers
name-error-suffix
Error suffix for error types
name-result-type-alias
Crate-specific Result alias
name-const-env-var
_ENV_VAR suffix for env constants
name-request-response
Request/Response type pairing
name-options-suffix
Options suffix for config bundles
name-info-suffix
Info suffix for read-only data
name-provider-suffix
Provider suffix for services
name-client-suffix
Client suffix for API clients
name-manager-suffix
Manager suffix for lifecycle mgmt
name-bool-is-prefix
is_/has_/should_ for booleans
name-plural-collections
Plural names for collections
Style
Rule
Description
style-import-granularity
One item per use statement
style-deny-stdout
Deny stdout/stderr in libraries
style-inline-format-args
Inline format arguments
style-module-docs
Module-level documentation
style-expect-reason
#[expect] with reason for lints
style-cfg-test-module
Unit tests in mod tests
Cross-Crate
Rule
Description
cross-workspace-lints
Workspace-level lint config
cross-workspace-deps
Centralized dependency versions
Example: Proper Error Handling
use thiserror::Error;
use anyhow::Context;
// Domain error with thiserror
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("failed to read config file: {path}")]
ReadFailed {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error(transparent)]
Parse(#[from] toml::de::Error),
}
// Library function returns domain error
pub fn load_config(path: &Path) -> Result<Config, ConfigError> {
let content = fs::read_to_string(path)
.map_err(|source| ConfigError::ReadFailed {
path: path.to_owned(),
source,
})?;
toml::from_str(&content).map_err(Into::into)
}
// Application code uses anyhow with context
fn main() -> anyhow::Result<()> {
let config = load_config(Path::new("config.toml"))
.context("failed to load configuration")?;
run(config).await
}
Source
Patterns extracted from OpenAI Codex (codex-rs/ subdirectory) - a production Rust codebase with 50 crates and 787 Rust files.
1 --- 2 name: rust-cli-agent-style 3 description: OpenAI Codex Rust CLI Agent Best Practices 4 --- 5 # OpenAI Codex Rust CLI Agent Best Practices 6 7 This skill teaches you to write Rust code in the style of the OpenAI Codex codebase - a production CLI/agent system with 50 crates and 787 Rust files. 8 9 ## Key Characteristics 10 11 - **Edition 2024** with strict Clippy configuration 12 - **Zero unwrap/expect** in non-test code (enforced at workspace level) 13 - **Tokio async runtime** with proper Send + Sync bounds 14 - **thiserror** for library errors, **anyhow** for application code 15 - **Flat workspace** structure with centralized dependencies 16 17 ## When to Apply 18 19 Apply this skill when: 20 - Building CLI tools or agent systems in Rust 21 - Writing async Rust with Tokio 22 - Designing Rust workspace organization 23 - Implementing error handling patterns 24 - Working on production Rust codebases 25 26 ## Quick Reference 27 28 ### Critical Rules (Must Follow) 29 30 | Rule | Description | 31 |------|-------------| 32 | [err-no-unwrap](references/err-no-unwrap.md) | Never use `unwrap()` in non-test code | 33 | [err-no-expect](references/err-no-expect.md) | Avoid `expect()` in library code | 34 | [err-thiserror-domain](references/err-thiserror-domain.md) | Use thiserror for domain errors | 35 | [err-context-chain](references/err-context-chain.md) | Add context to errors with `.context()` | 36 37 ### Error Handling 38 39 | Rule | Description | 40 |------|-------------| 41 | [err-anyhow-application](references/err-anyhow-application.md) | Use anyhow::Result for entry points | 42 | [err-from-derive](references/err-from-derive.md) | Use #[from] for error conversion | 43 | [err-transparent](references/err-transparent.md) | Use #[error(transparent)] for wrapped errors | 44 | [err-structured-variants](references/err-structured-variants.md) | Include relevant data in error variants | 45 | [err-io-result](references/err-io-result.md) | Use std::io::Result for I/O functions | 46 | [err-map-err-conversion](references/err-map-err-conversion.md) | Use map_err for error conversion | 47 | [err-doc-errors](references/err-doc-errors.md) | Document error conditions | 48 49 ### Organization 50 51 | Rule | Description | 52 |------|-------------| 53 | [org-workspace-flat](references/org-workspace-flat.md) | Flat workspace with utils subdirectory | 54 | [org-crate-naming](references/org-crate-naming.md) | kebab-case directories, project prefix | 55 | [org-module-visibility](references/org-module-visibility.md) | Use pub(crate) for internal APIs | 56 | [org-test-common-crate](references/org-test-common-crate.md) | Shared test utilities crate | 57 | [org-integration-tests-suite](references/org-integration-tests-suite.md) | Tests in suite directory | 58 | [org-feature-modules](references/org-feature-modules.md) | Feature-based module organization | 59 | [org-handlers-subdir](references/org-handlers-subdir.md) | Handlers in dedicated subdirectory | 60 | [org-errors-file](references/org-errors-file.md) | Errors in dedicated file | 61 62 ### Component Patterns 63 64 | Rule | Description | 65 |------|-------------| 66 | [mod-derive-order](references/mod-derive-order.md) | Consistent derive macro ordering | 67 | [mod-async-trait-macro](references/mod-async-trait-macro.md) | Use #[async_trait] for async traits | 68 | [mod-trait-bounds](references/mod-trait-bounds.md) | Send + Sync + 'static for concurrent traits | 69 | [mod-extension-trait-suffix](references/mod-extension-trait-suffix.md) | Ext suffix for extension traits | 70 | [mod-builder-pattern](references/mod-builder-pattern.md) | Builder pattern for complex config | 71 | [mod-type-alias-complex](references/mod-type-alias-complex.md) | Type aliases for complex generics | 72 | [mod-impl-block-order](references/mod-impl-block-order.md) | Consistent impl block ordering | 73 | [mod-generic-constraints](references/mod-generic-constraints.md) | Where clauses for complex bounds | 74 | [mod-newtype-pattern](references/mod-newtype-pattern.md) | Newtypes for type safety | 75 | [mod-struct-visibility](references/mod-struct-visibility.md) | Private fields with public constructor | 76 | [mod-serde-rename](references/mod-serde-rename.md) | Serde rename for wire format | 77 | [mod-jsonschema-derive](references/mod-jsonschema-derive.md) | JsonSchema for API types | 78 79 ### Naming Conventions 80 81 | Rule | Description | 82 |------|-------------| 83 | [name-async-no-suffix](references/name-async-no-suffix.md) | No _async suffix for async functions | 84 | [name-try-prefix-fallible](references/name-try-prefix-fallible.md) | try_ prefix for fallible constructors | 85 | [name-with-prefix-builder](references/name-with-prefix-builder.md) | with_ prefix for builder methods | 86 | [name-handler-suffix](references/name-handler-suffix.md) | Handler suffix for handlers | 87 | [name-error-suffix](references/name-error-suffix.md) | Error suffix for error types | 88 | [name-result-type-alias](references/name-result-type-alias.md) | Crate-specific Result alias | 89 | [name-const-env-var](references/name-const-env-var.md) | _ENV_VAR suffix for env constants | 90 | [name-request-response](references/name-request-response.md) | Request/Response type pairing | 91 | [name-options-suffix](references/name-options-suffix.md) | Options suffix for config bundles | 92 | [name-info-suffix](references/name-info-suffix.md) | Info suffix for read-only data | 93 | [name-provider-suffix](references/name-provider-suffix.md) | Provider suffix for services | 94 | [name-client-suffix](references/name-client-suffix.md) | Client suffix for API clients | 95 | [name-manager-suffix](references/name-manager-suffix.md) | Manager suffix for lifecycle mgmt | 96 | [name-bool-is-prefix](references/name-bool-is-prefix.md) | is_/has_/should_ for booleans | 97 | [name-plural-collections](references/name-plural-collections.md) | Plural names for collections | 98 99 ### Style 100 101 | Rule | Description | 102 |------|-------------| 103 | [style-import-granularity](references/style-import-granularity.md) | One item per use statement | 104 | [style-deny-stdout](references/style-deny-stdout.md) | Deny stdout/stderr in libraries | 105 | [style-inline-format-args](references/style-inline-format-args.md) | Inline format arguments | 106 | [style-module-docs](references/style-module-docs.md) | Module-level documentation | 107 | [style-expect-reason](references/style-expect-reason.md) | #[expect] with reason for lints | 108 | [style-cfg-test-module](references/style-cfg-test-module.md) | Unit tests in mod tests | 109 110 ### Cross-Crate 111 112 | Rule | Description | 113 |------|-------------| 114 | [cross-workspace-lints](references/cross-workspace-lints.md) | Workspace-level lint config | 115 | [cross-workspace-deps](references/cross-workspace-deps.md) | Centralized dependency versions | 116 117 ## Example: Proper Error Handling 118 119 ```rust 120 use thiserror::Error; 121 use anyhow::Context; 122 123 // Domain error with thiserror 124 #[derive(Debug, Error)] 125 pub enum ConfigError { 126 #[error("failed to read config file: {path}")] 127 ReadFailed { 128 path: PathBuf, 129 #[source] 130 source: std::io::Error, 131 }, 132 133 #[error(transparent)] 134 Parse(#[from] toml::de::Error), 135 } 136 137 // Library function returns domain error 138 pub fn load_config(path: &Path) -> Result<Config, ConfigError> { 139 let content = fs::read_to_string(path) 140 .map_err(|source| ConfigError::ReadFailed { 141 path: path.to_owned(), 142 source, 143 })?; 144 toml::from_str(&content).map_err(Into::into) 145 } 146 147 // Application code uses anyhow with context 148 fn main() -> anyhow::Result<()> { 149 let config = load_config(Path::new("config.toml")) 150 .context("failed to load configuration")?; 151 run(config).await 152 } 153 ``` 154 155 ## Source 156 157 Patterns extracted from [OpenAI Codex](https://github.com/openai/codex) (`codex-rs/` subdirectory) - a production Rust codebase with 50 crates and 787 Rust files.
ComeOnOliver/skillshub/tree/main/skills/pproenca/dot-skills/rust-cli-agent-style commit 407da669f9
Frequently asked questions How do I install the Rust CLI Agent Style skill? Run npx skillmds@latest add comeonoliver/rust-cli-agent-style in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
What does the Rust CLI Agent Style skill do? OpenAI Codex Rust CLI Agent Best Practices It is listed under AI & ML on SkillMD.
Is Rust CLI Agent Style safe to use? This skill has not completed SkillMD's automated safety review yet. Independent scanners report: SkillSpector: PASS, Skill Scanner: PASS. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
Which AI agents work with Rust CLI Agent Style? This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Is Rust CLI Agent Style free to use? Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
Who published Rust CLI Agent Style? ComeOnOliver (@comeonoliver) published this skill. Their other Agent Skills are listed on their SkillMD profile.