AgentSkillsCN

rust-cli-agent-style

从 OpenAI Codex Rust 代码库中提炼出的编程模式——一个具备严格错误处理、异步模式与工作区组织的生产级 CLI/代理系统。

SKILL.md
--- frontmatter
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)

RuleDescription
err-no-unwrapNever use unwrap() in non-test code
err-no-expectAvoid expect() in library code
err-thiserror-domainUse thiserror for domain errors
err-context-chainAdd context to errors with .context()

Error Handling

RuleDescription
err-anyhow-applicationUse anyhow::Result for entry points
err-from-deriveUse #[from] for error conversion
err-transparentUse #[error(transparent)] for wrapped errors
err-structured-variantsInclude relevant data in error variants
err-io-resultUse std::io::Result for I/O functions
err-map-err-conversionUse map_err for error conversion
err-doc-errorsDocument error conditions

Organization

RuleDescription
org-workspace-flatFlat workspace with utils subdirectory
org-crate-namingkebab-case directories, project prefix
org-module-visibilityUse pub(crate) for internal APIs
org-test-common-crateShared test utilities crate
org-integration-tests-suiteTests in suite directory
org-feature-modulesFeature-based module organization
org-handlers-subdirHandlers in dedicated subdirectory
org-errors-fileErrors in dedicated file

Component Patterns

RuleDescription
mod-derive-orderConsistent derive macro ordering
mod-async-trait-macroUse #[async_trait] for async traits
mod-trait-boundsSend + Sync + 'static for concurrent traits
mod-extension-trait-suffixExt suffix for extension traits
mod-builder-patternBuilder pattern for complex config
mod-type-alias-complexType aliases for complex generics
mod-impl-block-orderConsistent impl block ordering
mod-generic-constraintsWhere clauses for complex bounds
mod-newtype-patternNewtypes for type safety
mod-struct-visibilityPrivate fields with public constructor
mod-serde-renameSerde rename for wire format
mod-jsonschema-deriveJsonSchema for API types

Naming Conventions

RuleDescription
name-async-no-suffixNo _async suffix for async functions
name-try-prefix-fallibletry_ prefix for fallible constructors
name-with-prefix-builderwith_ prefix for builder methods
name-handler-suffixHandler suffix for handlers
name-error-suffixError suffix for error types
name-result-type-aliasCrate-specific Result alias
name-const-env-var_ENV_VAR suffix for env constants
name-request-responseRequest/Response type pairing
name-options-suffixOptions suffix for config bundles
name-info-suffixInfo suffix for read-only data
name-provider-suffixProvider suffix for services
name-client-suffixClient suffix for API clients
name-manager-suffixManager suffix for lifecycle mgmt
name-bool-is-prefixis_/has_/should_ for booleans
name-plural-collectionsPlural names for collections

Style

RuleDescription
style-import-granularityOne item per use statement
style-deny-stdoutDeny stdout/stderr in libraries
style-inline-format-argsInline format arguments
style-module-docsModule-level documentation
style-expect-reason#[expect] with reason for lints
style-cfg-test-moduleUnit tests in mod tests

Cross-Crate

RuleDescription
cross-workspace-lintsWorkspace-level lint config
cross-workspace-depsCentralized dependency versions

Example: Proper Error Handling

rust
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.