关于 working-with-skills
这是一个 PostHog 技能,指导 Agent 高效选择和使用 `skill-*` MCP 工具,涵盖技能发现、按需读取、编写、更新及版本安全流程。
主要功能
- 01渐进式读取技能内容
- 02指导选择合适的技能工具
- 03定向编辑正文与文件
- 04基于版本的更新流程
- 05大型技能的组织建议
适用场景
- 01先查找适用技能再读取正文
- 02仅查看任务所需的文件
- 03创建或修改技能
- 04避免替换整个文件包来更新技能
MCP 相关
该技能说明 Agent 如何使用 PostHog 的 `skill-*` MCP 工具来发现、查看、创建和更新技能。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ posthog/ skills --skill working-with-skills安装后在 Claude Code 中输入/working-with-skills确认已加载。
附带文件references/skill-patterns.md
详细介绍
使用 PostHog 技能
此技能将教 Agent 如何高效使用 skill-* MCP 工具——尽可能减少上下文、往返次数和错误。如果你还不熟悉这些工具本身,请先阅读 skills-store 技能,了解目录。本文介绍的是_如何在工具之间做出选择_,以及当技能变得庞大时_如何扩展工作流_。
操作原则
- 渐进式披露不可妥协。 列表工具返回描述,get 工具返回正文和清单,file-get 工具返回单个文件。切勿“以防万一”而预加载捆绑文件——对于实际任务而言,每个预加载的脚本都是浪费的上下文。
- 选择能完成任务的最小写入操作。 与完整替换正文或整个文件包相比,针对性的
edits或file_edits更省资源、更安全,也能让版本历史更清晰。 - 读取成本低,并发覆盖则不然。 调用任何写入工具前,务必先从
skill-get(或上一次写入的响应)获取最新的version,并将其作为base_version传入。 - 创作时遵循 Agent Skills 规范。
name使用 kebab-case,描述中包含丰富的触发词,正文保持简短,冗长内容放在捆绑文件中。
决策树:我应该调用哪个工具?
Need to know what's available?
└─► skill-list (names + descriptions only)
Need to use / inspect a specific skill?
└─► skill-get (body + file manifest, NO file contents)
└─► skill-file-get (one file, on demand, only as referenced)
Authoring a brand new skill?
└─► skill-create (body + all initial files in one call)
Editing an existing skill?
├─ Body change?
│ ├─ Substantial rewrite ............. update(body=...)
│ └─ Surgical tweak .................. update(edits=[{old, new}, ...])
├─ Bundled file content change?
│ └─ update(file_edits=[{path, edits:[...]}, ...])
├─ Add / remove / rename a file?
│ ├─ Add ............................. skill-file-create
│ ├─ Delete .......................... skill-file-delete
│ └─ Rename .......................... skill-file-rename
└─ Wholesale bundle reset (rare!) ....... update(files=[...]) # replaces ALL files
Renaming the skill itself?
└─► skill-rename (keeps versions, files, and owners)
Want a fork as the starting point?
└─► skill-duplicate (then update the copy)
Done with a skill entirely?
└─► skill-archive (hides ALL versions; cannot be undone)
如果你发现自己要使用 update(body=...),再附上冗长的 files=[...],只为修改一个段落和一个脚本,请停下来——这应该拆成两个更精简的调用(update(edits=[...]) 加 update(file_edits=[...])),或者甚至只需一次同时包含 edits 和 file_edits 的 update 调用。
获取内容前先查找
posthog:skill-list
{ "search": "fractal" }
要“查找某项技能”,正确的工具是 skill-list——它只返回名称和描述。阅读描述正是整个流程的重点:先选出合适的技能,再获取正文。如果 search 无法充分缩小范围,就不带它列出结果并逐项浏览,但不要盲目开始获取候选技能的正文。
每项技能在每个任务中只应调用一次 skill-get,而不是每个问题调用一次。将正文缓存在工作记忆中;只有在怀疑技能内容已发生变化时才重新获取(例如写入时遇到 409——见下文“并发控制”)。
高效阅读大型技能
对于正文较长、捆绑文件较多的大型技能,延迟加载尤为重要。
skill-get(skill_name=...)——读取body和files[]清单。- 浏览正文中的目录/标题。正文应已说明哪些文件对应哪些任务——这正是正文要保持简短并按路径引用文件的原因。
- 对于正文明确指出与_当前任务_相关的每个文件,调用
skill-file-get(file_path=...)。跳过其他所有文件。 - 如果正文提到“少见情况 Y 请参阅 scripts/X”,而你当前并非遇到情况 Y,就不要获取
scripts/X。
拿不准时,少获取文件。你随时可以在下一轮再多获取一个。
创作新技能
使用一次 skill-create 调用,同时提供正文和初始文件——这样技能创建完成后就是 version: 1。不要先创建空技能,再调用 N 次 skill-file-create;那会徒增 N 个版本和 N 次往返,没有任何好处。
posthog:skill-create
{
"name": "my-skill",
"description": "What it does AND when to use it. Include trigger keywords.",
"body": "# my-skill\n\n## When to use\n...\n## Workflow\n...",
"license": "MIT",
"compatibility": "Requires Python 3.10+",
"allowed_tools": ["Bash", "Write"],
"metadata": { "author": "me", "category": "..." },
"files": [
{ "path": "scripts/foo.py", "content": "...", "content_type": "text/x-python" },
{ "path": "references/primer.md", "content": "...", "content_type": "text/markdown" }
]
}
编写规则参考
description是发现入口。 这是skill-list返回的唯一内容。应使其包含丰富的触发条件(用户可能会怎么说),并准确说明范围(该技能能做什么、不能做什么)。name— 使用 kebab-case,最多 64 个字符,不得以连字符开头或结尾,也不得连续使用连字符。规范验证器会拒绝其他格式。- 正文不超过约 500 行。 冗长的前言、详尽的 SQL、完整的示例负载和可运行代码应放在
references/、assets/或scripts/中。正文应引导读者查看这些文件,而不是将内容直接写在正文中。 - 文件布局约定 —
scripts/用于可执行代码,references/用于说明文档和示例,assets/用于模板/数据。当 Agent 只有清单时,也可以依靠这一约定了解文件用途。 allowed_tools列出该技能请求使用的工具。 这只是请求,而非授权:从文件读取技能的执行框架会将列表视为已预先批准;通过 MCP 加载技能的执行框架则会忽略该列表,直到用户批准授权。 只列出该技能实际使用的工具,因为填充无关工具会扩大请求范围。 未声明的工具不会被预先批准,接下来如何处理由执行框架决定:它可以询问用户、拒绝调用,或根本不提供该工具。 有些产品会自行强制执行此列表,因此在这些产品中,遗漏工具会导致调用失败。- 存在相关技能时,以
## Related skills作为结尾部分:列出简短的项目符号列表,每项为`skill-name`,并用一句话说明何时应转而使用该技能,以便调用一个技能时也能发现后续技能。 只用名称引用技能(不含路径——相关技能通常位于其他产品中),并且只列出真正的后续步骤,不要罗列产品中的所有技能。
更新现有技能
最常见的错误是小改动时使用 update(body=..., files=[...])。这样虽然可行,但会将整个技能来回传输,导致版本历史中的差异难以阅读,并且如果 files 不完整,还可能丢失文件。应改用更小粒度的操作。
始终先读取,并记录 version
posthog:skill-get
{ "skill_name": "my-skill" }
记下返回的 version——每次写入时都将其作为 base_version 传入。成功写入后,响应中会包含新的 version;后续写入时应使用该版本。
正文:完整替换与增量编辑
重构正文时,使用完整替换:
posthog:skill-update
{ "skill_name": "my-skill", "body": "# my-skill\n\nNew body...", "base_version": 7 }
调整少数几行时,使用增量编辑(小改动时优先采用——更易审查,出错面更小):
posthog:skill-update
{
"skill_name": "my-skill",
"edits": [
{ "old": "Use Pillow for rendering.", "new": "Use Pillow ≥10.0 for rendering." },
{ "old": "## Old section title", "new": "## New section title" }
],
"base_version": 7
}
每个 edits[].old 在当前正文中都必须恰好匹配一次,并且一次调用中 body 和 edits 不能同时使用。
捆绑文件内容编辑
file_edits 可原位修补一个或多个现有文件——未指定的文件会保持不变。调整脚本逻辑或修正文档中的错别字时,应使用此操作:
posthog:skill-update
{
"skill_name": "my-skill",
"file_edits": [
{
"path": "scripts/foo.py",
"edits": [{ "old": "ITERATIONS = 100", "new": "ITERATIONS = 250" }]
},
{
"path": "references/primer.md",
"edits": [{ "old": "## Outdated header", "new": "## Updated header" }]
}
],
"base_version": 7
}
file_edits 不能添加、删除或重命名文件——只能修补现有文件。结构性更改请使用逐文件工具。
在一次调用中组合编辑
如果更改同时涉及正文和现有文件,可以在一次 skill-update 调用中组合使用 edits(正文)和 file_edits(现有文件),一次发布完整一致的版本:
posthog:skill-update
{
"skill_name": "my-skill",
"edits": [{ "old": "## Configuration", "new": "## Setup" }],
"file_edits": [
{ "path": "scripts/run.py", "edits": [{ "old": "DEBUG = False", "new": "DEBUG = True" }] }
],
"base_version": 7
}
文件路径参数命名(猜测前请先阅读)
同一个概念——捆绑文件的路径——会根据它在请求中的传递位置而采用不同的名称,这常常会让凭记忆操作的 Agent 混淆。规则只有一条:
file_path——当路径是 URL 的一部分时(skill-file-get、skill-file-delete)。这些工具会通过路径指定并读取/删除一个文件。两者也接受path,并会将其规范化为file_path,因此清单中的键也能正常使用。path——当路径是请求正文中的字段时:skill-file-create、files=[{path, content, content_type}]数组,以及file_edits=[{path, edits}]。old_path/new_path——skill-file-rename中的请求正文字段。
记忆方法:path 是文件 对象 中的字段名(它与 content 并列),因此所有携带文件对象的工具都使用 path;通过 URL 指定文件的两个工具则使用 file_path。不确定时,请检查工具的输入架构,不要猜测。
添加、删除、重命名文件
每项操作都是一次独立调用,每次都会发布一个新版本:
posthog:skill-file-create
{ "skill_name": "my-skill", "path": "scripts/julia.py", "content": "...", "base_version": 7 }
posthog:skill-file-delete
{ "skill_name": "my-skill", "file_path": "scripts/old.py", "base_version": 8 }
posthog:skill-file-rename
{ "skill_name": "my-skill", "old_path": "scripts/julia.py", "new_path": "scripts/julia_set.py", "base_version": 9 }
skill-file-rename 是真正的移动操作——它会保留现有内容,无需重新发送。内容未更改时,始终优先使用它,而不是先删除再创建。
何时使用 update(files=[...])(很少)
将 files 传给 skill-update 会替换整个捆绑包——不在数组中的内容都会被移除。只有在你有意清空并重新填充捆绑包时(例如导入新的本地 SKILL.md 文件树),才适合使用此工具。几乎所有其他情况下,都应优先使用 file_edits 和逐文件 CRUD。
处理包含多个文件的大型技能
包含许多文件(10 个以上)的技能需要格外谨慎:
- 将清单视为索引。
skill-get的files[]是你的文件映射。将每个任务步骤对应到一个文件,并且只获取该文件。 - 将结构性变更按顺序串联,而不是分叉。 如果要重命名三个文件,请依次执行:
rename → rename → rename,每次都通过上一次响应中的version串联。这样会产生三个易于审阅的小版本,而不是一个庞大的update(files=[...])数据块。 - 让编辑保持局部。 使用
file_edits针对五个文件执行一次skill-update没问题。一次update(files=[...])携带十个完整文件正文,几乎总是说明你本该使用file_edits。 - 先重构正文内容本身。 如果正文已经超过约 500 行,下一步通常应该是将内容拆分到新的捆绑文件中,再添加更多材料。
并发:base_version
每个写入工具都接受 base_version。请始终传入它。
- 服务端会将
base_version与当前最新版本进行比较。如果匹配,写入成功,新版本为base_version + 1。 - 如果不匹配,写入将被拒绝(其他人已更新该技能)。请重新运行
skill-get,根据新正文协调你的更改,并使用最新的version重试。 - 写入成功后,响应会包含新的
version。后续编辑请使用该版本串联——对于你控制的连续写入,不要在两次写入之间重新执行get。
省略 base_version 并不会让操作变快——这只会把明确的“其他人抢先更新”错误,变成对其工作的静默覆盖。
常见陷阱
- 不带搜索条件调用
skill-list,然后获取每个正文 — 这会破坏渐进式披露。先阅读描述。 - 调用
skill-get后预先获取每个捆绑文件 — 这是内层的同类错误。根据正文中的指示按需获取。 - 用
update(body=..., files=[...])修复一行内容 — 这会往返传输整个技能,使差异难以阅读,还可能导致文件丢失。请使用edits/file_edits。 - 想添加一个文件,却使用
update(files=[...])— 任何未包含的文件都会丢失。请改用skill-file-create。 - 删除后再创建,而不是重命名 — 会丢失内容历史记录,还会多消耗一次版本递增。
- 链式写入后使用过时的
base_version— 使用上一次写入响应中的version,而不是最初调用get时的版本。 - 省略
base_version— 会接受静默覆盖。调用过get后,务必始终包含它。 description为空或含糊 — 通过skill-list搜索几乎无法发现该技能。应将描述视为触发契约。- 正文很长,却没有捆绑文件 — 当正文超过约 500 行时,应重构并将内容移入
references/和scripts/,而不是任其增长。 - 在同一次更新调用中混用
body和edits— 两者不能同时使用。选其一即可。 - 猜测应使用
path还是file_path— file-get 和 file-delete 使用file_path(它位于 URL 中);create、rename(old_path/new_path)、files和file_edits使用path(它是请求正文中的字段)。请参阅上文的“文件路径参数命名”。
归档技能
skill-archive 会按名称隐藏某个技能的所有活动版本。它不针对特定版本,且无法撤销 — 整个团队都会在
skill-list 和 skill-get 中看不到该技能。
posthog:skill-archive
{ "skill_name": "my-skill" }
归档前,如果需要先检查或复制技能,请调用 skill-get。如果要彻底弃用某个技能,归档是合适的工具;要移除单个捆绑文件,请使用
skill-file-delete;要回滚内容,则应发布新版本,而不是归档。
将本地 SKILL.md 目录树迁移到 PostHog
迁移本地技能文件夹时(例如 my-skill/SKILL.md,以及
scripts/、references/、assets/):
- 阅读本地
SKILL.md。其中的 frontmatter 对应name、description、license、compatibility、allowed_tools、metadata。frontmatter 之后的正文会成为body。 - 遍历捆绑的子目录,收集所有文件,并整理为
{ path, content, content_type }。 - 调用一次
posthog:skill-create并传入所有内容 — 技能会以完整的version: 1创建。不要将此操作拆分为一次 create 调用和 N 次 file-create 调用。
创建后,所有人都可以通过 skill-get 使用该技能。
模式:技能适用于哪些用途
技能库中的技能是一种共享的版本化记忆,有写入权限的 Agent 可以更新它。 因此,它的用途远不止提供说明:它可以是 Agent 跨会话维护的项目中心、团队负责的 PostHog 对象目录、随着每次调查不断扩充的运行手册、每日“哪些事情需要我处理”队列,或是队友的 Agent 可以直接加载的交接内容。
references/skill-patterns.md 是一份包含这些模式的实用指南,为每种模式提供文件布局、维护约定和起点。
当用户询问技能适用于哪些用途时,或在创建需要由 Agent 长期维护的技能之前,请阅读此文档。
何时不该使用技能
并非所有持久化提示词都适合放在技能库中:
- 一次性任务说明应放在对话中,而不是技能里。
- 个人临时记录应放在 Agent 记忆或本地文件中。
- 代码不是技能 — 如果某项内容需要由服务运行,就应放在代码库中。
好的技能应可复用、能通过描述发现,并且值得长期投入精力以确保内容准确。