Technical Guide

11. Skills 源码:Skill 如何被发现、加载和写入

从 skill_utils、prompt_builder 和 skills 工具看 Hermes 的 Skill 生命周期。

这篇解决什么问题

上一篇讲 Skill 的意义,这一篇看源码。

目标是看懂:Hermes 怎么找到 Skill,怎么决定哪些 Skill 出现在索引里,模型怎么读取完整 Skill,写入 Skill 时又有什么边界。

先看哪些文件

关键文件包括:

agent/skill_utils.py
agent/prompt_builder.py
tools/skills_tool.py
agent/skill_preprocessing.py
agent/skill_commands.py
agent/curator.py

不同版本文件名可能有细节变化,但主线基本是:发现、索引、加载、写入、维护。

Skill 存在哪里

默认用户 Skill 在:

~/.hermes/skills/

Profile 场景下则在:

~/.hermes/profiles/<name>/skills/

此外,Hermes 还可能加载 bundled skills、hub skills、OpenClaw 迁移来的 skills。

agent/skill_utils.py 里的 get_all_skills_dirs() 就是找这些目录的关键函数之一。

发现 Skill 时会跳过哪些目录

skill_utils.py 里定义了排除目录,例如:

.git
.github
.archive
.venv
node_modules
site-packages
__pycache__
.pytest_cache

这不是小细节。

如果不排除,扫描 Skill 时可能把依赖目录、归档文件、测试缓存里的 SKILL.md 当成真实技能。

references 为什么不被当成 Skill

references/templates/assets/scripts/ 是 Skill 的支持目录。

源码里有 SKILL_SUPPORT_DIRS,并明确说明:这些目录里的文件是通过 skill_view(..., file_path=...) 显式加载的,不是独立 Skill 根目录。

这就是 progressive disclosure:主 Skill 先轻量加载,长资料按需读取。

platform 和 environment 过滤

Skill frontmatter 可以声明平台:

platforms: [linux, macos]

也可以声明环境相关条件。

源码里的注释强调:这是“展示/推荐时”的过滤,不是硬限制。也就是说,不匹配时可以不出现在索引里,但用户或系统显式 skill_view 时仍然可以加载。

这点很重要:显式加载代表明确意图。

skill_view 做什么

skill_view 是读取 Skill 的主要工具。

它可以读取:

SKILL.md
references/xxx.md
templates/xxx
scripts/xxx

所以一个复杂 Skill 不需要把所有内容塞进主文件。主文件只放流程和触发条件,长背景资料放 references。

skill_manage 做什么

skill_manage 用于创建、patch、编辑、删除或写入 Skill 支持文件。

它适合沉淀长期流程,不适合记录临时任务进度。

比如:

可以写:技术教程写作检查清单
不要写:今天修了某篇文章第 3 段

后者应该留在会话历史或 git commit 里,而不是 Skill。

Curator 是什么

Hermes 还有 curator 相关逻辑,用于维护 agent 创建的 Skill:使用统计、过期、归档、恢复等。

这说明 Skill 不是“写进去就永远不管”。Skill 会变旧,会重复,也会需要合并。

如果你要新增一个 Skill

最小路径是:

~/.hermes/skills/<category>/<skill-name>/SKILL.md

主文件建议包含:

name
description
when to use
workflow
pitfalls
verification

如果内容很长,把案例和参考拆到:

references/

下一篇看什么

下一篇看 Memory 和 Session。

Skill 是过程知识,Memory 是长期用户/环境事实,Session 是历史对话。三者不要混。