Imported from whatevertogo/astrcodey (
AGENTS.md). Install upstream withnpx skills add whatevertogo/astrcodey. Copyright stays with the author.
astrcodey 编码规范
适用对象:所有在本仓库工作的 AI agent(Claude Code、Codex、Cursor 等)与人类贡献者。 本文件是唯一事实来源,
CLAUDE.md通过 import 引用它。
角色
你是 Rust 专家。
总原则
不要贪图简洁而牺牲清晰度、可维护性和可扩展性。
内置插件
内置插件只能依赖插件系统,不能依赖项目的其他内容。
DTO 规则
只有数据跨边界时才创建 DTO(HTTP 请求/响应、SSE 载荷、前端契约、插件/MCP 边界、版本化持久化格式)。不要为内部函数调用创建 DTO;新增结构前先检查现有契约是否已满足。
映射规则
- 在边界做映射,不要在核心逻辑里映射。
- 需要上下文的转换用显式映射函数;明显、无损的转换才用
From。 - 不要为「未来可能用」添加
Option<T>字段(可留 TODO 注释)。 - 不要把内部 enum 直接暴露成线缆契约。
serde(rename_all = "camelCase")只用于 protocol/wire 类型和 LLM tool call 参数类型。
Rust 实现
- 函数直白,优先清晰的领域命名,不滥用
utils/helper/manager。 - 避免过宽的
pub,避免不必要的clone/unwrap/expect/panic。 - 不要在
.await时持有锁;不要启动无生命周期、无错误处理、无 tracing 的后台任务。 - 优先直接编写本地代码;仅当逻辑被复用,或提取能实质性澄清一个重要流程时,才抽辅助函数。
最小改动
- 只解决所提出的问题;不添加推测性功能、可配置性或相邻改进。
- 优先编辑现有代码,而不是重写文件或重塑无关逻辑。
- 只修改必要部分,只删除自己改动引入的产物。
- 修复 bug 或处理 review 意见时,保持既有控制流和逻辑结构,尤其是初始化、并发、元数据等敏感路径。
- 不要为方便单元测试而重构现有代码。
- 可以提及无关问题,但不要把它作为当前任务的一部分去解决。
注释
- 注释用于阐明不明显的意图和不变式,不要用来弥补代码的不清晰。
- 不要写解释下一行功能、重述签名、描述刚做的改动的注释——这些属于 PR 描述。
- 必需的不变式注释(如锁的获取顺序、
SAFETY解包理由、#[allow(dead_code)]的原因)只陈述不变式,不叙述。
先重用,再写新代码
写新代码前,先查找现有实现,在现有基础上扩展而不是重复编写:
- 共享原语:不要创建无明确领域归属的
support/utils桶。产品级默认目录在astrcode-core::config::defaults(进程级路径原语实体在astrcode-paths,由 defaults re-export);扩展可用的路径、frontmatter、shell 与 discovery 能力在astrcode-core(SDK 保留 re-export);S5R 子进程运行时(peer 状态机与 I/O driver)在astrcode-s5r-runtime,host 与 worker 共同依赖,不属于 SDK 作者面;工作区沙箱、展示格式化、哈希和运行时策略留在所属 crate,日志在astrcode-log。写新函数前先按语义在crates/<owner>/src与调用方中搜索签名。重新实现工作区已有的原语,或手写std/tokio已提供的功能,属于 review 意见而非风格偏好。 - 语义匹配而非名称匹配:采用一个函数前,确认它的归一化、错误类型、超时/重试行为是否适用于调用点。语义不同时,新建一个名称更明确的函数,并在注释里指出被放弃的近似函数。
- 常量与固定标记:协议标签、错误标识、事件名称、命令标签等,先找语义相同的现有常量/枚举复用。确属新值时,在相关逻辑附近定义本地常量,不要把字面量散落各处;修改既有行为时,命名与格式要与既有常量一致。
- 测试脚手架:复用
crates/*/tests/fixtures、crates/astrcode-protocol/fixtures等现有 fixtures,而非新写 setup。写测试前先rg -l '<fn-under-test>' <crate>/src <crate>/tests。新测试必须能暴露现有测试未覆盖的失败模式。
仅写必要代码
新增的文件、类型、分支、注释都是需要证明其合理性的成本,而非进步:
- 在信任边界验证:外部输入、从磁盘读入的字节、RPC 载荷、配置——在边界校验后即信任类型,不要重复检查类型系统或已校验的上游层已经保证的内容;保证不明显时用
file:line注明校验位置。 - 跨边界值要重复校验:跨越持久化、RPC、版本边界的值永远无法被对端代码保证(对端可能更旧或有缺陷,磁盘字节可能损坏),因此在执行破坏性操作(删除、覆盖)前要立即重新校验。删除既有保护属于行为变更,需对抗性 review,不是清理。
- 每个新分支都要有可命名的触发器:一个具体的输入、状态或故障条件。无法命名触发条件就不要写该分支;确实不可触发就把它编码进类型,否则返回有类型的内部错误。
debug_assert!仅可用于从未跨磁盘/RPC/配置边界的纯内部运算,绝不能作为解码后或外部数据的唯一保护。 - 不要用默认值掩盖数据损坏:在某个值必须存在的地方(如必须存在的元数据)不要用
unwrap_or_default(),那会把损坏转成错误结果;应返回有类型的错误,显式表达失败而非隐式成功。 - 错误上下文只加一次,加在可操作的层级:每一层重新包装等价上下文是噪音;把易错链展开成嵌套
match(本可用?或组合子)同样不可取。
测试
- 只写必要的测试。集成测试放
tests/,单元测试写在模块下方。 - 只有测试能放
.unwrap()。
验证
优先最小相关检查:cargo fmt --check → cargo test -p <crate> <test_name> → cargo clippy -p <crate> --all-targets -- -D warnings。然后再跑 cargo clippy --all-targets --all-features -- -D warnings + cargo test --all-features。
大范围改动:cargo clippy --all-targets --all-features -- -D warnings + cargo test --all-features。
修改代码后,在合适的收尾点必须跑对应验证和验收:
- 普通代码改动:至少跑
cargo fmt --check、相关 crate/test 的最小测试、相关 crate 的 clippy。 - 大范围/跨 crate/并发/协议/持久化/发布相关改动:跑完整
cargo clippy --all-targets --all-features -- -D warnings+cargo test --all-features。 - push、创建 PR、合并 PR、发 release 前:必须先确认本地或 CI 的对应验证已通过;若只是等 CI,也要明确说明哪些检查仍在跑。
- 若因环境缺失、耗时不可接受、用户明确要求跳过等原因无法执行验证,必须在回复中写清楚未跑哪些命令、原因和剩余风险。
- 不要把「能编译/能合并」当作验收;需根据改动性质补必要的行为测试或手动验收说明。
回复要求
每次完成修改后,回复末尾必须附带:
- 下一步建议:基于当前改动,接下来最值得做的事(按优先级排列);若无则说无。两种情况都需说明原因。
- 剩余风险:当前改动中已知或潜在的隐患、未覆盖的边界情况;若无则说无。