本教程面向已能基本使用 Claude Code、希望掌握自定义 Skill 开发的开发者。你将从零构建一个名为 bump-scout(依赖升级侦察兵)的完整 Skill:给定一个待升级的依赖包,它能扫描出受影响的文件、判定 SemVer 破坏性变更风险、产出一份带风险评级与回滚策略的升级计划。通过这一个项目,你将掌握 SKILL.md 的 frontmatter 触发写法、三层渐进式披露、bundled 脚本与参考文件的组织方式、动态上下文注入、工具权限收敛,以及"模型自动触发 vs 用户手动调用"的取舍。适合 Claude Code 训练营 Day 2 上午的 3 小时实战环节。
allowed-tools、动态上下文注入等特性)git 的真实项目(用于实战环节)主版本.次版本.修订号)的基本概念写 Skill 之前,先要理解它为什么长这样。Claude Code 的 Skill 遵循 Agent Skills 开放规范,其核心设计原则是渐进式披露(Progressive Disclosure)——按需加载,省 context。
把一个 Skill 想象成三层抽屉:
| 层级 | 内容 | 加载时机 | 大致成本 |
|---|---|---|---|
| 第一层 · 索引层 | name + description |
会话启动时始终扫描 | 约 100 tokens/skill |
| 第二层 · 主指令层 | SKILL.md 正文 |
触发匹配后一次性加载 | 通常 < 5000 tokens |
| 第三层 · 支撑层 | scripts/、references/、templates/ |
正文里被显式引用且确实需要时才读 | 按需,可很大 |
关键洞察:description 是触发器,不是文档。会话里装 50 个 Skill,没被用到的那些只各占约 100 tokens,几乎免费。但一旦某个 Skill 的正文被加载,它会常驻整个会话,每一行都是反复发生的 token 成本。所以正文要短,重内容要下沉到第三层。
flowchart LR
A[会话启动] -->|扫描所有 skill| B[第一层:索引\n约100 tokens/skill]
B --> C{用户 prompt\n是否匹配 description?}
C -->|否| D[不加载, 零成本]
C -->|是| E[第二层:加载 SKILL.md 正文]
E --> F{正文是否引用\nscripts/references?}
F -->|需要| G[第三层:按需读取支撑文件]
F -->|不需要| H[直接执行]
G --> H
理解了这层"成本经济学",bump-scout 的结构就自然浮现了:把"如何评估升级"的判断逻辑放进正文(短),把"扫描受影响文件"的机械劳动交给脚本,把"风险矩阵"这种查表型知识放进参考文件——只在真的要对号入座时才读。
新手最常见的错误是把 Skill 写成"瑞士军刀"。bump-scout 只负责一件事:评估一次依赖升级的影响并产出升级计划。它不做的事要明确排除:
npm install / go get(只评估,不改包锁——执行交给用户)audit 类 Skill)职责单一,description 才好写,触发才精准。Skill 与 MCP、Subagent 的边界也由此清晰:Skill 封装"我们团队怎么做某件事"的过程知识;MCP 封装"连接外部服务"的工具;Subagent 封装"隔离上下文的独立工作者"。依赖升级评估是过程知识,用 Skill 正合适。
Skill 存哪,决定了谁能用:
| 级别 | 路径 | 作用范围 |
|---|---|---|
| 个人 | ~/.claude/skills/<name>/SKILL.md |
你的所有项目 |
| 项目 | .claude/skills/<name>/SKILL.md |
仅当前项目 |
| 插件 | <plugin>/skills/<name>/SKILL.md |
启用该插件处 |
| 企业 | managed settings | 全组织 |
同名优先级:企业 > 个人 > 项目,任意级别都会覆盖同名 bundled skill。bump-scout 是通用工具,我们放到个人级,这样每个项目都能用:
mkdir -p ~/.claude/skills/bump-scout/{scripts,references,templates}
cd ~/.claude/skills/bump-scout
创建 ~/.claude/skills/bump-scout/SKILL.md。先看最关键的前两块——frontmatter 和正文开头:
---
name: bump-scout
description: Assesses the impact of upgrading a dependency and produces a risk-rated upgrade plan. Use when the user wants to bump/upgrade/update a package version, asks "is it safe to upgrade X", or plans a major version migration. Scans affected files, classifies SemVer breaking-change risk, and outputs a rollback-ready plan. Does NOT run installers or write migration code.
argument-hint: [package] [from-version] [to-version]
arguments: package from_version to_version
allowed-tools: Read Grep Glob Bash
---
## What this skill does
You are a dependency-upgrade impact assessor. Given a package and its target version,
produce a concise, risk-rated upgrade plan WITHOUT running any installer.
## Inputs
- Package: $package (from-version: $from_version -> to-version: $to_version)
- If versions are omitted, infer the current version from the lockfile/manifest below.
## Procedure
1. **Read the current dependency state** (already inlined in "Current state" below).
2. **Scan affected files** by running `scripts/affected.sh $package` — count and list
import sites grouped by directory.
3. **Classify risk** using `references/risk-matrix.md`. A major-version bump is HIGH
risk until proven otherwise.
4. **Fetch breaking changes**: read the package's CHANGELOG/release notes for the
target major version; summarize the top 3 breaking changes. If offline, say so
and mark risk conservatively.
5. **Produce the plan** by filling in `templates/upgrade-plan.md`.
## Output
Fill the template. Lead with a one-line risk verdict (LOW / MEDIUM / HIGH / BLOCKER).
Keep prose minimal — tables and bullet points over paragraphs.
写 description 的四条铁律(这是整个 Skill 成败的关键):
bump/upgrade/update a package、is it safe to upgrade X——把用户真实会说的话埋进去。Does NOT run installers——明确不做什么,避免误触发后产生危险操作。description + when_to_use 合并后在索引列表里被截断到 1536 字符,超出的部分 Claude 永远看不到。把最重要的放最前。arguments 字段定义了三个命名位置参数,正文里就能用 $package、$from_version、$to_version 替换。用户敲 /bump-scout react 18.2.0 19.0.0,这些变量会被自动填入。allowed-tools 把这个 Skill 能用的工具收敛到四个——这是安全护栏,下文第七步详述。
保存后,无需重启——Claude Code 实时监听 skill 目录变更,新 Skill 在当前会话立即生效。敲 / 触发自动补全,应能看到 bump-scout [package] [from-version] [to-version]。
正文要保持精炼,"扫描受影响文件"这种重复机械活交给脚本。创建 scripts/affected.sh:
#!/usr/bin/env bash
# 扫描某依赖的所有引用点,按目录分组统计。
# 用法: affected.sh <package-name>
set -euo pipefail
pkg="${1:?usage: affected.sh <package-name>}"
# 取包名最后一段做宽匹配:@scope/react -> react
short="${pkg##*/}"
echo "## Affected files for \`$pkg\`"
echo
# 1. 源码 import/require/from
mapfile -t files < <(grep -rIlE \
"(from|import|require)\s+['\"][^'\"]*${short}(@|/|['\"])" \
--include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' \
--include='*.py' --include='*.go' -- . 2>/dev/null || true)
if [ "${#files[@]}" -eq 0 ]; then
echo "- No direct imports found."
exit 0
fi
# 2. 按顶层目录分组计数
echo "| Directory | Files |"
echo "|-----------|-------|"
printf '%s\n' "${files[@]}" | \
awk -F/ '{print $2}' | sort | uniq -c | \
awk '{printf "| %s | %d |\n", $2, $1}'
echo
echo "Total: ${#files[@]} files"
给它可执行权限:
chmod +x ~/.claude/skills/bump-scout/scripts/affected.sh
为什么用脚本而不是让 Claude 自己 grep? 三个理由:(1) 脚本是一次性、确定性的,避免 Claude 在大仓库里反复试错浪费 token;(2) 脚本输出的是结构化数据,Claude 直接填表即可;(3) 脚本可以独立测试——这是 Skill 工程化的基础。注意脚本要做"防御性编程":set -euo pipefail、|| true 兜底 grep 无匹配时的非零退出码,避免 Claude 把脚本崩溃误判为"项目出问题"。
chmod +x 没做,或 shebang 写错。Skill 调用的是真实 shell,路径用绝对或相对仓库根。scripts/affected.ps1,正文里根据平台选择调用哪个。风险分级是"查表"而非"推理"——这种知识最适合放第三层参考文件。创建 references/risk-matrix.md:
# Upgrade Risk Matrix
Classify the bump, then adjust based on findings.
| Version delta | Base risk | What to check |
|---------------|-----------|---------------|
| patch (x.y.**Z**) | LOW | Bug fixes; run test suite |
| minor (x.**Y**.z) | LOW–MED | New APIs/deprecations; check removed deprecations |
| major (**X**.y.z) | **HIGH** | Breaking API/behavior; peer-dep range; migration guide |
| cross-major (e.g. 17→19) | **HIGH+** | Multiple breaking layers; treat as BLOCKER until reviewed |
## Downgrade triggers (move risk one level UP)
- Package is a framework (react, next, vue, express) — ripples through app
- Used in > 50 files OR in critical path (auth, payment, routing)
- Current version is > 2 majors behind (accumulated breaking changes)
- No tests cover the package's usage
## Upgrade triggers (move risk one level DOWN)
- Patch-only with a published security advisory (upgrade is safer than waiting)
- Used in 1–2 trivial files with full test coverage
## Verdict mapping
- LOW: ship directly after tests pass
- MEDIUM: ship behind a feature flag or in a staging canary
- HIGH: staged rollout + rollback plan required (template section 5)
- BLOCKER: do not upgrade without a migration spike first
正文里只用一行引用它(Classify risk using references/risk-matrix.md),Claude 只在真要分级时才读这个文件。这就是渐进式披露的精髓:一个没被触发的 bump-scout 只花 100 tokens;被触发后正文也就几百 tokens;只有真的在评估一次 React 18→19 这种大版本升级时,风险矩阵才会被读进上下文。
模板让 Skill 的输出可预测、可 diff、可纳入团队规范。创建 templates/upgrade-plan.md:
# Upgrade Plan: {{package}} {{from_version}} → {{to_version}}
**Risk verdict:** [LOW / MEDIUM / HIGH / BLOCKER]
## 1. Summary
- One line: what changes and why it matters.
## 2. Affected surface
| Directory | Files | Notes |
|-----------|-------|-------|
## 3. Top breaking changes (from CHANGELOG)
1. ...
2. ...
3. ...
## 4. Required code changes
- [ ] ...
## 5. Rollback plan
- Commit hash before upgrade: `<fill>`
- Rollback command: `git revert <hash>` or lockfile restore command
- Verify-rollback check: <which test/command proves rollback worked>
## 6. Verification
- [ ] `npm test` (or equivalent) green
- [ ] Manual smoke: <critical path>
模板 ≠ 参考文件:参考文件是"给 Claude 看的判断依据",模板是"给 Claude 填的输出骨架"。两者职责不同,分开放,正文里分别引用。
至此,bump-scout 的完整目录结构是:
~/.claude/skills/bump-scout/
├── SKILL.md # 第二层:主指令(短)
├── scripts/
│ └── affected.sh # 第三层:机械劳动
├── references/
│ └── risk-matrix.md # 第三层:查表知识
└── templates/
└── upgrade-plan.md # 第三层:输出骨架
依赖评估最怕 Claude "猜"。官方的动态上下文注入语法 !command` 能在 Claude 看到 Skill 内容**之前**先跑命令、把输出替换进去。在SKILL.md` 末尾追加:
## Current state
### Installed version & manifest
!`cat package.json 2>/dev/null | grep -A2 -B2 "$package" || grep -rI "$package" go.mod requirements.txt pyproject.toml Cargo.toml 2>/dev/null | head -20`
### Recent commits touching this dependency
!`git log --oneline -10 -- '*package.json' '*go.mod' '*requirements.txt' 2>/dev/null | head -10`
!...`` 这一行在 Skill 加载时被 Claude Code 执行并替换为输出,于是 Claude 读到的正文里,当前版本号和最近的相关提交已经是真实数据。这比让 Claude 自己去翻文件更省 token、也更准。
注意:动态注入的命令也算 allowed-tools 里的 Bash 权限范围,且每次 Skill 加载都会执行——别放慢命令(如全仓库 rg 大表),也别放会改写文件的命令(! 是只读注入,写操作应留给正文里的显式步骤)。
第七步的 frontmatter 里我们写了 allowed-tools: Read Grep Glob Bash。这意味着这个 Skill 一旦激活,Claude 只能用这四个工具——不能写文件(Edit/Write)、不能开子代理(Agent)、不能调 MCP 工具。对于"只评估、不执行"的 bump-scout,这是恰当的收敛:即便 Claude 误判想"顺手帮你升级",它也没有写权限,只能产出计划交给你。
写文件工具(Edit/Write)和 Bash 默认仍受你的全局权限模式(permission mode)约束,allowed-tools 是在此基础上再做减法。判断原则:Skill 只应拥有完成任务所必需的最小工具集。一个只读分析 Skill 就不该有写权限;一个生成代码的 Skill 才需要 Edit。
Skill 有两种触发方式,都要测:
方式 A · 模型自动触发(model-invoked)——开一个有 package.json 的项目,自然地说:
我想把 react 从 18 升到 19,先帮我看看影响多大
Claude 读到"upgrade react"匹配 description 里的触发短语,应自动加载 bump-scout,无需敲 /。
方式 B · 用户显式调用:
/bump-scout react 18.2.0 19.0.0
$package 等参数自动填入正文。
| 症状 | 原因 | 解决 |
|---|---|---|
| 完全不触发 | description 没写或没含触发短语 |
把用户真实会说的话放进描述前两句 |
| 触发太频繁(误伤) | 描述太宽泛(如只写 "helps with code") | 收窄到具体动作,加 Does NOT... 边界 |
| 自动补全里描述被截断 | 超过 1536 字符 | 删掉次要内容,关键信息前置 |
| 想强制手动调用 | 不想让模型自动触发 | frontmatter 加 disable-model-invocation: true |
想隐藏不让用户敲 / |
仅作内部子能力 | frontmatter 加 user-invocable: false |
迭代循环:改 description → 重新自然语言提问 → 看是否触发 → 调整。改 SKILL.md 正文或脚本无需重启,实时生效;只有首次创建一个顶层 skills/ 目录才需要重启 Claude Code。
对于扫大仓库这种重活,可让 Skill 在隔离的子代理里执行,避免污染主会话上下文。frontmatter 加一行:
context: fork
context: fork 会让该 Skill 在一个 fork 出来的子上下文里运行,其大量的中间读取(翻 CHANGELOG、扫文件)不占主会话窗口,只把最终计划返回。代价是子代理看不到主会话的对话历史——所以 bump-scout 这种需要当前依赖状态的任务,靠动态注入(第七步)把状态带进去,正好和 fork 配合得天衣无缝。
在某个中型前端项目根目录:
/bump-scout react 18.3.1 19.0.0
Claude 加载 bump-scout,动态注入读出当前 package.json 里 react 实为 18.3.1,随后:
scripts/affected.sh react → 发现 src/components/ 下 42 个文件、src/pages/ 下 18 个文件引用了 react。risk-matrix.md → 命中多条"上调一级"触发器 → 判定 HIGH。ReactDOM.render 移除、propTypes/defaultProps 函数组件弃用、ref 直接作 prop。upgrade-plan.md,产出:# Upgrade Plan: react 18.3.1 → 19.0.0
**Risk verdict: HIGH**
## 1. Summary
跨主版本升级,60 个文件受影响,需迁移已弃用 API;建议分阶段灰度。
## 2. Affected surface
| Directory | Files | Notes |
|-----------|-------|-------|
| src/components | 42 | 大量使用 defaultProps |
| src/pages | 18 | 普遍用 ReactDOM.render |
## 3. Top breaking changes
1. `ReactDOM.render` 被移除 → 须改用 `createRoot`
2. 函数组件 `defaultProps` 弃用 → 改默认参数
3. `ref` 作为普通 prop 传递 → 移除 `forwardRef` 的多数用法
## 4. Required code changes
- [ ] 全局替换 `ReactDOM.render` → `createRoot(...).render(...)`
- [ ] 扫描并迁移所有 `defaultProps` 为参数默认值
- [ ] 审查 `forwardRef` 使用,能简化则简化
## 5. Rollback plan
- Commit hash before upgrade: `<在本步骤前先提交>`
- Rollback command: `git revert <hash>` 并 `npm ci` 恢复锁文件
- Verify-rollback: `npm test` 全绿 + 首页冒烟
## 6. Verification
- [ ] `npm test` green
- [ ] 冒烟:首页渲染、路由跳转、表单提交
整个过程 Claude 没有执行任何 npm install(因为 allowed-tools 没给、description 也声明了不做),只产出计划。你 review 后再手动执行。这正是 bump-scout 的价值:把"升级前要不要慌、慌什么"这件需要经验的事,变成可复用的流程。
flowchart TD
U[用户: 我想升级 react 到 19] --> M{description 匹配?}
M -->|是| L[加载 bump-scout 第二层]
L --> INJ[动态注入: 读 package.json + git log]
INJ --> S1[运行 scripts/affected.sh\n扫描受影响文件]
S1 --> S2[读 references/risk-matrix.md\n判定风险等级]
S2 --> S3[读 CHANGELOG\n提炼破坏性变更]
S3 --> S4[填 templates/upgrade-plan.md]
S4 --> OUT[输出风险评级 + 升级计划]
M -->|否| X[不加载, 零成本]
style L fill:#fef3c7
style OUT fill:#dcfce7
style X fill:#fee2e2
绿色是产出,黄色是第二层加载点,红色是"没触发则免费"。整条链路里,risk-matrix.md 这种重内容只有在"真要分级"时才进入上下文。
bump-scout 优于 dependency-tool;命令名即用户要敲的 /bump-scout。set -euo pipefail、兜底非零退出、可独立测试。.claude/commands/deploy.md 仍可用,但 Skill 多了支撑文件、frontmatter 控制和自动触发——新项目优先用 Skill。bump-scout/ 目录提交到团队的 .claude/skills/(项目级,随仓库共享),或封装成插件(加 .claude-plugin/plugin.json)跨项目分发。code.claude.com/docs/en/skills —— frontmatter 字段表、动态注入、子代理执行、嵌套目录发现的权威来源/skill-creator 脚手架生成新 Skill 并跑 eval 度量触发准确率,是迭代优化的标准工具链allowed-tools 收敛权限的可用 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 等场景全覆盖。
