资讯动态

AOS 社区版 Capsule 开发实战:从 `aos capsule new` 脚手架到内容寻址安装的完整路径

发布时间:2026/9/25 5:13:51 来源:尧图企业网站定制
【免费下载链接】aos-ceAOS Community Edition: the open agent operating system.项目地址https://gitcode.com/gh_mirrors/ao/aos-ce点击查看免费下载Capsule 是 Unicity AOS 中承载全部业务逻辑的 Rust WebAssembly 组件,运行于 Astrid Runtime 沙箱之内:Runtime 负责路由 IPC、执行能力(capability)授权、中介宿主访问并审计执行过程。本文基于 AOS 社区版仓库内置的 Capsule Development Skill,结合仓库中真实的 Capsule 清单与脚手架源码,完整覆盖从零创建、配置编译目标、编写Capsule.toml、实现工具与生命周期钩子、打通类型化 IPC,到构建、打包、安装、隔离测试和常见故障排查的全流程。读完后,你将能够独立交付一个可安装、可被 Agent 发现的 AOS 工具 Capsule,并理解其 IPC 访问控制列表(ACL)背后的安全边界设计。Capsule 的本质:安全边界上的 Wasm 组件Capsule 有三个不可动摇的定位,决定了后续所有开发决策:业务逻辑的家。Runtime 只做路由、授权、中介与审计,不承载业务;所有工具实现、状态迁移、事件处理都写进 Capsule。清单是安全边界的一部分。Capsule.toml中的[publish]和[subscribe]表就是 IPC 的访问控制列表——未声明的主题一律拒绝(fail closed)。这不是路由建议,而是内核强制执行的 ACL。目标是wasm32-unknown-unknown,不是 WASI。Capsule 与宿主的一切交互都必须通过清单所授权的 SDK/WIT 导入完成,不存在绕过沙箱的旁路。仓库中 capsule-system 的清单 用注释印证了这一点:[publish]的键是唯一的 IPC-publish 声明,[subscribe] 的handler把主题绑定到#[astrid::interceptor]导出,而键本身同时充当 subscribe ACL。从官方脚手架开始,而不是手写模板支持的起点是官方命令:aos capsule new my-capsule cd my-capsule生成结果是一个可编译的工具 Capsule 骨架:my-capsule/ ├── .cargo/config.toml ├── rust-toolchain.toml ├── Cargo.toml ├── Capsule.toml └── src/lib.rs这套模板并非凭空存在——仓库中的 capsule-forge 脚手架模块 以path - content映射形式实现了同一套文件,其注释明确写明了每个文件的取舍,例如cargo_config()上方写道:getrandom 标志是第一号静默陷阱——没有它,uuid/HashMap 在 wasm32-unknown-unknown 上会链接失败。WASM 产物文件名规则也可在源码中确认:连字符替换为下划线再加.wasm(如my_capsule.wasm),内核按该文件名解析组件。重要弃用声明:不要从旧式[[interceptor]]清单或ipc_publish/ipc_subscribe能力数组开始——这些格式已经废弃,当前格式就是下文描述的[publish]/[subscribe]表。编译目标与工具链.cargo/config.toml:选定目标并激活自定义随机源后端[build] target wasm32-unknown-unknown [target.wasm32-unknown-unknown] rustflags [--cfggetrandom_backend\custom\]两条配置各有深意:target指向无 WASI 的裸 Wasm 目标;getrandom_backend custom让 SDK 接管随机数源。这条 rustflag 必须写在最终 Capsule crate 自己的.cargo/config.toml里,依赖 crate 无法替最终组件设置该标志。缺失的直接后果是:UUID 生成器、随机化 HashMap 这类依赖在链接期失败,而且失败点离根因很远,排查成本高。capsule.md 指南 将这一点称为第一号静默陷阱。rust-toolchain.toml:钉死工具链[toolchain] channel 1.94.0 targets [wasm32-unknown-unknown] components [rustfmt, clippy]仓库脚手架(scaffold.rs)生成的工具链文件与上述内容逐字一致,说明这是官方支持的基线组合。Cargo.toml:cdylib 0.7 SDK 面[package] name my-capsule version 0.1.0 edition 2024 publish false [lib] crate-type [cdylib] [dependencies] astrid-sdk { version 0.7, features [derive] } serde { version 1.0, features [derive] } serde_json 1.0 [profile.release] opt-level z lto true codegen-units 1 strip true panic abort要点解析:crate-type [cdylib]:Wasm 组件必须编译为动态库形态导出;astrid-sdk带derive特性以使用#[capsule]、#[astrid::tool]等宏;仓库工作区 根 Cargo.toml 将其精确钉在astrid-sdk 0.7.1,因此社区版中的内置 Capsule 全部基于 0.7 面开发;release profile 用opt-level z(体积优先) LTO 单代码生成单元 符号剥离 panic abort换取最小的.wasm产物——仓库工作区级的[profile.release]也是同一组参数,可见这是官方一致性的打包约定。Capsule.toml:把 IPC ACL 写进清单一个暴露hello工具的最小工具 Capsule 清单如下(与官方脚手架生成的模板同构):[package] name my-capsule version 0.1.0 description A small example capsule authors [Your Name youexample.com] astrid-version 0.7.0 [[component]] id my-capsule file my_capsule.wasm type executable [capabilities] fs_read [home://data/my-capsule/] fs_write [home://data/my-capsule/] [publish] tool.v1.execute.*.result { wit unicity-astrid/wit/types/tool-call-result } tool.v1.response.describe.* { wit unicity-astrid/wit/tool/describe-response } [subscribe] tool.v1.execute.hello { wit unicity-astrid/wit/types/tool-call, handler tool_execute_hello } tool.v1.request.describe { wit unicity-astrid/wit/tool/describe-request, handler tool_describe }各表职责[package]:包元数据。astrid-version声明运行时兼容下限;名称用 lowercase ASCII 字母数字与连字符,版本是三段式语义化版本。manifest.md 指南 强调:不要在没有实测宿主 ABI 的情况下放宽astrid-version。[[component]]:file相对Capsule.toml定位组件字节;Rust 包名的连字符在 WASM 文件名中变为下划线。大多数 Capsule 只有一个executable组件;库组件用于组合而非独立运行环。不要在清单里手写内容摘要——安装记录会自行验证内容寻址的组件字节。[capabilities]:宿主能力声明,所有字段 fail closed(列表缺省为空,布尔缺省为 false)。仓库 capsule-shell 的清单 给出了一个最小示例:host_process [bash, sh, zsh]——只放行需要的可执行名。[publish]/[subscribe]:键既是路由声明,也是被强制执行的主题 ACL;值是 WIT 类型串或含wit的表,subscribe 表还可携带handler(与组件导出绑定)和priority。工具 Capsule 的四条硬规则两个 publish 项缺一不可:一个返回工具结果(tool.v1.execute.*.result),另一个应答 describe 扇出(tool.v1.response.describe.*)——后者让工具对 Agent 可见;每个工具都需要一条具体的 execute 订阅,例如tool.v1.execute.hello绑定到生成导出tool_execute_hello;subscribe 通配符最多一个尾随*;publish 权限应尽可能收窄;清单数据是不可信输入。不要把操作员权限、principal 身份或密钥作用域写进 Capsule 可控字段——调用者身份由内核盖章,operator-only 策略由内核决定。对照真实清单能更直观地看到这套模式: capsule-system 的 [subscribe] 段 声明了list_capsules、inspect_capsule、list_interfaces、read_interface、system_status五个具体 execute 订阅加一条 describe 订阅,与 capsule-shell 的清单 结构完全一致,只是工具名与宿主能力不同(shell 用host_process放行 shell 解释器)。关于 Skills 的边界澄清Skill 是 Agent 用户态的指令,不是Capsule.toml协议:触发型 Skill 应通过宿主插件或 Agent 级 Skills 服务分发,Capsule 自有的参考资料在有用时通过类型化 IPC 工具暴露。不要为修改宿主指令目录而在清单里添加 Agent Skill 段落或申请文件系统写权限。稳定的运行时标识符清单中出现的unicity-astrid/wit/...字符串与astrid:*WIT 命名空间是稳定的运行时标识符。尽管产品 CLI 叫aos,这些字符串也必须原样保留,不要顺手改名。实现一个工具#![deny(unsafe_code)] #![deny(clippy::all)] use astrid_sdk::prelude::*; use astrid_sdk::schemars; use serde::Deserialize; #[derive(Default)] pub struct MyCapsule; #[derive(Debug, Default, Deserialize, schemars::JsonSchema)] pub struct HelloArgs { /// Person to greet. pub name: String, } #[capsule] impl MyCapsule { /// Greet a person by name. #[astrid::tool(hello)] pub fn hello(self, args: HelloArgs) - ResultString, SysError { Ok(format!(Hello, {}!, args.name)) } }这段代码与 capsule-forge 脚手架 生成的src/lib.rs几乎逐字相同。宏展开的语义(由 capsule.md 指南 与 Skill 文档共同确认):工具宏从JsonSchema派生输入 schema——字段级 doc 注释会成为模型可见的参数说明;方法 doc 注释成为工具描述;导出名为tool_execute_hello的组件导出;生成配套的tool_describe处理器(你只声明,不手写);清单再把这两个生成导出名绑定到对应 IPC 主题。类型约束:容器结构实现Default;参数类型实现Deserialize JsonSchema;返回值实现Serialize;错误实现Display,宿主边界优先用SysError。工具形态有四种:#[astrid::tool]、#[astrid::tool(name)]、#[astrid::tool(mutable)]、#[astrid::tool(name, mutable)]。显式或推断出的工具foo一律绑定到tool_execute_foo;mutable只是给审批/ UI 层的效果标注,路由仍由清单决定。拦截器仅用于原始处理器:只有需要原始事件中间件时才用#[astrid::interceptor(handler_name)],并从[subscribe]条目绑定该处理器;废弃的清单级[[interceptor]]表禁止使用。仓库内置的 capsule-hook-bridge 展示了真实用法:十多个#[astrid::interceptor(on_tool_call_started)]之类的钩子把宿主事件桥接进来; capsule-agents 则用#[astrid::interceptor(on_before_prompt_build)]参与提示词构建。状态与生命周期持久化状态当可变状态需要运行时持久化时使用#[capsule(state)]。状态作用域是Capsule principal双维隔离;生成路径会在处理器执行前从 principal 作用域的 KV 载入__state,成功执行后持久化——失败的处理器不会保存半截状态。无状态selfCapsule 走内存单例,不触 KV。一条硬性纪律:绝不把 per-principal 配置缓存在进程级 static 里,否则不同 principal 的配置会串号(见后文故障表)。生命周期钩子钩子触发时机关键约束#[astrid::install]首次安装可创建初始 VFS 数据或引导配置;返回Result(), SysError#[astrid::upgrade]已安装版本被替换额外接收上一版本号;迁移必须幂等,先验证后写,避免半截改写持久化状态#[astrid::run]常驻运行环初始化完成后必须调用runtime::signal_ready()每个生命周期钩子是单例,install 与 upgrade 应保持窄职责且幂等。仓库内 capsule-cli 与 capsule-context-engine 都带有真实的#[astrid::run]实现,可作为常驻环参考。运行环的正确姿势(capsule.md 指南 的 Run loops 节):有界初始化后signal_ready();通过 receive/sleep/宿主调用让出 CPU 而非空转;把 receive 超时当作Ok空消息批;对长寿命状态做显式检查点(run 环不会每轮自动保存);关停与重启幂等。IPC:类型化 JSON、批语义与 principal 校验契约是 JSON 时使用类型化辅助函数:ipc::publish_json(my.v1.event.ready, payload)?; let subscription ipc::subscribe(my.v1.request.*)?; let batch subscription.recv(500)?; for message in batch.messages { // Parse and handle each envelope independently. }三条语义必须记住,它们直接决定正确性:recv(timeout)超时返回Ok 空消息批,不返回超时错误——轮询代码要判空,不要匹配错误字符串;一个批可含多个发布者。敏感操作必须逐条读取内核盖章的 principal 并要求已验证归因;永不信任被复制进 payload 的 principal 字段(调用者身份由内核盖章,写在消息体里的只是声称);扇出响应必须发布到已声明的响应主题上。从某个拦截器return一个值,并不会替你发布给其他订阅者——describe 路径若只 return 而不 publish,整个扇出就是空的。工具请求的完整链路(可对照 ipc.md 指南):模型选择foo→ 路由器校验并发布tool.v1.execute.foo→ 提供端 Capsule 的tool_execute_foo执行 → 提供端发布tool.v1.execute.foo.result→ 路由器按call_id匹配出统一结果。工具发现则是另一条扇出:提示词构建发布tool.v1.request.describe,各 Capsule 的生成版tool_describe发布 schema 响应,prompt builder 收集并去重工具名。主题匹配有四个不同的上下文,通配符语义各不相同:事件投递(尾随*订阅子树)、ACL 授权(模式匹配,publish 结果模式用.result前的通配段)、静态处理器分发(段数必须匹配,通配段只匹配一段,所以每个工具处理器要有具体的 execute 行)、动态ipc::subscribe(最多一个尾随通配,且仍需清单 ACL 覆盖)。未声明或格式非法的主题 fail closed;工具名被刻意限制,防止名字注入额外主题段。运行时中介的宿主访问宿主访问默认拒绝,除非清单与运行时共同授权。Skill 文档列出的通道:fs:只接受home://、cwd://等 VFS 路径,不暴露原始宿主路径。home://是调用 principal 的家目录、随调用作用域变化;父目录穿越即使声明了宽前缀也被拒绝;fs_read不蕴含写,fs_write不蕴含读;kv:自动按 Capsule principal 隔离,普通 KV 当前无需清单授权(清单中的kv列表是保留面);http:仅当 Capsule 具备所需 HTTP 权限时执行出站请求;net按主机名把守高层 HTTP 客户端,与原始套接字的net_connect/net_bind互不蕴含;env::var:在调用时解析普通配置或属主 Capsule 的密钥。密钥不是普通 env JSON,绝不能跨 principal 缓存;log:输出结构化 Capsule 日志,落在~/.aos/runtime/home/principal/.local/log/capsule/,按 principal 隔离。capabilities 指南 给出了完整字段目录:uplink、net、kv、fs_read、fs_write、host_process、allow_persistent、net_bind、net_connect、identity、allow_prompt_injection。不要发明shell、internet、filesystem或通用admin能力——不存在这些字段。原则:只申请 Capsule 需要的最小路径、主机、主题与进程;不要为了迁就一个失败的测试而扩大权限。能力声明是必要条件但不充分——principal 授权、操作员策略与运行时同意可以进一步收窄。构建、打包与安装rustup target add wasm32-unknown-unknown aos capsule build aos capsule install ./dist/my-capsule.capsule aos capsule list aos status关键约束:aos capsule build把组件与清单打包成可安装、内容寻址的dist/*.capsule制品;裸cargo build --release只是有用的编译检查,其原始.wasm输出不可安装,不要把手工产出的 WASM 文件拷进运行时 home;没有热重载。每次迭代都要重新构建并重装.capsule制品;安装会替换上一版本但保留配置,除非显式清除:aos capsule remove my-capsule aos capsule remove my-capsule --purge安装前的验证:主机单测 边界行为清单测试策略分两层。第一层,把解析、校验与业务规则放进普通 Rust 函数,让它们在宿主目标的单元测试里直接跑,不必每次都为纯逻辑付一次 Wasm 构建。第二层,单独验证 guest 面:cargo fmt --all -- --check cargo check aos capsule build然后装入一个隔离的 AOS home,对真实边界做七步验证:确认 Capsule 出现在aos capsule list;确认aos status保持健康;用有效与无效输入逐一演练每个已声明工具;证明未声明的 IPC 主题与宿主操作被拒绝(负路径测试是安全边界的一部分);用第二个 principal 测试,确认配置与状态不跨调用者串流;撤销访问权限,证明下一次调用即观察到撤销生效;重装并升级,证明状态迁移正确且配置被保留。第 4、5、6 步正是前文清单 ACL、principal 作用域与 fail closed 语义的端到端验收——它们验证的不是功能,而是边界。常见故障排查Skill 文档自带的症状对照表,结合仓库佐证:症状检查工具不出现是否齐备 execute 与 describe 订阅加 result/describe 两个 publish 主题(对照 capsule-system 清单)链接器在随机数附近失败在.cargo/config.toml恢复自定义getrandom_backendrustflagIPC publish 或 subscribe 被拒绝把精确主题加进[publish]或[subscribe];不要加无关通配构建只产出.wasm运行aos capsule build,从dist/安装制品请求超时无错误把空recv批当作超时处理一个用户的配置出现在另一个用户身上删掉 static/global 的 env 缓存,改为每次调用时解析Capsule panic 或退出检查 per-principal Capsule 日志;从 guest 错误路径移除unwrap/expect升级损坏状态让迁移幂等,验证成功之后才写新状态小结与继续深入的入口Capsule 开发的复杂度其实集中在两处:一是最小权限的清单([capabilities][publish]/[subscribe]ACL),二是围绕 principal 作用域的正确性(不缓存、逐条验源、迁移幂等)。仓库里值得继续读的材料:capsule-forge 的 guides 目录:Capsule 解剖、宏面、状态模式与 SDK 模块全表;manifest.md:Capsule.toml完整作者面,含[env]安装期配置、[[context_file]]、[[command]]、[[mcp_server]]等进阶表;ipc.md:priority 如何把并发扇出切换为有序中间件链、Deny与Err的语义差异;capabilities.md:完整能力字段目录与最小授权工作流;capsule-shell 与 capsule-system 两份内置清单:最简可读的真实工程样例。起步时的建议与 Skill 文档一致:优先使用aos capsule new与 capsule-forge 工具链生成代码级起点,而不是复制旧发布版里的过期示例。赞分享【免费下载链接】aos-ceAOS Community Edition: the open agent operating system.项目地址https://gitcode.com/gh_mirrors/ao/aos-ce点击查看免费下载相关推荐Unicity AOSaos-ceCapsule 构建全生命周期实战从脚手架、编译、安装到诊断与升级Unicity AOSaos ceCapsule 构建全生命周期实战从脚手架、编译、安装到诊断与升级 本文基于 aos ce 仓库中 capsule foAOS CE 工作区指南Capsule 源码选址、VFS 可移植路径与仓库所有权边界AOS CE 工作区指南Capsule 源码选址、VFS 可移植路径与仓库所有权边界 本文围绕 AOS Community Edition下称 AOS CEaos-ce capsule-forge从零构建受治理 Capsule 的 Agent 作者工作流全解aos ce capsule forge从零构建受治理 Capsule 的 Agent 作者工作流全解 本文以 aos ce 仓库中的 capsule for上一篇Python-JOSE未来展望即将实现的JWE功能与路线图下一篇Rust OS开发者引导加载器教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑