<!-- title: 依开放规范打造首个跨平台Skill -->

## 概述

本教程聚焦 2026 年正在成型的 **Agent Skills 开放规范**（agentskills.io），带你从零编写一份同时满足规范、可在 Claude Code 与 Codex/OpenClaw 等多运行时复用的 `SKILL.md`。适合已经跑通过 Claude Code 首个项目的开发者，希望把重复的团队约定沉淀成"按需加载、可分发、可跨平台"的能力模块。学完你将掌握：frontmatter 元数据规范、三层渐进式披露结构、捆绑脚本与引用文件的工程化写法、`allowed-tools` 安全护栏，以及"计划—校验—执行"的可复用模式。

## 前置条件

- 已安装 Claude Code CLI（`claude --version` 可用），了解基本交互与 `/` 命令。
- 本机有 `git`、`python3`（≥3.8）；建议准备一个使用约定式提交（Conventional Commits）的 Git 仓库作为练习对象。
- 了解 YAML 与 Markdown 基础语法。
- 一个文本编辑器即可，无需额外框架。

---

## 一、先理解：Skill 是什么，规范为何重要

一个 Skill 本质上是**一个目录**，至少包含一个 `SKILL.md`。它把"指令 + 可选脚本 + 引用资料 + 资产"打包成一个可被 Agent 按上下文自动发现并加载的模块。和把长提示词塞进 `CLAUDE.md` 相比，Skill 的关键优势是**按需加载**——只有当当前任务匹配时才进入上下文，不污染无关会话。

为什么强调"开放规范"？因为 2026 年 `SKILL.md` 已不再是 Claude Code 的私有格式。Codex、OpenClaw 等运行时都在采纳同一份清单文件。**只要遵守规范的必填字段、把平台特有行为放进可选元数据，同一份 Skill 就能在多个 Agent 间移植**，这让你沉淀的团队知识不会和单一工具绑定。

### 三层渐进式披露（Progressive Disclosure）

规范的核心设计是分层，让上下文成本最小化：

| 层级 | 内容 | 何时加载 | 设计目标 |
|------|------|----------|----------|
| L1 元数据 | frontmatter 的 `name` / `description` | 会话开始时全量扫描 | 让 Agent 判断"要不要用"，≤200 字符 |
| L2 正文 | `SKILL.md` 的 Markdown 指令 | 决定调用后才读 | 工作流与步骤，建议 <5000 token |
| L3 引用/脚本 | `references/`、`scripts/`、`assets/` | 正文明确指向时才加载 | 大段规范、模板、可执行代码 |

一个装了 20 个 Skill 的项目，任意一次会话通常只为其中 1–2 个付出完整 token 成本——这就是分层加载的价值。

## 二、SKILL.md frontmatter 规范

frontmatter 用 YAML 写在文件最顶部，三横线包裹。

**必填字段（开放规范底线）：**

- `name`：小写、连字符分隔的标识符，必须与目录名一致。
- `description`：用一句话说清"做什么 + 何时该用"。这是 Claude 决定是否调用的唯一依据，**最长 200 字符**，要包含正向触发短语。

**可选字段：**

- `version`：语义化版本，便于团队锁定。
- `allowed-tools`：Claude Code 扩展字段，限制该 Skill 可使用的工具白名单（安全护栏，下文详述）。
- 其它平台特有字段建议放进独立键，保持不破坏 YAML 解析。

一段合格的 description 长这样（注意它同时给了能力与触发词）：

```yaml
description: >-
  Drafts a changelog from git history grouped by conventional-commit type.
  Use when the user asks to "generate release notes", "write a changelog",
  or "what changed since the last release". Emits Keep-a-Changelog format.
```

**反面教材**：`description: 帮助写发布说明`——既没有触发词，也没说输入输出，Agent 很难在合适时机选中它。

## 三、跨平台兼容性对照

写"跨平台"并不等于处处等价，而是让差异**优雅降级**：

| 维度 | Claude Code | Codex | OpenClaw |
|------|-------------|-------|----------|
| 清单文件 | `SKILL.md` | `SKILL.md`（兼容） | `SKILL.md` |
| 个人目录 | `~/.claude/skills/` | 用户级 skills 目录 | 用户级目录 |
| 项目目录 | `.claude/skills/` | `.claude/skills/` | 项目级目录 |
| 安全字段 | `allowed-tools` 白名单 | 平台自有策略 | ClawHub 注册表校验 |
| 注册表分发 | 插件市场 / ZIP | 内置安装命令 | ClawHub（类 npm） |

**可移植性原则**：必填只留 `name` + `description`；把 `allowed-tools` 这类 Claude 专有字段当作"增强"而非"必需"——其它运行时遇到不认识的键会忽略它，而不是报错。脚本要面向 Agent 设计（命令行入参、JSON 出参、有意义的退出码），避免依赖某个 Agent 的交互特性。

## 四、动手：创建 release-notes-drafter Skill

下面构建一个完整、可运行的示例：读取自上次 tag 以来的提交，按约定式提交类型分桶，草拟 Keep-a-Changelog 风格的发布说明。它同时演示捆绑脚本、引用文件与安全护栏。

### Step 1 — 建目录结构

在项目根或用户级目录下创建：

```
.claude/skills/release-notes-drafter/
├── SKILL.md
├── scripts/
│   └── group_commits.py
└── references/
    └── keepachangelog.md
```

目录名 `release-notes-drafter` 必须与 frontmatter 的 `name` 完全一致，否则部分运行时无法发现。

### Step 2 — 编写 SKILL.md

```markdown
---
name: release-notes-drafter
description: >-
  Drafts a changelog from git history grouped by conventional-commit type.
  Use when the user asks to "generate release notes", "write a changelog",
  or "what changed since last release", or before tagging a version. Emits
  Keep-a-Changelog format from commits since the last tag.
---

# Release Notes Drafter

You draft human-readable release notes from a repository's git history,
following Keep-a-Changelog. Deterministic grouping is delegated to a bundled
script; you own the prose and the judgment calls.

## When to use
- User asks for release notes / changelog / "what changed".
- About to cut a tag or publish a release.

## When NOT to use (negative triggers)
- User just wants a raw commit log — run `git log` directly.
- User only needs a semver bump — defer to a dedicated tool.
- Repo has no conventional commits — warn first, do not silently guess types.

## Workflow (plan → validate → execute)
1. PLAN: run `scripts/group_commits.py <range> --dry-run` to confirm scope.
2. VALIDATE: if the script exits with code 2 (empty range), ask the user for
   the correct revision range instead of guessing.
3. EXECUTE: run `scripts/group_commits.py <range>`, read the JSON, then write
   the changelog. Bucket order: Breaking, Added, Fixed, Performance, Changed,
   then Others. Reference each entry's short SHA.
4. Return the draft in a fenced block; list any commits you could not classify.

See `references/keepachangelog.md` for exact section headings and tone.
```

**预期结果**：保存后，当你在 Claude Code 里说"帮我生成本次发布的 changelog"，Agent 会自动加载该 Skill 并按四步流程执行。

### Step 3 — 捆绑脚本（面向 Agent 设计）

`scripts/group_commits.py` 的设计遵循四条铁律：**命令行入参、JSON 出参、有意义退出码、破坏性操作默认 dry-run**。

```python
#!/usr/bin/env python3
"""Group conventional commits into changelog buckets.
Agent-facing: CLI args in, JSON out, meaningful exit codes."""
import sys, json, subprocess, re, argparse

TYPE_MAP = {
    "feat": "Added", "fix": "Fixed", "perf": "Performance",
    "refactor": "Changed", "docs": "Documentation", "test": "Tests",
    "chore": "Maintenance", "build": "Build", "ci": "CI",
}
CONV = re.compile(
    r'^(feat|fix|perf|refactor|docs|test|chore|build|ci)(\([^)]+\))?(!)?:\s*(.+)$',
    re.I)

def resolve_range(rng):
    if rng:
        return rng
    try:
        tag = subprocess.check_output(
            ["git", "describe", "--tags", "--abbrev=0"],
            stderr=subprocess.DEVNULL, text=True).strip()
        return f"{tag}..HEAD"
    except subprocess.CalledProcessError:
        return ""

def collect(rng):
    cmd = ["git", "log", "--pretty=format:%H%x09%s"]
    if rng:
        cmd.append(rng)
    out = subprocess.check_output(cmd, text=True, stderr=subprocess.DEVNULL)
    groups, misc = {}, []
    for line in out.splitlines():
        if "\t" not in line:
            continue
        sha, subj = line.split("\t", 1)
        m = CONV.match(subj)
        if m:
            typ, scope, bang, msg = m.groups()
            label = "Breaking" if bang else TYPE_MAP.get(typ.lower(), "Changed")
            groups.setdefault(label, []).append(
                {"sha": sha[:8], "scope": scope or "", "msg": msg.strip()})
        else:
            misc.append({"sha": sha[:8], "msg": subj.strip()})
    return {"range": rng or "all", "groups": groups, "misc": misc}

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("range", nargs="?", default="")
    ap.add_argument("--dry-run", action="store_true")
    args = ap.parse_args()
    if args.dry_run:
        print(json.dumps({"action": "would-parse", "range": args.range or "auto"}))
        return 0
    result = collect(resolve_range(args.range))
    if not result["groups"] and not result["misc"]:
        print(json.dumps({"error": "no commits in range", "range": result["range"]}))
        return 2
    print(json.dumps(result, indent=2, ensure_ascii=False))
    return 0

if __name__ == "__main__":
    sys.exit(main())
```

**预期输出**（在任意约定式提交仓库执行 `python3 scripts/group_commits.py`）：

```json
{
  "range": "v1.2.0..HEAD",
  "groups": {
    "Added": [{"sha": "a1b2c3d4", "scope": "(auth)", "msg": "support OIDC login"}],
    "Fixed":  [{"sha": "e5f6g7h8", "scope": "",       "msg": "null crash on empty payload"}]
  },
  "misc": []
}
```

退出码约定：`0` 正常产出；`2` 范围内无提交（让 Agent 转而询问用户）。这种"机器可读 + 可分支"的输出，是 Agent 能稳定编排的前提。

### Step 4 — 引用文件（L3 加载）

`references/keepachangelog.md` 只在正文指向时才进上下文，放完整的章节标题与语气规范：

```markdown
# Keep-a-Changelog 参考
- 段落顺序：Added → Changed → Deprecated → Removed → Fixed → Security
- 语气：过去时、面向使用者，不要写实现细节
- 每条以短 SHA 收尾，便于回溯
```

### Step 5 — 加安全护栏

若希望该 Skill 只读不写，可在 frontmatter 追加：

```yaml
allowed-tools:
  - Read
  - Bash(python3 scripts/group_commits.py:*)
  - Bash(git log:*)
  - Bash(git describe:*)
```

这样即使被提示注入诱导，也无法执行 `rm` 或外发请求。注意这是 Claude Code 专有字段，Codex/OpenClaw 会忽略它而不报错——这正是"平台特有字段放可选元数据"的可移植性体现。

## 五、测试与触发验证

1. **静态自检**：目录名 == `name`；`description` < 200 字符且含触发词；所有 `references/`、`scripts/` 路径真实存在。
2. **触发测试**：开新会话，用 3–5 种不同措辞（"写发布说明"/"这次改了啥"/"准备发版"）确认能被自动选中；再用一条**不该触发**的指令（"看一下最近提交"）确认不会误触。
3. **观察 thinking**：若未触发，检查 description 是否缺少关键短语，迭代措辞后再测。

## 六、最佳实践与安全清单

- **写给 Agent，不是写给人**：步骤要可执行，避免模糊的"酌情处理"。
- **包含负向触发**（negative triggers）：明确说"什么情况下不要用"，减少误用。
- **正文控制在 5000 token 内**：超长内容拆到 `references/`。
- **脚本面向 Agent**：CLI 入参、JSON 出参、退出码、默认 dry-run。
- **像对待代码依赖一样对待 Skill**：只用可信来源、安装前审查脚本与 frontmatter、锁定版本。恶意 Skill 可能通过提示注入外发数据、执行捆绑脚本或放大 token 成本。

---

## 实战案例小结

最终产物是一个三文件 Skill：`SKILL.md`（L1+L2）、`scripts/group_commits.py`（确定性分桶）、`references/keepachangelog.md`（L3 规范）。它演示了"计划—校验—执行"模式：先 dry-run 确认范围，校验空范围则反问用户，再产出 JSON 并由 Agent 撰写散文。同一份目录放进 `.claude/skills/` 即被 Claude Code 发现，放进 Codex/OpenClaw 的对应目录同样可用——因为核心只依赖规范的 `name` + `description`。

## 工作流与架构图

```mermaid
flowchart TD
    U[用户: 生成本次发布说明] --> CC{Claude Code 会话}
    CC -->|L1 扫描全部 frontmatter| D[匹配 description?]
    D -->|是| L2[加载 SKILL.md 正文]
    D -->|否| SKIP[跳过, 不消耗 token]
    L2 --> PLAN[1.PLAN: dry-run 确认范围]
    PLAN --> VAL[2.VALIDATE: 退出码=2?]
    VAL -->|是| ASK[反问用户范围]
    VAL -->|否| EXE[3.EXECUTE: 运行脚本取 JSON]
    EXE --> L3[按需加载 references/]
    L3 --> WRITE[4.撰写 Keep-a-Changelog 草稿]
    WRITE --> OUT[返回草稿 + 未分类提交]
    ASK --> PLAN

    subgraph 跨平台复用
      P1[Claude Code<br/>.claude/skills/]
      P2[Codex<br/>兼容 SKILL.md]
      P3[OpenClaw<br/>ClawHub]
    end
    SKILL[同一份 SKILL.md 目录] --> P1
    SKILL --> P2
    SKILL --> P3
```

## 常见问题

- **Skill 不触发？** 90% 是 `description` 问题：超 200 字符、缺触发词、或与其它 Skill 描述重叠导致歧义。
- **脚本被 Agent 改写参数导致报错？** 用 `argparse` 严格校验，并在 frontmatter 的 `allowed-tools` 里用 `Bash(python3 scripts/group_commits.py:*)` 限定可执行命令前缀。
- **跨平台时 `allowed-tools` 报错？** 不会——其它运行时忽略未知键。但别把核心逻辑依赖在它之上。
- **目录用 `skill.md` 还是 `SKILL.md`？** Claude Code CLI 主流约定是 `SKILL.md`；官方帮助文档中也写作 `skill.md`，二者指同一文件，建议统一用大写以兼容社区工具链。

## 延伸阅读

- Anthropic 官方《How to create custom skills》——三层渐进式披露的权威说明与 ZIP 分发结构。
- The Prompt Index《AI Agent Skills Guide 2026》——开放规范、跨平台对照与安全章节（含 Clawdrain 攻击讨论）。
- fp8.co《How to Build Claude Code Skills: 5 Examples》——`allowed-tools` 安全控制与 5 个可复用示例。
- agentskills.io 开放规范——必填/可选字段与发现、解析、信任门控的运行时要求。

## 训练营适用性评估

- **适合类型**：Agent / DevOps / 平台工程方向的中级训练营；也可作为"提示工程进阶"模块的实操课。
- **不适合**：零基础入门营（需先掌握 Claude Code 基本交互与 Git）。
- **建议时长**：讲授 45 分钟 + 动手 60 分钟 + 触发迭代 30 分钟，合计约 2.5 小时。
- **考核点**：学员能独立交付一个含 frontmatter、捆绑脚本、引用文件与 `allowed-tools` 护栏的 Skill，并通过"正/负触发"双测试。

## 参考来源

1. [How to create custom skills — Claude Help Center](https://support.claude.com/en/articles/12512198-how-to-create-custom-skills) — 官方对 SKILL.md 结构、三层渐进式披露与 ZIP 分发的权威说明。
2. [AI Agent Skills Guide 2026: SKILL.md, Claude Code, Codex & Security — The Prompt Index](https://www.thepromptindex.com/how-to-use-ai-agent-skills-the-complete-guide.html) — 开放规范、跨平台对照表与 Skill 安全/最佳实践。
3. [How to Build Claude Code Skills: 5 Examples (2026) — fp8.co](https://fp8.co/articles/Claude-Code-Skills-Complete-Developer-Guide) — frontmatter 规范、`allowed-tools` 安全控制与多个可复用示例。
4. [Claude Code Skills: How to Set Them Up and Use Them — DEV Community](https://dev.to/padawanabhi/claude-code-skills-how-to-set-them-up-and-use-them-1chm) — 目录约定与个人/项目级 Skill 的设置流程。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
