SimpleClaw 的 Skill(技能)系统是一种「可插拔专家指令」机制。每个 Skill 是一个 SKILL.md 文件,描述如何完成某类特定任务(如转录音频、操作 GitHub、调用外部 API)。模型在 System Prompt 中看到技能列表,当用户请求匹配时自行读取技能文件并遵循其指令执行。
Skill 由目录 + SKILL.md 文件构成,文件分 YAML frontmatter 和 Markdown 正文 两部分:
skills/
openai-whisper-api/
SKILL.md ← 主入口
scripts/
transcribe.sh ← 技能引用的辅助脚本
| 字段 | 必须 | 说明 |
|---|---|---|
name |
是 | 技能唯一标识名,fallback 为目录名 |
description |
是 | 一句话描述,展示在 System Prompt 的 <available_skills> 中 |
homepage |
否 | 官网链接,UI 可点击 |
user-invocable |
否 | 是否允许用户通过 /skill 命令直接调用(默认 true) |
disable-model-invocation |
否 | 设为 true 则不出现在 System Prompt,仅供内部引用(默认 false) |
metadata.openclaw |
否 | OpenClaw 扩展元数据(见下文) |
| 字段 | 类型 | 说明 |
|---|---|---|
always |
boolean | 设为 true 时忽略 env/bin 检测,始终加载 |
emoji |
string | UI 展示用图标 |
skillKey |
string | 覆盖默认的配置 key(默认等于 name) |
primaryEnv |
string | 主 API Key 环境变量名(UI 可配置) |
os |
string[] | 限定适用平台,如 ["darwin", "linux"] |
requires |
object | 运行时依赖要求(见下文) |
install |
object[] | 安装规格列表 |
| 字段 | 类型 | 逻辑 | 说明 |
|---|---|---|---|
bins |
string[] | AND | 所有 bin 都必须存在 |
anyBins |
string[] | OR | 任一 bin 存在即可 |
env |
string[] | AND | 所有 env 变量都必须设置 |
config |
string[] | AND | 配置路径条件,如 "browser.enabled" |
---
name: openai-whisper-api
description: Transcribe audio using OpenAI Whisper API
homepage: https://platform.openai.com/docs/guides/speech-to-text
user-invocable: true
metadata:
openclaw:
emoji: 🎤
primaryEnv: OPENAI_API_KEY
os: [darwin, linux, windows]
requires:
env: [OPENAI_API_KEY]
bins: [curl]
---
# OpenAI Whisper API
## Usage
```bash
curl https://api.openai.com/v1/audio/transcriptions \\
-H "Authorization: Bearer $OPENAI_API_KEY" \\
-F file="@{baseDir}/audio.mp3" \\
-F model=whisper-1file: Audio file path (supported formats: mp3, mp4, mpeg, mpga, m4a, wav, webm)model: Always usewhisper-1language: Optional, ISO-639-1 code (e.g.,en,zh)response_format: Optional,json,text,srt,verbose_json,vtt
> **注意**:正文中的 `{baseDir}` 是技能根目录的占位符,模型在 System Prompt 指引中被告知将相对路径解析为技能目录的绝对路径。
---
## Skills 加载机制
### 扫描源(按优先级从低到高)
| 优先级 | 源 | 路径 | source 标签 |
|--------|----|------|-------------|
| 1 | 内置捆绑技能 | `<install>/skills/` | `openclaw-bundled` |
| 2 | 托管技能 | `~/.simpleclaw/skills/` | `openclaw-managed` |
| 3 | 工作区技能 | `<workspace>/skills/` | `openclaw-workspace` |
| 4 | 额外目录 | `config.skills.extraDirs` 配置 | `openclaw-extra` |
同名技能(按 `skill.name`)**高优先级源覆盖低优先级源**,最终合并到一张 `Map<name, Skill>`。
### 单目录扫描逻辑
1. 若目录本身有 `SKILL.md`,将整个目录视为一个技能,直接返回
2. 否则遍历一级子目录,每个含 `SKILL.md` 的子目录是一个技能
3. 过滤隐藏目录(`.` 开头)和 `node_modules`
4. 跳过超出大小上限(默认 256KB)的 `SKILL.md`
---
## 配置参数
Skills 系统的所有配置位于 `config.yml` 的 `skills` 节点下:
```yaml
skills:
# 是否加载内置技能(默认 true)
loadBundled: true
# 内置技能白名单(null 或空列表表示无限制)
allowBundled:
- openai-whisper-api
- github-cli
# 被禁用的技能列表
disabledSkills:
- deprecated-skill
# 额外技能目录列表
extraDirs:
- /path/to/custom/skills
- /another/skill/dir
# 容量限制配置
maxCandidatesPerRoot: 300 # 每根最多候选目录数(默认 300)
maxSkillsLoadedPerSource: 200 # 每源最多加载技能数(默认 200)
maxSkillsInPrompt: 150 # Prompt 最多展示技能数(默认 150)
maxSkillsPromptChars: 30000 # Prompt 最大字符数(默认 30000)
maxSkillFileBytes: 256000 # 单技能文件最大字节(默认 256KB)
| 配置键 | 默认值 | 说明 |
|---|---|---|
skills.loadBundled |
true |
是否加载内置捆绑技能 |
skills.allowBundled |
null |
内置技能白名单,限制只能加载列表中的技能 |
skills.disabledSkills |
[] |
被禁用的技能名称列表 |
skills.extraDirs |
[] |
额外的技能目录路径列表 |
skills.maxCandidatesPerRoot |
300 |
每根目录最多扫描的候选目录数 |
skills.maxSkillsLoadedPerSource |
200 |
每个来源最多加载的技能数 |
skills.maxSkillsInPrompt |
150 |
System Prompt 中最多展示的技能数 |
skills.maxSkillsPromptChars |
30000 |
技能相关 Prompt 的最大字符数 |
skills.maxSkillFileBytes |
256000 |
单个 SKILL.md 文件的最大字节数 |
技能加载时会进行多维度过滤(全部条件为 AND 关系):
- 用户禁用检查:
skillConfig.enabled !== false - 白名单检查:如配置了
skills.allowBundled,内置技能必须在白名单内 - 运行时环境检查(
evaluateRuntimeEligibility()):os:当前平台在允许平台列表内(无列表则不限)requires.bins:所有必需二进制文件可执行requires.anyBins:至少一个 bin 可执行requires.env:所有必需 env 变量非空requires.config:所有配置路径条件为真always=true:跳过所有运行时检查,强制加载
| 标志 | 说明 |
|---|---|
user-invocable: false |
不允许用户通过 /skill 命令直接调用 |
disable-model-invocation: true |
不出现在 System Prompt 的 <available_skills> 中,但仍可被内部引用访问 |
<available_skills>
<skill name="openai-whisper-api" description="Transcribe audio using OpenAI Whisper API" path="~/.simpleclaw/skills/openai-whisper-api/SKILL.md" />
<skill name="github-cli" description="Execute GitHub CLI commands" path="~/.simpleclaw/skills/github-cli/SKILL.md" />
</available_skills>
<skill_usage_instructions>
When a user request matches a skill, use the read_file tool to read the SKILL.md
and follow its instructions. The {baseDir} placeholder in skill content refers
to the skill's root directory.
</skill_usage_instructions>为节省 Token,技能路径中的 $HOME/ 会被替换为 ~/:
- 原路径:
/Users/alice/.simpleclaw/skills/foo/SKILL.md - 压缩后:
~/.simpleclaw/skills/foo/SKILL.md
每个路径节约 5-6 token,100 个技能约节约 500 token。
模型只知道技能文件的路径,不预先加载内容。当任务匹配时模型调用 read_file 工具读取 SKILL.md,再按内容执行。这避免了所有技能文件内容涌入上下文。
public class Skill {
private String name; // 技能名称
private String description; // 技能描述
private String source; // 来源标签
private SkillMetadata metadata; // 扩展元数据
// 检查是否始终加载(忽略 env/bin 检测)
public boolean isAlwaysLoaded()
// 获取主环境变量名
public String getPrimaryEnv()
}public class SkillMetadata {
private boolean always; // 是否始终加载
private String emoji; // UI 图标
private String skillKey; // 配置 key
private String primaryEnv; // 主 API Key 环境变量
private List<String> os; // 适用平台列表
private SkillRequires requires; // 运行时依赖
private List<Map<String, Object>> install; // 安装规格
// 检查平台限制
public boolean isOsAllowed(String currentOs)
}public class SkillRequires {
private List<String> bins; // 必须存在的二进制(AND)
private List<String> anyBins; // 任一存在的二进制(OR)
private List<String> env; // 必须设置的环境变量
private List<String> config; // 配置路径条件
// 检查是否有任何依赖要求
public boolean hasRequirements()
}public class SkillsLoader {
// 加载所有可用技能(按优先级合并)
public Map<String, Skill> loadAllSkills()
// 获取启用的技能列表(根据配置和运行时环境过滤)
public List<Skill> getEnabledSkills(List<String> skillFilter)
}public class SkillParser {
// 解析 SKILL.md 文件,提取 YAML frontmatter 和 Markdown 正文
public Optional<Skill> parseSkillFile(Path file, String source)
}- 在工作区创建技能目录:
mkdir -p my-project/skills/my-custom-skill- 创建
SKILL.md文件:
---
name: my-custom-skill
description: Execute custom data processing tasks
metadata:
openclaw:
emoji: 📊
requires:
bins: [python3]
---
# My Custom Skill
## Usage
Run the processing script:
```bash
python3 {baseDir}/scripts/process.py --input "$INPUT_FILE"
3. 放置辅助脚本:
```bash
mkdir -p my-project/skills/my-custom-skill/scripts
echo '#!/usr/bin/env python3
import sys
print(f"Processing: {sys.argv}")' > my-project/skills/my-custom-skill/scripts/process.py
在 config.yml 中添加:
skills:
extraDirs:
- /absolute/path/to/more/skills
disabledSkills:
- some-unwanted-skill- 技能名称唯一性:同名技能高优先级源会覆盖低优先级源
- 路径安全:技能路径必须在允许的目录范围内,禁止软链接逃逸
- 文件大小限制:默认单技能文件最大 256KB,超大文件会被跳过
- 运行时检测:依赖检测失败会导致技能被过滤,不会出现在 Prompt 中
- 惰性加载:模型需要时才会读取 SKILL.md 内容,不会自动加载