Pi Coding Agent 03:扩展体系——Skill、Extension 与 Package 的职责边界

Pi Coding Agent 03:扩展体系——Skill、Extension 与 Package 的职责边界
Asaakii在许多开源 Agent 项目的迭代过程中,扩展系统经常会陷入一种令人啼笑皆非的架构混乱:
- 明明一份几十行的 Markdown 检查清单就能规范好的代码审查步骤,开发者偏偏要写几百行高权限的 TypeScript 代码把它封装成一个黑盒工具;
- 明明必须 100% 强制拦截的“严禁删除生产数据库”安全红线,却仅仅写在 System Prompt 里祈祷模型道德自律;
- 当团队需要共享一套能力时,大家只能在聊天工具里机械地互相复制粘贴目录文件。
Pi 深刻洞察了这一痛点,在扩展架构中建立了边界分明的“三层分离机制”:
- Skill(技能):改变模型知道什么(按需加载的领域操作知识与流程);
- Extension(扩展):改变运行时能做什么(同进程内执行原生 TypeScript 代码,拦截命令、注入工具);
- Package(包):改变资源如何交付(将 Skill、Extension、Prompt 与 Theme 进行版本化封装与分发)。
一、先用决策表理清需求边界
在着手编写扩展前,切勿盲目选择“能力最强”的方式,而应根据需求的真实本质进行精确匹配:
| 实际业务诉求 | 首选扩展机制 | 架构选择背后的核心考量 |
|---|---|---|
| 团队规范、代码发布检查清单、排障手册 | Skill | 纯文本操作指引,按需进入模型上下文,不增加多余的常驻工具与权限面 |
| 由用户显式触发的一段可复用 Prompt | Prompt Template | 相当于快捷宏展开,不需要模型在全局自动匹配 |
| 新增自定义工具、扩展命令行斜杠命令、注入状态栏 | Extension | 必须由程序逻辑在当前运行进程内注册功能或监听生命周期 |
无条件强制拦截特定高危命令(如 rm -rf) |
Extension + 外部隔离 | 拦截必须由程序代码执行,但必须配合底层沙箱防御绕过 |
| 将打磨好的规范、工具或界面主题跨团队分发 | Package | 提供统一的 Git / npm 安装依赖管理与版本更新通道 |
二、Skill:渐进披露(Progressive Disclosure)的精妙设计
Skill 是一个高度自包含的目录,它的核心入口是 SKILL.md,并可以携带专属脚本与参考文档:
1 | release-review/ |
SKILL.md 的核心灵魂是它的 YAML Frontmatter:
1 | --- |
为什么说渐进披露(Progressive Disclosure)拯救了上下文窗口?
如果把团队所有的规范文档(可能长达上万行)一股脑全量塞进系统提示词,不仅费用昂贵,还会严重稀释模型的注意力。
Pi 采用了精密的四步渐进式披露机制:
flowchart TD Boot["1. 系统启动扫描<br/>仅将 Skill 的 name 与 description 载入系统上下文<br/>(仅占几十个 Token)"] --> Match["2. 意图模糊匹配<br/>用户下发任务时,模型根据描述判断是否需要激活"] Match --> Read["3. 按需动态加载<br/>模型通过内置 read 工具仅读取对应的 SKILL.md 正文"] Read --> Deep["4. 深度展开<br/>仅在遇到特殊情况时,继续读取子目录中的 scripts 与 references"]
[!WARNING]
警惕:Skill 绝不是安全边界!
Skill 无论写得多么言之凿凿(例如“发布前必须经过双人确认”),它在本质上仅仅是模型的上下文阅读材料。模型依然可能因为幻觉或 Prompt 注入而跳过这些步骤。涉及物理权限的强规则,必须交由 Extension 或外部沙箱强制执行。
三、Extension:掌控运行时的同进程原生代码
与纯文本的 Skill 截然不同,Extension 是运行在 Pi 主 Node.js 进程内部的原生 TypeScript 模块。
当前官方推荐的 Extension 写法是一个标准的工厂函数:
1 | import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; |
[!IMPORTANT]
关键设计:无头模式下的 Fail-Closed(失败默认阻断)
在上面的代码中,请注意if (!ctx.hasUI) return { block: true }。当 Pi 在自动化脚本、CI/CD 或无头 JSON 模式下运行时,根本没有交互界面。此时必须严格拒绝高危操作!如果因为没有弹窗而默认放行,整个安全防御就会在最脆弱的自动化环节被彻底击穿!
四、加载顺序与 Project Trust(项目信任机制)
在进入一个未知的 Git 代码仓库时,Pi 是如何加载这些扩展资源的?
很多人误以为“只要不信任项目,Pi 就什么文件都不读”。实际的加载流程要微妙得多:
flowchart TD
Enter["进入工作区目录"] --> ReadContext["1. 优先加载项目上下文文件<br/>(AGENTS.md / CLAUDE.md / README.md)"]
ReadContext --> CheckTrust{"2. 检查 Project Trust 状态<br/>(~/.pi/agent/trust.json)"}
CheckTrust -->|已被人类信任| LoadHigh["3. 激活高影响资源<br/>• .pi/settings.json<br/>• .pi/extensions (执行代码)<br/>• .pi/skills (加载项目技能)"]
CheckTrust -->|未被信任| SkipHigh["4. 坚决跳过所有项目级代码扩展<br/>仅保留系统全局配置运行"]
这个时序揭示了一个关键安全事实:AGENTS.md 等纯上下文文件默认会在信任决策前被读取(以便让模型理解当前工程背景)。这意味着恶意仓库完全可以在 AGENTS.md 里埋伏间接提示词注入。因此,“项目未信任”防住了恶意代码在本地立刻运行,但绝没有完全防住模型被恶意文本诱导。
五、Package:将能力打包分发
Package 是承载 Skill、Extension、Prompt 与 Theme 的标准分发格式。
在 package.json 中,通过显式声明 pi 清单即可完成自描述:
1 | { |
安装命令非常灵活:
1 | # 全局安装(对本机所有项目生效) |
在引入任何第三方 Package 时,请时刻谨记:一个包的安全风险,取决于其中包含的最高风险组件。 只要包内包含一个 Extension,它在被激活时就拥有了与你本地开发环境完全等同的全部系统权限。











