| name | tool-creator |
| description | 把用户的可复用需求封装成标准化的 Agent-CLI 工具,并用 `myagents tool add` 注册进 MyAgents 工具注册表——注册后所有未来会话(builtin / Claude Code / Codex / Gemini 全 runtime)的 AI 都会在 system prompt 里自动发现它。触发场景:(1) 用户说「把 XX 封装成工具」「做成一个工具」「注册个工具」「写个 CLI」「以后能直接用」;(2) 用户描述一个会反复出现的自动化需求——文档/文件批量处理、调用某个云 API、用某个多模态大模型做图像/视频理解等,即使没说"工具"两个字;(3) 你发现自己第二次为同类需求写几乎一样的脚本——这时要主动提议把它升格为注册工具,不要等用户开口。反向边界:一次性任务就地解决、不铸工具;接入现成的 MCP server 用 `myagents mcp`,不归这里。 |
Tool Creator — 创建并注册 Agent-CLI 工具
你正在 MyAgents 里运行。MyAgents 有一个工具注册表(~/.myagents/tools/):注册进去的 CLI 工具会被投放到 PATH(~/.myagents/bin/),它的 description 会自动注入所有未来会话的 system prompt——未来的 AI(包括别的 runtime 上的)会自己想起它、查它的用法、调用它。用户也能在设置页「工具箱」里看到并管理它。
这个 skill 教你两件事:写出一个对 Agent 友好的合格 CLI 工具,以及把它注册进去。
第 0 步:判断要不要铸工具
铸一个工具是在为未来的几百次调用做投资,但注册表里的每个工具都占一行 system prompt。判断标准:
- 铸:需求会重复出现(用户明说"以后还要用",或你已经第二次写同类脚本);有清晰的输入→输出边界;参数可枚举。
- 不铸:一次性任务(就地写脚本跑完即弃);纯交互探索类需求;已有注册工具能覆盖(先
myagents tool list 查一遍)。
- 模型管理器里已配置的模型、单发单收的调用——未来由
myagents model call 覆盖(若该命令存在,优先用它,不铸工具)。
灰色地带主动问用户:"这个要不要我注册成工具,以后直接用?"
第 1 步:选原型
| 原型 | 特征 | 范例(动手前先读对应那个) |
|---|
| A · 纯本地处理 | 文件进文件出,零网络、零密钥 | references/example-local-tool.md |
| B · API 包装 | 调外部 API,有密钥,可能多步工作流(上传→轮询→取结果) | references/example-api-tool.md |
两个范例都是完整可跑的代码,照着改,不要从零发明结构。
第 2 步:写工具——形态契约
目录布局
~/.myagents/tools/<tool-name>/
├── tool.json # manifest(注册时被读取校验)
└── run.mjs # 入口,Node 单文件
tool.json
{
"name": "md-merge",
"version": "1.0.0",
"description": "<≤800 字符,见第 3 步的撰写模板>",
"entry": "run.mjs",
"runtime": "node",
"envKeys": [],
"deps": []
}
name:kebab-case,3–30 字符。起名避开常见系统命令(curl、jq、git、node…)——~/.myagents/bin 在 PATH 里排在系统路径之前,重名会遮蔽系统命令,注册时会被直接打回。加领域前缀最稳妥(md-merge 而不是 merge)。
envKeys:工具需要的环境变量名列表(API key 等)。
deps:依赖的外部二进制(ffmpeg 等),没有就空数组。
技术栈
内置 Node v24 单文件 + node:util 的 parseArgs,零第三方依赖。这不是偏好是约束:MyAgents 已内置 Node 并打通全部 PATH,单文件意味着没有 node_modules、拷目录即分发、跨平台问题已被产品解决过一遍。确实绕不开外部二进制时声明进 deps 并做启动自检(见生死线 8)。
八条生死线
每条都解释了违反的后果——它们不是风格偏好,是工具在 Agent 手里能不能活的分界:
- 绝对禁止交互式输入。 任何 stdin prompt(确认、选择、密码)都会让 Agent 的 shell 调用永久挂死——Agent 没有键盘。危险操作(删除、覆盖、花钱)用确认协议替代:缺
--yes 时打印将要做的变更 + 完整的带 --yes 重跑命令,以退出码 4 退出。Agent 会把变更展示给用户、获准后重跑。
- stdout 只放结果,stderr 放诊断,退出码语义化。 Agent 判断成败只靠这三样。退出码约定:
0 成功 / 1 一般错误 / 2 用法或参数错误 / 3 环境缺失(缺 env key、缺依赖)/ 4 需要确认。进度提示、调试信息一律 stderr;spinner / 彩色转义码对 Agent 是纯噪音,不要。
- 必须有
--json 模式,错误也要结构化。 默认输出给人读的简洁文本;--json 输出机器可解析结果。出错时 stderr 给一行 JSON:{"error": "...", "code": "...", "remediation": "怎么修"}——remediation 是给下一个 Agent 的可行动建议("run myagents tool env <name> set KEY=..."),不是模糊的 "something went wrong"。
- 密钥走 env,绝不走 argv。 argv 会泄进进程列表和日志。从
process.env[KEY] 读,缺失时按退出码 3 + remediation 处理。key 在 tool.json::envKeys 声明,由 myagents tool env <name> set KEY=value 设置。
- 有界运行时间。 不准变 daemon。所有网络请求带
AbortSignal.timeout(...);轮询循环必须有次数/时间上限。预期超过 30 秒的操作在 readme 里声明耗时量级。
- 产物文件输出绝对路径到 stdout。 生成的文件落到当前工作区(或用户指定路径),把绝对路径作为结果打印——这是下游(预览、IM 发送)能接住产物的前提。
- readme 子命令返回标准化使用文档。 固定章节(见第 3 步),未来的 AI 第一次用这个工具前会先跑
<tool> readme。
- 依赖自检,失败要可行动。
deps 里声明的二进制在启动时探测(等效 which),缺失则按生死线 3 的错误格式给出安装指引 + 退出码 3——Agent 拿到的是"装 ffmpeg:brew install ffmpeg",不是一个看不懂的崩溃栈。
三条进阶约定(让工具经得起时间)
- 接口即契约:工具被注册后,未来的 Agent 会从历史会话、readme 缓存里学到它的参数。改版时只加不改不删——加新参数可以,改既有参数的含义/删参数等于在所有学过它的 Agent 脚下抽地毯。
- 高信号输出:返回语义化字段(文件名、人类可读状态),不要裸 UUID / 内部 ID / 全量原始响应。输出大时做截断并提示如何取全量(
--limit/--offset)。
- 本地先验证:参数格式、文件存在性在发网络请求之前验证,错误更快更准(退出码
2)。
第 3 步:写三面文档
工具有三个文档面,各答各的问题,不许混:
| 面 | 回答 | 消费者 |
|---|
description(tool.json) | "什么情况下该想起我" | system prompt 注入 + 设置页列表 |
--help | "参数怎么传" | AI 调用前现查 + 终端用户 |
readme 子命令 | "解决这类问题的方法论" | AI 决定用之后 fetch + 设置页详情 |
description(≤800 字符,超长注册时被打回)
这 800 字符决定未来的 AI 会不会想起这个工具。按五件套写:
- 一句话能力声明
- 触发条件——给具体的用户说法("用户要合并多个 markdown / 把文档拼成一个文件时")。这是五件套里最值钱的部分:写"什么时候用",不要重复"是什么"
- 反模式排除(如有):"单文件转换不要用这个,直接处理即可"
- 2–4 行 quick reference(最常用的调用形态)
- 收尾固定句式:
首次使用前先运行 \ readme`;机器可读输出加 --json`
写完做"新同事测试":一个不知道这个工具存在的同事(或 AI),只读这 800 字符,能不能在对的时机想起它、并大致知道怎么开始?参数命名同理——--input-file 不要 --i,歧义是 Agent 的第一杀手。写不下的细节全部挪进 readme。
--help
必含:用法契约行(md-merge <files...> --out <path> [--json])、每个参数一行说明、至少 3 条贴近真实的示例(Agent 靠示例适配自己的场景)、退出码表。
readme 子命令
固定章节,顺序不变(AI 每次读到的形状一致才能快速定位):
# <tool-name>
## 何时使用 # 适用场景 + 不适用场景
## 快速开始 # 最小可用示例
## 参数 # 完整参数表(与 --help 一致)
## 示例 # 3+ 个真实场景的完整命令
## 失败模式 # 每种退出码/常见错误的含义与处理
## 产物回流 # 产物落在哪、怎么展示给用户(见下)
产物回流章节是强制的:写明"调用方(Agent)拿到产物路径后,必须在回复中引用它(Markdown 链接/图片);IM 会话里用 myagents im send-media --file <path> 发送"。工具跑成功但用户看不到结果 = 这次调用白跑。
第 4 步:自测三连
注册前在 shell 里依次验证,任何一项不过就修:
node run.mjs --help
node run.mjs readme
node run.mjs <真实参数>
原型 B 还要验:故意不设 env key 跑一次——应得到退出码 3 + 带 remediation 的 JSON 错误,而不是裸异常栈。
第 5 步:注册 + 告知
myagents tool add ~/.myagents/tools/<tool-name>
myagents tool env <tool-name> set API_KEY=<value>
myagents tool list
tool add 的常见打回:description 超 800 字符(精简后重试)、工具名撞系统命令(换名加前缀)。报错里带 recoveryHint,照做即可。
注册成功后必须在回复中明确告知用户(可审计性,不可省略):
已注册工具 md-merge(合并多个 Markdown 文件)。我和之后的会话都能直接用它;你可以在 设置 → 工具箱 里查看、停用或删除它。
注册的工具对当前 session 之外的会话在它们下次启动时生效;你自己刚写完它,本 session 直接用就行。
如果 myagents tool --help 报 unknown command:当前 app 版本还没有注册机。把工具完整写好放在 ~/.myagents/tools/<name>/,告知用户"工具已就绪,等应用更新后运行 myagents tool add 注册"。
速查:完整流程
判断值不值得铸(第 0 步)
→ 选原型 A/B,读对应 references 范例(第 1 步)
→ 写 tool.json + run.mjs,过八条生死线(第 2 步)
→ 写 description 五件套 / --help / readme(第 3 步)
→ 自测三连(第 4 步)
→ tool add + env + 告知用户(第 5 步)