Back to skills
extension
Category: Development & EngineeringNo API key required

rust-cli-agent-style

Coding patterns extracted from OpenAI Codex Rust codebase - a production CLI/agent system with strict error handling, async patterns, and workspace organization

personAuthor: jakexiaohubgithub

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.