给 Agent Zero 写插件:从零上手笔记
先说结论:官方文档(docs/developer/plugins.md)的态度很明确——插件是首选,扩展(extensions)是高级玩法。先学会插件,别一上来就碰扩展。这篇笔记基于官方文档(plugins.md / extensions.md / create-plugin 指南),把插件开发的完整路径捋一遍。
插件放哪:/a0/usr/plugins/,没有例外
本地插件统一放运行实例内的:
/a0/usr/plugins/
/
最小骨架:
plugin.yaml
README.md
webui/
plugin.yaml 是插件的"身份证"
name: unread_dot
title: Unread Dot
description: Shows a pulsing dot beside chats that received new activity while you were elsewhere.
version: 1.0.0
settings_sections: []
per_project_config: false
per_agent_config: false
三个关键点:
name必须和目录同名,否则插件加载不了。per_project_config/per_agent_config控制配置作用域:false表示全局一份配置,最省事;true则配置跟着 Project 或 Agent Profile 走。- 改完插件必须重启 Agent Zero。否则 Web UI 扩展列表不重建、钩子不生效。这个坑别踩。
纯前端插件的完整形状
官方 create-plugin 指南里的 unread_dot 案例是个很好的起点:不做后端 API、不注册工具、不装依赖、不发网络请求,只动 Web UI 和一个 localStorage 键。
完整目录结构:
extensions/webui/apply_snapshot_before/track-unread.js
extensions/webui/initFw_end/bootstrap-unread-dot.js
webui/unread-dot.css
webui/unread-dot-store.js
两个钩子是核心:
initFw_end/bootstrap-unread-dot.js:Web UI 启动完成后加载 store 和样式,做初始化。apply_snapshot_before/track-unread.js:每次状态快照应用前跑一遍,检测到另一个 chat 有新的 agent 活动就标记。
行为逻辑:当前 chat 没被选中、但另一个 chat 收到新活动时,在聊天列表挂一个脉冲圆点;打开该 chat 后消失。
实现边界要注意:它只监听"chat 活动"信号,不是解析消息作者。这是官方点名的边界,别自己发挥。
store 用框架的 createStore 模式(webui/js/AlpineStore.js),别另起炉灶。
让 Agent 自己造插件:a0-create-plugin
创建流程不是手工写文件,而是把任务交给 Agent 自己跑 a0-create-plugin skill。
指令要把话说死:
- 插件名、路径、可见行为
- 边界:无外部依赖、无后端 API、无工具、无网络调用
- 已存在就改进而非复制
写完后跑 a0-review-plugin skill,按阶段给出结论:
- Manifest
- Structure
- Code patterns
- Security & index
每个阶段给 PASS / WARN / FAIL。把"能否发布"变成机器可判定的结论。
两条典型教训(都是实际踩过的):
- LICENSE 缺失:本地跑没问题,但上 Plugin Index 会被卡住。
- 社区已有功能相近的 Chat Status Marklet:要先判断你是做学习示例还是做一个值得独立存在的东西,别盲目重复造轮子。
什么时候用扩展而不是插件?
extensions.md 划的界线很实在:
能用插件、项目指令、skill、agent profile 解决就别上扩展。
扩展适合的场景:
- 在特定生命周期点插入行为
- 可复用改 prompt
- 跟核心工具深度绑定
- 任务开始前准备框架态
扩展目录按生命周期阶段组织:
message_loop_prompts_after/
system_prompt/
tool_execute_before/
源码级细节官方丢给 DeepWiki 了,动手前建议去核对。
简单 UI 改动、一次性脚本,插件是更干净的归宿。
发布与安全:上 Plugin Index 前过一遍 checklist
- 独立公开仓库
- 清晰的 README + LICENSE
- 不夹带 secrets、本地路径、机器专属文件
- 说清楚改了什么、怎么卸载
一个关键认知:透明不等于安全。
插件跑在 Web UI 进程上,纯前端相对可控;但一旦加了 subprocess、网络调用、读宿主机(经 A0 CLI Connector),风险边界就完全变了。评审的时候按这个标准收紧。
落地判断
- 从
/a0/usr/plugins/建纯前端小插件开始,别一上来写扩展。 plugin.yaml的name必须和目录同名;per_project_config/per_agent_config决定配置作用域;改完必重启。- Web UI 钩子(
initFw_end、apply_snapshot_before)是前端插件的接入点,store 走createStore。 - 用
a0-create-plugin生成、a0-review-plugin审查。 - 上 Plugin Index 前,LICENSE、README、无 secrets/本地路径是硬门槛。
未实测部分
本文依据官方文档(plugins.md / extensions.md / create-plugin 指南),未在真实实例跑过 a0-create-plugin 生成流程,DeepWiki 的源码细节也没深挖。动手前建议对照 DeepWiki 复核钩子签名。
另外官方文档迭代速度快,路径和 API 以 main 分支为准。