Skip to content

OpenClaw 源码解读(十九)技能系统与 ClawHub

本篇深入分析 OpenClaw 的技能(Skill)系统——一种基于 Markdown 的声明式 Agent 能力扩展机制。从 SKILL.md 文件格式到六源加载引擎,从 Frontmatter 解析到安全扫描器,从 Prompt 构建到 ClawHub 生态。技能系统让 Agent 从通用 AI 助手进化为领域专家,而无需编写一行代码。


目录


一、技能系统全景

1.1 技能是什么?

技能(Skill)是 OpenClaw 的声明式能力扩展机制。与插件(Plugin)不同,技能不需要编写任何代码——它只是一个 Markdown 文件(SKILL.md),告诉 Agent "你现在拥有这个领域的知识和能力"。

Plugin(插件)= TypeScript 代码 → 运行时注册新功能
Skill(技能)= Markdown 文档 → 注入到 Agent 的 System Prompt 中

核心理念: Agent(LLM)已经非常聪明了,大多数任务它只需要正确的指导(而非新代码)就能完成。技能就是提供这种指导的标准化载体。

1.2 三层渐进式加载

技能使用渐进式上下文披露设计,最大化利用有限的上下文窗口:

Layer 1: 元数据(name + description)
├── 始终存在于 Agent 上下文中
├── ~100 tokens
└── Agent 用它决定"是否需要触发这个技能"

Layer 2: SKILL.md 正文
├── 技能被触发后加载
├── <5000 words
└── 包含具体的操作指令和工作流

Layer 3: 捆绑资源(scripts/ + references/ + assets/)
├── Agent 按需加载
├── 无大小限制(脚本可直接执行而不读入上下文)
└── 只加载当前任务需要的部分

![技能系统全景:Plugin vs Skill 与三层渐进式加载](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/01-infographic-skill-system-overview-1775150757559.png)

1.3 核心文件清单

文件职责
src/agents/skills/types.ts核心类型定义(SkillEntry, SkillSnapshot, SkillMetadata 等)
src/agents/skills/workspace.ts主入口 — 六源加载 + 合并 + Prompt 构建 + 沙箱同步
src/agents/skills/config.ts资格判定 + 配置解析 + 白名单过滤
src/agents/skills/frontmatter.tsYAML Frontmatter 解析 + 元数据提取
src/security/skill-scanner.ts安全扫描(危险代码检测)
skills/*/SKILL.md52 个内置技能定义
skills/clawhub/SKILL.mdClawHub CLI 技能
skills/skill-creator/SKILL.md技能创建指南(元技能)

二、SKILL.md 文件格式

2.1 基本结构

每个技能都是一个目录,包含一个必需的 SKILL.md 文件和可选的捆绑资源:

weather/
├── SKILL.md           ← 必需:技能定义
├── scripts/           ← 可选:可执行脚本
├── references/        ← 可选:参考文档
└── assets/            ← 可选:输出资源(模板、图标等)

2.2 SKILL.md 格式

markdown
---
name: weather
description: "Get current weather and forecasts via wttr.in. Use when: 
  user asks about weather, temperature, or forecasts for any location."
homepage: https://wttr.in/:help
metadata: { "openclaw": { "emoji": "🌤️", "requires": { "bins": ["curl"] } } }
---

# Weather Skill

Get current weather conditions and forecasts.

## When to Use

**USE this skill when:**
- "What's the weather?"
- "Will it rain today/tomorrow?"

## Commands

### Current Weather
​```bash
curl "wttr.in/London?format=3"
​```

2.3 Frontmatter 字段说明

字段必需说明
name技能唯一标识(用于去重、过滤、命令名)
description技能描述(LLM 用它决定何时触发,非常重要)
homepage技能主页 URL
metadataOpenClaw 扩展元数据(环境要求、安装方式等)
command-dispatch斜杠命令分发方式("tool" = 直接调用工具)
command-tool配合 command-dispatch: tool 指定目标工具名

2.4 元数据结构 (metadata.openclaw)

jsonc
{
  "openclaw": {
    "emoji": "🌤️",                   // UI 显示的表情符号
    "primaryEnv": "WEATHER_API_KEY",  // 主要环境变量(用于资格判定)
    "requires": {
      "env": ["WEATHER_API_KEY"],     // 必需的环境变量
      "bins": ["curl"],               // 必需的二进制命令
      "platforms": ["darwin", "linux"] // 支持的平台
    },
    "install": [                      // 安装指南
      {
        "id": "brew",
        "kind": "brew",
        "package": "curl",
        "label": "Install via Homebrew"
      }
    ]
  }
}

2.5 正文设计原则

技能正文遵循**"少即是多"**原则:

默认假设:Agent 已经非常聪明了。 只添加 Agent 不知道的信息。每一段文字都要问自己:"Agent 真的需要这个解释吗?" "这段话值得它占用的 token 吗?"

最佳实践:

  • 正文控制在 500 行以内
  • 用简洁的代码示例替代冗长的文字说明
  • 复杂内容拆分到 references/ 目录
  • 包含明确的 "When to Use" 和 "When NOT to Use" 章节

![SKILL.md 文件格式:目录结构与 Frontmatter 规范](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/02-infographic-skillmd-format-1775150758383.png)


三、Frontmatter 解析引擎

3.1 解析流程 (src/agents/skills/frontmatter.ts)

typescript
export function parseFrontmatter(raw: string): ParsedSkillFrontmatter {
  // 1. 提取 YAML frontmatter(--- 包裹的部分)
  const match = raw.match(/^---\n([\s\S]*?)\n---/);
  if (!match) return {};

  // 2. 解析 YAML
  const yamlText = match[1];
  const parsed = parseYaml(yamlText);  // 使用 yaml 库

  // 3. 安全验证和类型转换
  return {
    name: readString(parsed, "name"),
    description: readString(parsed, "description"),
    homepage: readString(parsed, "homepage"),
    metadata: readObject(parsed, "metadata"),
    // ... 斜杠命令相关字段
  };
}

3.2 OpenClaw 元数据提取

typescript
export function resolveOpenClawMetadata(
  frontmatter: ParsedSkillFrontmatter,
): OpenClawSkillMetadata | undefined {
  const raw = frontmatter?.metadata;
  if (!raw || typeof raw !== "object") return undefined;

  // metadata.openclaw 是 OpenClaw 特有的命名空间
  const openclawMeta = (raw as Record<string, unknown>)["openclaw"];
  if (!openclawMeta || typeof openclawMeta !== "object") return undefined;

  const oc = openclawMeta as Record<string, unknown>;
  return {
    emoji: readString(oc, "emoji"),
    primaryEnv: readString(oc, "primaryEnv"),
    requires: resolveRequires(oc["requires"]),     // { env, bins, platforms }
    install: resolveInstallSpecs(oc["install"]),   // 安装方式数组
  };
}

3.3 调用策略解析

typescript
export function resolveSkillInvocationPolicy(
  frontmatter: ParsedSkillFrontmatter,
): SkillInvocationPolicy {
  return {
    // disableModelInvocation: true → 技能不出现在 Agent 的 prompt 中
    // (仅通过斜杠命令或 API 触发)
    disableModelInvocation: readBool(frontmatter, "disable-model-invocation"),

    // userInvocable: false → 不生成斜杠命令
    userInvocable: readBool(frontmatter, "user-invocable") ?? true,
  };
}

![Frontmatter 解析引擎:从原始文本到结构化数据](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/03-infographic-frontmatter-parser-1775150759172.png)


四、六源加载与优先级合并

4.1 六个技能来源

这是技能系统最核心的设计之一——技能可以来自 6 个不同的来源,按优先级合并:

来源 1: extra(最低优先级)
├── 配置中的 skills.load.extraDirs
└── 插件提供的 skill 目录

来源 2: bundled(内置)
├── OpenClaw 安装目录下的 skills/
└── 52 个内置技能

来源 3: managed(托管)
├── ~/.openclaw/skills/
└── 通过 ClawHub 安装的技能

来源 4: agents-skills-personal(个人全局)
├── ~/.agents/skills/
└── 跨项目的个人技能

来源 5: agents-skills-project(项目级)
├── <工作区>/.agents/skills/
└── 项目特有的技能

来源 6: workspace(最高优先级)
├── <工作区>/skills/
└── 用户手动放置的技能

4.2 合并规则

typescript
const merged = new Map<string, Skill>();

// 低优先级先写入,高优先级覆盖
for (const skill of extraSkills)           merged.set(skill.name, skill);  // 最低
for (const skill of bundledSkills)         merged.set(skill.name, skill);
for (const skill of managedSkills)         merged.set(skill.name, skill);
for (const skill of personalAgentsSkills)  merged.set(skill.name, skill);
for (const skill of projectAgentsSkills)   merged.set(skill.name, skill);
for (const skill of workspaceSkills)       merged.set(skill.name, skill);  // 最高

为什么这样设计? 用户最近放置的技能应该覆盖内置技能。例如,用户可以在 <工作区>/skills/weather/SKILL.md 中放置一个自定义的天气技能,覆盖内置的 weather 技能。

4.3 加载安全限制

每个来源的加载都有严格的资源限制:

typescript
const DEFAULT_LIMITS = {
  maxSkillsLoadedPerSource: 200,     // 每个来源最多 200 个技能
  maxCandidatesPerRoot: 500,         // 每个根目录最多扫描 500 个子目录
  maxSkillFileBytes: 256 * 1024,     // 单个 SKILL.md 最大 256KB
  maxSkillsInPrompt: 80,             // Prompt 中最多包含 80 个技能
  maxSkillsPromptChars: 200_000,     // Prompt 中技能总字符数上限 200K
};

为什么需要限制?

  • 防止恶意技能目录(包含数万个子目录)导致加载超时
  • 防止超大 SKILL.md 文件(如 1GB 的二进制数据伪装成 Markdown)导致 OOM
  • 防止 Prompt 注入超过 LLM 上下文窗口

4.4 异常目录检测

typescript
const childDirs = listChildDirectories(baseDir);
const suspicious = childDirs.length > limits.maxCandidatesPerRoot;

if (suspicious) {
  skillsLogger.warn("Skills root looks suspiciously large, truncating discovery.", {
    dir: params.dir,
    childDirCount: childDirs.length,
  });
}

如果一个技能根目录下有超过 500 个子目录,会被标记为可疑并截断扫描。

![六源加载与优先级合并:从低到高的技能来源层级](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/04-infographic-six-source-loading-1775150759950.png)


五、技能资格判定与过滤

5.1 过滤流程 (src/agents/skills/config.ts)

加载完所有技能后,需要根据当前环境决定哪些技能有资格被包含到 Agent 的 Prompt 中:

加载的全部技能

    ├─ Filter 1: skillFilter(配置指定的技能白名单)
    │   └─ 如果配置了 skills.filter: ["weather", "github"],只保留这两个

    ├─ Filter 2: bundled allowlist(内置技能白名单)
    │   └─ 如果配置了 skills.bundled.allowlist: ["weather"]
    │       则只保留内置技能中的 weather

    ├─ Filter 3: 平台检查
    │   └─ requires.platforms 不包含当前 OS?→ 排除

    ├─ Filter 4: 环境变量检查
    │   └─ requires.env 中有未设置的变量?→ 排除

    ├─ Filter 5: 二进制命令检查
    │   └─ requires.bins 中有未安装的命令?→ 排除

    └─ 输出:eligible 技能列表

5.2 资格上下文

typescript
export type SkillEligibilityContext = {
  platform?: NodeJS.Platform;          // "darwin" | "linux" | "win32"
  envKeys?: Set<string>;               // 当前已设置的环境变量名
  availableBins?: Set<string>;         // 已安装的二进制命令名
  remote?: {                            // 远程执行上下文
    note?: string;                      // 远程注入的说明
    envKeys?: Set<string>;
  };
};

5.3 shouldIncludeSkill 决策函数

typescript
export function shouldIncludeSkill(
  entry: SkillEntry,
  config?: OpenClawConfig,
  skillFilter?: string[],
  eligibility?: SkillEligibilityContext,
): boolean {
  // 1. 名称过滤
  if (skillFilter && !skillFilter.includes(entry.skill.name)) {
    return false;
  }

  // 2. 内置技能白名单
  if (entry.skill.source === "openclaw-bundled") {
    if (!isBundledSkillAllowed(entry.skill.name, config)) {
      return false;
    }
  }

  // 3. 平台要求
  const platforms = entry.metadata?.requires?.platforms;
  if (platforms?.length && eligibility?.platform) {
    if (!platforms.includes(eligibility.platform)) {
      return false;
    }
  }

  // 4. 环境变量要求
  const envReqs = entry.metadata?.requires?.env;
  if (envReqs?.length && eligibility?.envKeys) {
    const allMet = envReqs.every(e => eligibility.envKeys!.has(e));
    if (!allMet) return false;
  }

  // 5. 二进制命令要求
  const binReqs = entry.metadata?.requires?.bins;
  if (binReqs?.length && eligibility?.availableBins) {
    const allMet = binReqs.every(b => eligibility.availableBins!.has(b));
    if (!allMet) return false;
  }

  return true;
}

![技能资格判定:五层过滤漏斗](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/05-infographic-eligibility-filter-1775150760821.png)


六、Prompt 构建与上下文预算

6.1 构建流程

eligible 技能列表

    ├─ 排除 disableModelInvocation=true 的技能
    │   (这些技能只通过斜杠命令触发,不占用 Prompt 空间)

    ├─ 应用数量上限(maxSkillsInPrompt = 80)

    ├─ 应用字符预算(maxSkillsPromptChars = 200,000)
    │   └─ 二分搜索找到不超预算的最大前缀

    ├─ 路径压缩(compactSkillPaths)
    │   └─ 将绝对路径压缩为相对路径,节省 token

    └─ 格式化输出

6.2 二分搜索字符预算

当技能总量超过字符预算时,使用二分搜索找到能装入预算的最大技能数:

typescript
function applySkillsPromptLimits(params) {
  const { skills, config } = params;
  const limits = resolveSkillsLimits(config);

  // 先按数量截断
  let skillsForPrompt = skills.slice(0, limits.maxSkillsInPrompt);

  const fits = (skills: Skill[]): boolean => {
    const block = formatSkillsForPrompt(skills);
    return block.length <= limits.maxSkillsPromptChars;
  };

  if (!fits(skillsForPrompt)) {
    // 二分搜索:找到最大的 N 使得前 N 个技能的 Prompt 长度 ≤ 预算
    let lo = 0;
    let hi = skillsForPrompt.length;
    while (lo < hi) {
      const mid = Math.ceil((lo + hi) / 2);
      if (fits(skillsForPrompt.slice(0, mid))) {
        lo = mid;
      } else {
        hi = mid - 1;
      }
    }
    skillsForPrompt = skillsForPrompt.slice(0, lo);
  }

  return { skillsForPrompt, truncated: ... };
}

为什么用二分搜索而非逐个添加? 因为 formatSkillsForPrompt() 需要序列化整个列表(开销较大),二分搜索只需要 O(log N) 次调用。

6.3 SkillSnapshot 快照

Prompt 构建完成后生成一个快照,供运行时使用:

typescript
type SkillSnapshot = {
  prompt: string;                    // 最终注入 Agent Prompt 的文本
  skills: Array<{
    name: string;                    // 技能名
    primaryEnv?: string;             // 主要环境变量(UI 显示用)
    requiredEnv?: string[];          // 所需环境变量(UI 显示用)
  }>;
  skillFilter?: string[];            // 应用的过滤器
  resolvedSkills: Skill[];           // 完整的技能对象(含文件路径等)
  version?: number;                  // 快照版本号
};

![Prompt 构建与上下文预算:二分搜索最大装入量](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/06-infographic-prompt-budget-1775150761549.png)


七、技能安全扫描器

7.1 为什么需要安全扫描?

技能可以来自第三方(ClawHub 或手动安装),可能包含恶意代码。虽然 SKILL.md 本身只是 Markdown,但技能目录中可能包含 scripts/ 下的可执行脚本。

7.2 扫描目标

扫描器检查技能目录中的 JavaScript/TypeScript 文件

typescript
const SCANNABLE_EXTENSIONS = new Set([
  ".js", ".ts", ".mjs", ".cjs", ".mts", ".cts", ".jsx", ".tsx",
]);

7.3 扫描规则

行级规则(逐行匹配):

规则 ID严重性检测内容正则模式
dangerous-exec🔴 criticalShell 命令执行exec|spawn|execFile + child_process
dynamic-code-execution🔴 critical动态代码执行eval( | new Function(
crypto-mining🔴 critical加密货币挖矿stratum+tcp|coinhive|xmrig
suspicious-network🟡 warn非标准端口 WebSocketnew WebSocket("wss://...:PORT")

源码级规则(全文匹配):

规则 ID严重性检测内容检测逻辑
potential-exfiltration🟡 warn数据泄露readFile + fetch/post/http.request 同时出现
obfuscated-code🟡 warn混淆代码连续 6+ 个 \xHH 或 200+ 字符的 base64
env-harvesting🔴 critical凭证窃取process.env + fetch/post/http.request 同时出现

7.4 扫描架构

scanSkillDirectory(dirPath)

    ├─ 递归遍历目录(最大深度限制)
    │   ├─ 跳过 node_modules/
    │   ├─ 跳过 .git/
    │   └─ 限制最多 500 个文件

    ├─ 对每个可扫描文件:
    │   ├─ 检查文件大小(≤ 1MB)
    │   ├─ 检查缓存(mtimeMs + size 未变 → 跳过)
    │   ├─ 读取文件内容
    │   ├─ 执行行级规则
    │   ├─ 执行源码级规则
    │   └─ 缓存结果

    └─ 返回 SkillScanSummary
        { scannedFiles, critical, warn, info, findings }

7.5 缓存机制

扫描结果使用文件指纹缓存(size + mtimeMs),避免重复扫描未修改的文件:

typescript
function getCachedFileScanResult(params: {
  filePath: string;
  size: number;
  mtimeMs: number;
  maxFileBytes: number;
}): FileScanCacheEntry | undefined {
  const cached = FILE_SCAN_CACHE.get(params.filePath);
  if (!cached) return undefined;
  if (
    cached.size !== params.size ||
    cached.mtimeMs !== params.mtimeMs ||
    cached.maxFileBytes !== params.maxFileBytes
  ) {
    FILE_SCAN_CACHE.delete(params.filePath);
    return undefined;
  }
  return cached;
}

缓存上限 5000 条,超出时采用 FIFO 淘汰。

7.6 上下文关联规则

某些规则需要两个模式同时出现才触发(减少误报):

typescript
{
  ruleId: "env-harvesting",
  severity: "critical",
  pattern: /process\.env/,                    // 主模式
  requiresContext: /\bfetch\b|\bpost\b|http\.request/i,  // 上下文模式
  // 只有当文件同时包含 process.env 和网络请求时才报告
}

单独使用 process.env 是完全正常的(读取配置),但如果同时存在网络请求,可能是在窃取环境变量中的凭证

![技能安全扫描器:双层规则与缓存机制](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/07-infographic-security-scanner-1775150762287.png)


八、斜杠命令生成

8.1 从技能到斜杠命令

每个有资格的技能都会自动生成一个斜杠命令,供用户在消息渠道中触发:

技能 "weather" → 斜杠命令 /weather
技能 "gh-issues" → 斜杠命令 /gh-issues
技能 "openai-image-gen" → 斜杠命令 /openai-image-gen

8.2 命令名归一化

typescript
function sanitizeSkillCommandName(rawName: string): string {
  return rawName
    .toLowerCase()
    .replace(/[^a-z0-9_-]/g, "-")     // 非法字符替换为 "-"
    .replace(/^-+|-+$/g, "")           // 去掉前后 "-"
    .slice(0, 32);                      // 最大 32 字符
}

8.3 命令去重

如果多个技能归一化后命名相同,会自动添加数字后缀:

typescript
function resolveUniqueSkillCommandName(base: string, used: Set<string>): string {
  if (!used.has(base.toLowerCase())) return base;
  for (let i = 2; i < 10_000; i++) {
    const candidate = `${base}-${i}`;
    if (!used.has(candidate.toLowerCase())) return candidate;
  }
  // 极端情况的 fallback...
}

8.4 工具分发命令

某些技能可以配置为直接调用工具而非注入 Prompt:

yaml
---
name: camsnap
description: Take a photo using the phone camera
command-dispatch: tool
command-tool: nodes
command-arg-mode: raw
---

当用户输入 /camsnap front 时,系统直接调用 nodes 工具的 camera_snap 操作,而非将消息发给 Agent 处理。

8.5 保留命令名

系统命令(如 /help/model/session)的名称被预留,技能命令不能与它们冲突:

typescript
const specs = buildWorkspaceSkillCommandSpecs(workspaceDir, {
  reservedNames: new Set(["help", "model", "session", "status", ...]),
});

![斜杠命令生成:从技能名到 /command](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/08-infographic-slash-commands-1775150763304.png)


九、沙箱同步机制

9.1 为什么需要同步?

当 Agent 在 Docker 沙箱中运行时,沙箱内没有主机上的技能文件。syncSkillsToWorkspace 将技能从主机复制到沙箱工作区:

主机文件系统                          Docker 沙箱
├── ~/.openclaw/skills/weather/       
├── ~/workspace/skills/github/        
├── /usr/lib/.../skills/canvas/       
│                                     ├── /sandbox/skills/weather/
│         syncSkillsToWorkspace() ──→ ├── /sandbox/skills/github/
│                                     └── /sandbox/skills/canvas/

9.2 同步流程

typescript
export async function syncSkillsToWorkspace(params: {
  sourceWorkspaceDir: string;    // 主机工作区
  targetWorkspaceDir: string;    // 沙箱工作区
  config?: OpenClawConfig;
}) {
  // 1. 如果源和目标相同,跳过(非沙箱模式)
  if (sourceDir === targetDir) return;

  // 2. 序列化执行(防止并发同步)
  await serializeByKey(`syncSkills:${targetDir}`, async () => {
    // 3. 加载所有来源的技能
    const entries = loadSkillEntries(sourceDir, { ... });

    // 4. 清空目标目录
    await fsp.rm(targetSkillsDir, { recursive: true, force: true });
    await fsp.mkdir(targetSkillsDir, { recursive: true });

    // 5. 逐个复制(安全路径解析 + 名称去重)
    for (const entry of entries) {
      const dest = resolveSyncedSkillDestinationPath({ ... });
      await fsp.cp(entry.skill.baseDir, dest, { recursive: true });
    }
  });
}

9.3 路径安全

目标路径经过沙箱路径解析(resolveSandboxPath),确保技能文件不会被复制到沙箱工作区之外:

typescript
const dest = resolveSandboxPath({
  filePath: uniqueDirName,
  cwd: targetSkillsDir,
  root: targetSkillsDir,   // 不能逃出这个目录
}).resolved;

![沙箱同步机制:主机到 Docker 的技能迁移](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/09-infographic-sandbox-sync-1775150764104.png)


十、ClawHub 生态

10.1 ClawHub 是什么?

ClawHub(clawhub.com)是 OpenClaw 的技能分发平台——类似于 npm 之于 Node.js,或 Docker Hub 之于容器。用户可以在 ClawHub 上搜索、安装、更新和发布技能。

10.2 ClawHub CLI

ClawHub 本身也是一个技能(skills/clawhub/SKILL.md),通过 npm 安装:

bash
npm i -g clawhub

10.3 核心命令

命令说明
clawhub search "postgres backups"搜索技能
clawhub install my-skill安装技能到 ~/.openclaw/skills/
clawhub install my-skill --version 1.2.3安装指定版本
clawhub update --all更新所有已安装技能
clawhub update my-skill --force强制更新
clawhub list列出已安装技能
clawhub publish ./my-skill --slug my-skill发布技能
clawhub login登录(发布需要)

10.4 版本管理

ClawHub 使用基于文件哈希的版本匹配

bash
clawhub update my-skill
# 1. 计算本地技能文件的哈希
# 2. 在 registry 中找到匹配的版本
# 3. 如果有更新版本,下载并替换

10.5 三种分发方式

方式目录来源说明
Bundled<安装目录>/skills/内置于 OpenClaw随版本更新
Managed~/.openclaw/skills/ClawHub 安装独立于版本更新
Workspace<工作区>/skills/手动放置最高优先级

![ClawHub 生态:技能分发平台架构](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/10-infographic-clawhub-ecosystem-1775150765073.png)


十一、内置技能巡览

11.1 52 个内置技能分类

🖥️ 开发工具(12 个):

技能说明
githubGitHub CLI 操作(issues/PRs/repos)
gh-issuesGitHub Issues 管理
coding-agent编码代理工作流
tmuxTmux 终端复用器操作
oracle数据库查询辅助
sagSearch-and-grep 代码搜索
session-logs会话日志分析
skill-creator创建新技能的元技能
gogGo 开发辅助
eightctl8base 平台操作
blucliBlueink CLI 操作
nano-banana-proBanana 推理平台

🌐 Web & API(6 个):

技能说明
weather天气查询(wttr.in)
xurlURL 处理工具
blogwatcher博客/RSS 监控
goplaces地点搜索
healthcheckHTTP 健康检查
gifgrepGIF 搜索

📱 消息与社交(8 个):

技能说明
discordDiscord 操作增强
slackSlack 操作增强
imsgiMessage 操作
bluebubblesBlueBubbles iMessage 桥
wacliWhatsApp CLI
voice-call语音通话
telegram*(通过插件提供)
songsee歌曲识别

📝 笔记与生产力(7 个):

技能说明
apple-notesApple Notes 操作
apple-remindersApple Reminders 操作
bear-notesBear 笔记操作
notionNotion 操作
obsidianObsidian 笔记操作
trelloTrello 看板操作
things-macThings 任务管理

🎨 媒体与 AI(8 个):

技能说明
openai-image-genOpenAI 图像生成(DALL·E)
openai-whisper本地语音转文字
openai-whisper-apiWhisper API 语音转文字
geminiGoogle Gemini 增强
canvasCanvas UI 操作
camsnap手机拍照
peekaboo截图分析
video-frames视频帧提取
nano-pdfPDF 处理

🏠 智能家居 & 设备(4 个):

技能说明
openhuePhilips Hue 灯光控制
sonoscliSonos 音响控制
spotify-playerSpotify 播放控制
1password1Password 密码管理

🔧 系统与运维(5 个):

技能说明
clawhubClawHub 技能管理
model-usage模型用量统计
summarize文本总结
himalaya邮件客户端
mcporterMC Porter 工具
ordercliOrder CLI 工具
sherpa-onnx-tts本地 TTS 引擎

11.2 技能结构示例

weather 技能为例,展示一个设计良好的技能:

weather/
└── SKILL.md (112 行)
    ├── Frontmatter:
    │   ├── name: weather
    │   ├── description: 清晰的使用场景描述
    │   └── metadata: { requires: { bins: ["curl"] } }

    ├── When to Use: 5 个匹配场景
    ├── When NOT to Use: 5 个排除场景

    └── Commands: 具体的 curl 命令示例
        ├── 当前天气
        ├── 预报
        ├── 格式选项
        └── 快速响应模板

![52 个内置技能分类全景图](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/11-infographic-builtin-skills-1775150765898.png)


十二、设计模式与架构总结

12.1 技能系统数据流

                    ┌──────────────────────────────────────┐
                    │          6 个技能来源                  │
                    │  extra < bundled < managed <          │
                    │  personal < project < workspace       │
                    └───────────────┬──────────────────────┘
                                    │ loadSkillEntries()
                    ┌───────────────▼──────────────────────┐
                    │        合并 (Map.set 覆盖)             │
                    │        + Frontmatter 解析              │
                    │        + 元数据提取                    │
                    └───────────────┬──────────────────────┘
                                    │ filterSkillEntries()
                    ┌───────────────▼──────────────────────┐
                    │           资格过滤                     │
                    │  平台 / 环境变量 / 二进制命令 / 白名单  │
                    └──┬────────────────────────────────┬──┘
                       │                                │
          ┌────────────▼──────────┐      ┌──────────────▼──────────┐
          │  buildSkillsPrompt()  │      │  buildSkillCommandSpecs │
          │  → Agent System Prompt│      │  → 斜杠命令注册          │
          │                       │      │                         │
          │  二分搜索字符预算     │      │  名称归一化+去重        │
          │  路径压缩             │      │  保留名冲突检查         │
          └───────────────────────┘      └─────────────────────────┘

                    ┌──────────────────────────────────────┐
                    │        安全扫描器 (skill-scanner)      │
                    │                                      │
                    │  行级规则: exec/eval/mining/websocket │
                    │  源码级规则: exfiltration/obfuscation │
                    │  缓存: 文件指纹 (size+mtime)          │
                    └──────────────────────────────────────┘

12.2 关键设计模式

模式应用说明
声明式扩展SKILL.md无需代码,Markdown 即能力
渐进式披露三层加载元数据 → 正文 → 资源,最小化 token 消耗
优先级覆盖六源合并用户本地 > 托管 > 内置
二分搜索Prompt 预算O(log N) 找到最大装入量
静态分析安全扫描器无需执行即可检测恶意代码
资源限制加载限制防止恶意技能目录 DoS
缓存失效文件指纹size + mtimeMs 变化即重新扫描
序列化执行沙箱同步serializeByKey 防止并发写入

![设计模式总结:技能系统 8 大设计模式](https://qn.huat.xyz/blog/article-Illustration/OpenClaw 源码解读(十九)技能系统与 ClawHub/12-infographic-design-patterns-1775150766700.png)

12.3 推荐阅读顺序

优先级文件行数难度
🔴 必读skills/skill-creator/SKILL.md~200★☆☆☆☆
🔴 必读agents/skills/types.ts~89★★☆☆☆
🔴 必读agents/skills/workspace.ts~760★★★★☆
🟡 推荐agents/skills/frontmatter.ts~228★★★☆☆
🟡 推荐agents/skills/config.ts~102★★☆☆☆
🟡 推荐security/skill-scanner.ts~260★★★☆☆
🟢 选读skills/weather/SKILL.md~112★☆☆☆☆
🟢 选读skills/clawhub/SKILL.md~77★☆☆☆☆
🟢 选读skills/github/SKILL.md(示例)★☆☆☆☆

12.4 思考题

  1. 为什么技能系统选择 Markdown 文件而非 JSON/YAML 配置?

    提示:考虑 LLM 的"母语"——它最擅长理解什么格式的文本?

  2. 六源加载中,为什么 workspace(工作区)优先级最高,而 bundled(内置)只排第二?

    提示:考虑用户需要覆盖内置技能行为的场景。

  3. 安全扫描器为什么用 requiresContext 来减少误报?单模式匹配有什么问题?

    提示:process.env 在正常代码中非常常见,仅匹配它会产生大量误报。

  4. Prompt 字符预算为什么用二分搜索而非逐个添加?

    提示:考虑 formatSkillsForPrompt() 的计算开销——它需要序列化整个列表。

  5. 如果你要创建一个新技能,应该放在哪个目录?为什么?

    提示:根据技能的使用范围选择——个人全局 vs 项目特有 vs 工作区。


📌 小结: 技能系统是 OpenClaw 最具创新性的设计之一——它用最朴素的载体(Markdown 文件)实现了最强大的效果(领域专家能力)。52 个内置技能覆盖了从天气查询到智能家居控制的广泛场景,而 ClawHub 生态则让社区可以共享和分发技能。整个系统的工程设计体现了"简单但不简陋"的哲学——六源加载、渐进式披露、二分搜索预算、静态安全分析,每一个细节都经过精心考量。对于想要理解"如何让 AI Agent 拥有领域知识"的开发者来说,这是一个值得反复学习的参考实现。

读文档、看源码、写代码,理解 AI Agent 本质 🤖