rust-cli-agent-style
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenAI Codex Rust CLI Agent Best Practices
OpenAI Codex Rust CLI Agent 最佳实践
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.
本技能将教你以OpenAI Codex代码库的风格编写Rust代码——这是一个包含50个crate和787个Rust文件的生产级CLI/Agent系统。
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
- 采用2024 Edition及严格的Clippy配置
- 非测试代码中禁止使用unwrap/expect(在工作区层面强制执行)
- 带有正确Send + Sync约束的Tokio异步运行时
- 库错误使用thiserror,应用代码使用anyhow
- 集中管理依赖的扁平化工作区结构
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
在以下场景中应用本技能:
- 使用Rust构建CLI工具或Agent系统
- 编写基于Tokio的异步Rust代码
- 设计Rust工作区的组织结构
- 实现错误处理模式
- 开发生产级Rust代码库
Quick Reference
快速参考
Critical Rules (Must Follow)
核心规则(必须遵守)
| Rule | Description |
|---|---|
| err-no-unwrap | Never use |
| err-no-expect | Avoid |
| err-thiserror-domain | Use thiserror for domain errors |
| err-context-chain | Add context to errors with |
| 规则 | 描述 |
|---|---|
| err-no-unwrap | 非测试代码中禁止使用 |
| err-no-expect | 库代码中避免使用 |
| err-thiserror-domain | 使用thiserror处理领域错误 |
| err-context-chain | 使用 |
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 |
| 规则 | 描述 |
|---|---|
| err-anyhow-application | 入口点使用anyhow::Result |
| err-from-derive | 使用#[from]进行错误转换 |
| err-transparent | 使用#[error(transparent)]包装错误 |
| err-structured-variants | 错误变体中包含相关数据 |
| err-io-result | I/O函数使用std::io::Result |
| err-map-err-conversion | 使用map_err进行错误转换 |
| err-doc-errors | 为错误场景添加文档说明 |
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 |
| 规则 | 描述 |
|---|---|
| org-workspace-flat | 带有utils子目录的扁平化工作区 |
| org-crate-naming | 目录使用kebab-case,带项目前缀 |
| org-module-visibility | 内部API使用pub(crate) |
| org-test-common-crate | 共享测试工具crate |
| org-integration-tests-suite | 测试用例放在suite目录 |
| org-feature-modules | 基于功能的模块组织方式 |
| org-handlers-subdir | 处理器放在专用子目录 |
| org-errors-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 |
| 规则 | 描述 |
|---|---|
| mod-derive-order | 一致的derive宏顺序 |
| mod-async-trait-macro | 异步 trait 使用#[async_trait] |
| mod-trait-bounds | 并发 trait 需满足Send + Sync + 'static |
| mod-extension-trait-suffix | 扩展 trait 使用Ext后缀 |
| mod-builder-pattern | 复杂配置使用建造者模式 |
| mod-type-alias-complex | 复杂泛型使用类型别名 |
| mod-impl-block-order | 一致的impl块顺序 |
| mod-generic-constraints | 复杂约束使用Where子句 |
| mod-newtype-pattern | 使用Newtype模式保证类型安全 |
| mod-struct-visibility | 私有字段搭配公共构造函数 |
| mod-serde-rename | Serde重命名适配有线格式 |
| mod-jsonschema-derive | API类型使用JsonSchema |
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 |
| 规则 | 描述 |
|---|---|
| name-async-no-suffix | 异步函数不添加_async后缀 |
| name-try-prefix-fallible | 可能失败的构造函数使用try_前缀 |
| name-with-prefix-builder | 建造者方法使用with_前缀 |
| name-handler-suffix | 处理器使用Handler后缀 |
| name-error-suffix | 错误类型使用Error后缀 |
| name-result-type-alias | crate专属的Result别名 |
| name-const-env-var | 环境常量使用_ENV_VAR后缀 |
| name-request-response | Request/Response类型配对 |
| name-options-suffix | 配置集合使用Options后缀 |
| name-info-suffix | 只读数据使用Info后缀 |
| name-provider-suffix | 服务使用Provider后缀 |
| name-client-suffix | API客户端使用Client后缀 |
| name-manager-suffix | 生命周期管理使用Manager后缀 |
| name-bool-is-prefix | 布尔值使用is_/has_/should_前缀 |
| name-plural-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 |
| 规则 | 描述 |
|---|---|
| style-import-granularity | 每个use语句仅导入一个项 |
| style-deny-stdout | 库中禁止直接输出到stdout/stderr |
| style-inline-format-args | 内联格式化参数 |
| style-module-docs | 模块级文档说明 |
| style-expect-reason | 为lint禁用添加#[expect]及原因 |
| style-cfg-test-module | 单元测试放在mod tests中 |
Cross-Crate
跨Crate规范
| Rule | Description |
|---|---|
| cross-workspace-lints | Workspace-level lint config |
| cross-workspace-deps | Centralized dependency versions |
| 规则 | 描述 |
|---|---|
| cross-workspace-lints | 工作区级别的lint配置 |
| cross-workspace-deps | 集中管理依赖版本 |
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
}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 ( subdirectory) - a production Rust codebase with 50 crates and 787 Rust files.
codex-rs/这些模式提取自OpenAI Codex的子目录——一个包含50个crate和787个Rust文件的生产级Rust代码库。
codex-rs/