oh-my-claudecode skillify 技能萃取指南:把会话中的可复用工作流固化为 OMC Skill
【免费下载链接】oh-my-claudecodeTeams-first Multi-agent orchestration for Claude Code项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-claudecode
导读
本文围绕 oh-my-claudecode 内置的skillify技能展开,讲解如何将一次会话中刚刚完成、且具备复用价值的多步工作流,萃取为一份带 YAML frontmatter 的可复用 OMC Skill 草稿。读完本文,你将掌握 skillify 的触发前提(Quality Gate)、六步萃取流程、learned skill 的落盘路径约定(omc-learned与.omc/skills),以及 frontmatter 的最低字段规范;同时结合仓库源码,理解内置技能加载、用户技能兼容同步与触发注入的底层机制。
skillify 是什么
在 oh-my-claudecode 中,skillify是一个内置技能(built-in skill),其定位在 skills/skillify/SKILL.md 的 frontmatter 中写得很明确:
--- name: skillify description: Turn a repeatable workflow from the current session into a reusable OMC skill draft ---它解决的问题非常具体:当当前会话暴露了一个可重复的多步工作流时,立即把它固化为一份具体的技能草稿,而不是以后再重新发现一遍。这正是 skills/skill/SKILL.md 中/skill add子命令描述的“从会话中扫描模式并调用 skillify 萃取”的落地入口。
需要说明的是,skillify在仓库中还保留了/oh-my-claudecode:learner这一历史命令作为已弃用的兼容别名(deprecated compatibility alias)。在 commands/skillify.md 中可以看到,skillify兼容命令本身并不携带完整技能描述,而是负责“调度”:读取当前激活的 OMC 插件/安装中捆绑的完整技能说明skills/skillify/SKILL.md,然后把用户的参数作为$ARGUMENTS交给该 SKILL.md 处理;若当前工作目录下不可直接读取该文件,则到CLAUDE_PLUGIN_ROOT/OMC_PLUGIN_ROOT、包根目录或已安装的 OMC 插件目录中定位后再继续。
萃取前的质量门禁(Quality Gate)
SKILL.md 明确要求:在萃取任何技能之前,以下三个条件必须全部为真:
| 判定问题 | 期望答案 | 含义 |
|---|---|---|
| "Could someone Google this in 5 minutes?" | No | 别人花 5 分钟就能搜到的东西不值得固化 |
| "Is this specific to this codebase, project, or workflow?" | Yes | 必须是本代码库/项目/工作流特有的知识 |
| "Did this take real debugging, design, or operational effort to discover?" | Yes | 必须是用真实的调试、设计或运维代价换来的 |
优先萃取那些编码了决策启发式(decision-making heuristics)、约束、陷阱与验证步骤的技能;应避免把通用代码片段(generic snippets)、样板代码或库用法示例沉淀成技能——这些内容属于普通文档的范畴,不应进入技能体系。
这一质量理念在技能模板中同样被贯彻。参考 skills/skill/SKILL.md 的 Skill Quality Guidelines,一份好技能应该同时满足四条标准:
- 非可检索性(Non-Googleable):无法轻易通过搜索引擎找到。例如“如何在 TypeScript 中读取文件”是反例;而“本代码库使用自定义路径解析,需要 fileURLToPath”才是合格示例。
- 上下文特异性(Context-Specific):引用本代码库的真实文件与真实错误,例如“server.py:42 中的 aiohttp 代理会在 ClientDisconnectedError 时崩溃”。
- 精确可执行(Actionable with Precision):精确说明做什么、在哪里做,例如“看到 dist/ 下的 Cannot find module 时,检查 tsconfig.json 的 moduleResolution”。
- 来之不易(Hard-Won):必须经历过显著的调试投入,例如“worker.ts 中的竞态——第 89 行 Promise.all 需要 await”。
六步萃取工作流
skills/skillify/SKILL.md 给出了完整的萃取流程,共六步:
- 识别会话刚刚完成的可重复任务;
- 抽取以下要素:
- 输入(inputs)
- 有序步骤(ordered steps)
- 成功标准(success criteria)
- 约束/陷阱(constraints / pitfalls)
- 验证证据(verification evidence)
- 技能的最佳存放位置(best target location)
- 决策该工作流归属哪种形态:
- 仓库内置技能(repo built-in skill)
- 用户/项目级 learned skill(user/project learned skill)
- 仅文档化(documentation only)
- 起草 learned skill 文件时,必须输出以 YAML frontmatter 开头的完整技能文件:
- 绝不输出纯 Markdown 无 frontmatter 的技能文件;
- 最低 frontmatter 字段如下:
--- name: <skill-name> description: <one-line description> triggers: - <trigger-1> - <trigger-2> ---- 补齐技能文件剩余部分:清晰的触发词、步骤、成功标准与陷阱;
- 指出任何仍过于模糊、不足以安全编码的内容。
落盘路径约定
SKILL.md 明确要求 learned/user/project 技能写入扁平文件路径(flat file-backed paths):
${CLAUDE_CONFIG_DIR:-~/.claude}/skills/omc-learned/<skill-name>.md .omc/skills/<skill-name>.md即用户级技能落在 Claude 配置目录下的skills/omc-learned/,项目级技能落在仓库根目录的.omc/skills/。这两个路径在源码中均有对应实现:
- 在 src/hooks/learner/constants.ts 中定义了
USER_SKILLS_DIR = join(getClaudeConfigDir(), 'skills', 'omc-learned')、GLOBAL_SKILLS_DIR = join(homedir(), '.omc', 'skills')以及PROJECT_SKILLS_SUBDIR = OmcPaths.SKILLS; - 在 scripts/skill-injector.mjs 中同样以
USER_SKILLS_DIR = join(cfgDir, 'skills', 'omc-learned')作为读取 learned skill 的用户级目录。
同时要注意:未提交(uncommitted)的技能在合并到用户级目录或提交到版本控制之前,仍只对当前 worktree 本地可见。这与 skills/skill/SKILL.md 中“项目级技能(.omc/skills/)应随代码一起提交以便团队共享;在 linked worktree 中未提交的技能仅对当前 worktree 生效,worktree 被移除即消失”的描述一致。
为什么目录名固定为 omc-learned
SKILL.md 的 Rules 部分专门强调:为兼容性考虑,请将omc-learned作为存储目录名保留,不要把它当作公开调用名(public invocation name)来对外展示。也就是说,“omc-learned”是一个内部兼容目录约定,而用户在 Claude Code 中实际触发的命令是/oh-my-claudecode:skillify。
这一兼容性在 src/utils/user-skill-compat.ts 中有完整的实现佐证:listOmcLearnedUserSkills()会扫描{CLAUDE_CONFIG_DIR}/skills/omc-learned/下的.md文件与子目录SKILL.md,随后ensureClaudeCodeUserSkillCompat()会尝试在{CLAUDE_CONFIG_DIR}/skills/<name>/SKILL.md位置建立符号链接(symlink)或内容拷贝,从而让 Claude Code 原生技能加载机制也能发现这些 learned skill。这正是“omc-learned 目录 + 兼容同步”双层结构的意义。
skillify 的规则约束
SKILL.md 在 Rules 一节给出了五条硬性约束,起草时须逐条遵守:
- 只捕获真正可重复的工作流;
- 保持技能务实且有边界(practical and scoped);
- 优先使用显式的成功标准,而非含糊的描述;
- 如果工作流仍存在未解决的分支决策,先记录这些分支再起草;
omc-learned仅作为存储目录名保留,不对外呈现为公开调用名(即上节所述兼容性约定)。
输出物清单
一次完整的 skillify 会话结束后,应当产出一份结构化的输出,至少包含:
- 建议的技能名称(Proposed skill name)
- 目标存放位置(Target location)
- 草稿工作流结构或完整技能文件(Draft workflow structure or complete skill file)
- 验证/质量门禁备注(Verification or quality-gate notes)
- 待决问题(Open questions, if any)
其中“待决问题”与 Rules 第 4 条呼应——对于尚不确定的分支决策,宁可显式列出,也不要带着模糊状态落盘。
从源码看 skillify 的完整运行链路
内置技能如何被加载
skillify与仓库skills/目录下的其他技能一样,由 src/features/builtin-skills/skills.ts 统一加载。该模块的核心逻辑是:
- 技能目录固定为包根目录下的
skills/,加载路径为skills/<SKILLNAME>/SKILL.md; loadSkillFromFile()通过parseFrontmatter()解析 YAML frontmatter,取出name、description、aliases、argument-hint等元数据,并将正文(body)渲染为运行时模板;- 加载结果带缓存(
cachedSkills),首次加载后避免重复读盘; - 值得注意的是,
loadSkillsFromDirectory()在排序时将skillify目录提前处理,以保证其废弃别名learner在遇到旧的兼容技能之前先被声明(见代码注释 "Public canonical skill-making surface must claim its deprecated learner alias")。
触发词注入与技能发现
learned skill 之所以能在后续会话中被自动应用,依赖 scripts/skill-injector.mjs 的触发注入机制:该脚本扫描用户级omc-learned与项目级技能目录,解析每个SKILL.md的 frontmatter 中的triggers(其内建 fallback 解析器用正则从 YAML 中提取triggers:列表),然后在当前会话上下文中按触发词匹配并注入相关技能内容。
质量/长度约束与自动萃取提示
src/hooks/learner/constants.ts 还定义了 learned skill 工程化的若干阈值,可作为起草技能时的参考边界:
| 常量 | 值 | 含义 |
|---|---|---|
MAX_SKILL_CONTENT_LENGTH | 4000 | 单份技能正文最大字符数 |
MIN_QUALITY_SCORE | 50 | 自动注入所需的最低质量分 |
MAX_SKILLS_PER_SESSION | 10 | 每个会话最多注入的技能数 |
REQUIRED_METADATA_FIELDS | id, name, description, triggers, source | 必须存在的元数据字段 |
而 src/hooks/learner/detector.ts 则实现了“可萃取时刻检测器”:它用正则模式识别 problem-solution、technique、workaround、optimization、best-practice 五类模式(支持中、英、韩、日、西五语),并给出 0–100 的置信度与建议触发词;当置信度达到阈值(默认 60)时,shouldPromptExtraction()返回 true,generateExtractionPrompt()会生成提示,引导用户输入/oh-my-claudecode:skillify完成萃取。这也解释了 skills/skill/SKILL.md 中/skill setup的 “Scan conversation for patterns” 选项为何会在发现可萃取模式后转交 skillify 处理。
测试契约的印证
仓库测试 src/tests/skills-frontmatter-regression.test.ts 直接锁定了一份与本文内容强相关的契约:它断言skillify技能的模板必须包含“以 YAML frontmatter 开头的完整技能文件”“绝不输出纯 Markdown 技能文件”以及两个落盘路径.omc/skills/<skill-name>.md与skills/omc-learned/<skill-name>.md。这意味着上文描述的最低 frontmatter 规范与路径约定不是文档建议,而是受测试守护的实现事实。
典型使用流程速览
将上述内容串成一个完整的实战闭环:
- 在一次 Claude Code 会话中,你通过大量调试/设计/运维投入解决了一个本项目特有的问题(例如定位到某个文件特定行号的竞态条件);
- Agent 侧的 learner 检测器识别到 problem-solution 模式,置信度达标后建议萃取;
- 你输入
/oh-my-claudecode:skillify,commands/skillify.md 将控制权转交给 skills/skillify/SKILL.md 的完整流程; - 按 Quality Gate 自检三条判定后,抽取 inputs / ordered steps / success criteria / constraints / verification evidence,并选择归属(内置技能 / learned skill / 仅文档化);
- 输出带最低 frontmatter(
name、description、triggers)的完整技能文件,写入${CLAUDE_CONFIG_DIR:-~/.claude}/skills/omc-learned/<skill-name>.md(用户级)或.omc/skills/<skill-name>.md(项目级); - 提交/复制到用户级目录后,技能脱离 worktree 本地状态;后续会话中由 scripts/skill-injector.mjs 依据 triggers 自动注入,从而把“一次性排障”转化为“可复用的团队资产”。
注意事项与边界
- 不要萃取通用知识:能被搜索引擎轻易回答的问题(如库的基本用法)不属于技能范畴,应留在普通文档;
- 不要省略 frontmatter:纯 Markdown 技能文件不会被技能加载/注入链路正确解析,最低字段
name、description、triggers缺一不可; - 未提交的技能是 worktree 本地的:若希望跨项目复用,请将其复制到用户级
omc-learned目录;若希望团队共享,请随项目代码提交.omc/skills/; - 分支未决时先记录:工作流中任何尚未解决的分支决策都应显式写入输出清单的 Open questions,而非带病落盘;
omc-learned是目录名而非命令名:对外调用始终使用/oh-my-claudecode:skillify,/oh-my-claudecode:learner仅为向后兼容的弃用别名。
【免费下载链接】oh-my-claudecodeTeams-first Multi-agent orchestration for Claude Code项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-claudecode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考