Agent Skills: OpenAI Codex Rust CLI Agent Best Practices

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

UncategorizedID: pproenca/dot-skills/rust-cli-agent-style

Install this agent skill to your local

pnpm dlx add-skill https://github.com/pproenca/dot-skills/tree/HEAD/skills/.experimental/rust-cli-agent-style

Skill Files

Browse the full folder contents for rust-cli-agent-style.

Download Skill

Loading file tree…

skills/.experimental/rust-cli-agent-style/SKILL.md

Skill Metadata

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

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.