如何写一个Claude_Code的Skills插件
本文介绍了如何为Claude Code开发Skills插件,提升AI辅助开发效率。主要内容包括: Skills概念:类似VS Code插件,通过Markdown文件扩展Claude能力,分为参考内容和任务内容两种类型。 实战教程: 创建代码解释Skill,提供结构化解释方法(类比+流程图+逐步讲解) 开发PR总结Skill,自动分析GitHub PR变更并生成报告 高级技巧: 使用参数实现动态调用
从零开始写一个Claude Code Skills插件:前端开发者的实战指南
让Claude Code拥有专属技能,像安装VS Code插件一样简单
开篇:为什么我要研究Skills插件?
最近在用Claude Code写代码时,发现每次遇到相似的任务都要重新解释一遍需求,比如"帮我写一个符合团队规范的React组件"、“按照我们的commit规范提交代码”。作为一个做了10年前端的开发者,我第一反应是:这不就像每次都要手写工具函数吗?能不能把这些常用的指令封装起来?
翻了下文档,发现Claude Code确实有这个能力——Skills插件系统。花了两天时间研究+踩坑,终于搞明白了怎么玩,这篇文章就分享一下我的实战经验。
这篇文章能帮你什么?
- 理解Skills是什么,为什么要用它
- 手把手教你创建第一个Skill
- 分享我踩过的坑和解决方案
- 提供可以直接用的实战案例
如果你也在用Claude Code,或者想提升AI辅助开发的效率,这篇文章应该对你有帮助。
背景知识:Skills到底是什么?
用前端的话说
如果你熟悉VS Code插件或者npm包,Skills就是给Claude Code安装"插件"的方式。不同的是:
| 概念 | VS Code插件 | Claude Code Skills |
|---|---|---|
| 本质 | 可执行代码(JS/TS) | 文本指令(Markdown) |
| 安装 | marketplace下载 | 创建.md文件 |
| 作用 | 扩展IDE功能 | 扩展AI能力 |
| 调用 | 命令面板或快捷键 | /skill-name或自动触发 |
简单说,Skills = 给Claude的专业知识包 + 工作流模板。
两种用法
Claude官方把Skills分成两类:
1. 参考内容(Reference Content)
- 就像给Claude一本"团队开发手册"
- 例如:API调用规范、代码风格指南
- Claude在写代码时会自动参考这些规则
2. 任务内容(Task Content)
- 就像定义一个"自动化脚本"
- 例如:部署流程、代码迁移步骤
- 用户手动触发,Claude按步骤执行
实战:创建你的第一个Skill
场景:代码解释Skill
我经常需要向团队新人解释代码,每次都要说"画个图"、“举个例子”。不如写个Skill让Claude自动这么做。
第一步:创建目录
# 在用户目录下创建(所有项目通用)
mkdir -p ~/.claude/skills/explain-code
# 或在项目目录下创建(仅当前项目)
mkdir -p .claude/skills/explain-code
我的经验:新手建议先在~/.claude/skills/下创建,这样所有项目都能用。等熟悉了再根据项目创建专用Skills。
第二步:创建SKILL.md文件
在~/.claude/skills/explain-code/目录下创建SKILL.md:
---
name: explain-code
description: 使用视觉图表和类比来解释代码。当解释代码工作原理、教授代码库或用户问"这是如何工作的?"时使用
---
# 代码解释专家
当解释代码时,始终遵循以下结构:
## 1. 类比先行
用日常生活中的事物比喻代码逻辑。例如:
- Promise就像餐厅的取餐号码牌
- React Hooks就像React组件的"记忆系统"
## 2. 绘制流程图
用ASCII艺术展示代码执行流程:
```
用户点击按钮
↓
触发handleClick
↓
发送API请求 ──→ 等待响应
↓ ↓
更新loading 收到数据
↓ ↓
└──────→ 更新UI
```
## 3. 逐步讲解
把代码拆解成小步骤,一行一行解释发生了什么。
## 4. 指出常见陷阱
分享这种代码模式常见的错误和注意事项。
---
**语气要求**:像和朋友聊天一样,避免过度学术化的表达。
关键点解释:
- 头部元数据(YAML Frontmatter)
---
name: explain-code # Skill的唯一标识符,用于调用
description: ... # 告诉Claude什么时候应该用这个Skill
---
- 正文内容
- 用Markdown写给Claude的"工作指南"
- 可以包含示例、模板、规则
第三步:测试Skill
# 方法1:直接调用
claude
/explain-code src/components/LoginForm.tsx
# 方法2:让Claude自动调用
# 在对话中问:"这段代码是怎么工作的?"
# Claude会自动匹配description,应用这个Skill
我的测试结果:
第一次测试时,我发现Claude没有自动触发Skill。后来发现是description写得太模糊了。改成更具体的触发词(“解释代码工作原理”、“这是如何工作的”)后就正常了。
完整示例:创建一个实用的PR总结Skill
这是我在实际工作中常用的一个Skill,用来自动总结GitHub PR的变更:
~/.claude/skills/pr-summary/SKILL.md:
---
name: pr-summary
description: 总结GitHub Pull Request的变更内容,生成清晰的PR描述
disable-model-invocation: true
allowed-tools: Bash(gh *), Read, Grep
argument-hint: [pr-number]
---
# PR总结生成器
总结PR #$ARGUMENTS 的变更内容。
## 步骤
### 1. 获取PR信息
使用GitHub CLI获取数据:
```bash
# 获取PR详情
gh pr view $ARGUMENTS
# 获取文件变更
gh pr diff $ARGUMENTS
# 获取变更的文件列表
gh pr diff $ARGUMENTS --name-only
```
### 2. 分析变更
按以下维度分类:
- **新增功能**:新增的特性或能力
- **Bug修复**:修复的问题
- **重构**:代码结构改进
- **文档**:文档更新
- **测试**:测试相关变更
### 3. 生成总结
输出格式:
```markdown
## 📋 变更总结
### ✨ 新增功能
- [ 具体描述 ]
### 🐛 Bug修复
- [ 具体描述 ]
### 🔧 其他改进
- [ 具体描述 ]
## 📊 影响范围
- 修改文件数:X
- 新增代码:+X 行
- 删除代码:-X 行
## ✅ 测试计划
- [ ] [ 测试项1 ]
- [ ] [ 测试项2 ]
```
---
**注意**:执行前请确保已安装GitHub CLI (`gh`) 并完成认证。
使用方法:
# 总结PR #123
/pr-summary 123
配置字段说明:
disable-model-invocation: true # 禁止Claude自动调用(防止误触发)
allowed-tools: Bash(gh *), Read, Grep # 只允许使用这些工具(安全限制)
argument-hint: [pr-number] # 提示用户需要传入PR编号
高级技巧:让Skills更强大
1. 使用参数
Skills支持动态参数,类似函数调用:
---
name: migrate-component
description: 将组件从一个框架迁移到另一个
argument-hint: [component-name] [from] [to]
---
将 **$0** 组件从 **$1** 迁移到 **$2**。
保持以下内容:
- 所有现有功能
- 单元测试
- Props接口
迁移步骤:
1. 读取 $0 组件源码
2. 分析依赖和状态管理
3. 用 $2 语法重写
4. 迁移测试用例
5. 验证功能一致性
调用示例:
/migrate-component SearchBar React Vue
参数访问方式:
$ARGUMENTS- 所有参数(空格分隔的字符串)$0,$1,$2- 位置参数(推荐)$ARGUMENTS[0],$ARGUMENTS[1]- 数组访问方式
2. 动态上下文注入
有时候需要在Skill中获取实时数据,可以用!`command`语法:
---
name: team-stats
description: 展示团队的代码统计
---
# 团队代码统计
## 当前状态
- **Open PRs**: !`gh pr list --json number | jq length`
- **最老的PR**: !`gh pr list --json createdAt,number --jq 'sort_by(.createdAt) | .[0] | .number'`
- **今日提交数**: !`git log --since="today" --oneline | wc -l`
基于以上数据,分析团队工作状态...
工作原理:Claude在发送Skill内容前,先执行!`command`中的命令,将输出替换到文本中。
我的实战经验:这个特性超级好用,但要注意命令执行时间。如果命令很慢(比如复杂的git查询),会阻塞Skill加载。
3. 在隔离环境中运行Skill
有些Skill需要大量探索(比如代码库分析),会占用主对话的context。可以让Skill在独立的subagent中运行:
---
name: deep-research
description: 深入研究某个技术主题
context: fork # 在独立的context中运行
agent: Explore # 使用Explore类型的agent
---
深入研究 **$ARGUMENTS** 主题:
1. 使用Glob查找所有相关文件
2. 用Grep搜索关键实现
3. 读取核心文件并分析
4. 总结架构设计和最佳实践
好处:
- 主对话不会被大量文件内容污染
- Explore agent针对搜索优化,速度更快
- 完成后只返回总结结果
4. 限制工具访问(安全最佳实践)
如果Skill只需要读权限,不要给它写权限:
---
name: safe-analyzer
description: 安全地分析代码库
allowed-tools: Read, Grep, Glob
---
分析代码质量,但**不做任何修改**。
检查项:
- 代码重复度
- 函数复杂度
- 潜在的性能问题
安全考虑:
- 只给必要的工具权限
- 危险操作(部署、删除)使用
disable-model-invocation: true - 涉及文件写入的Skill要谨慎测试
踩坑分享:我遇到的问题和解决方案
坑1:Skill不触发
问题:创建了Skill,但Claude从来不用。
原因:description写得太模糊或太宽泛。
解决方案:
# ❌ 不好的description
description: 帮助代码分析
# ✅ 好的description
description: 分析React组件性能,当用户问"为什么组件很慢"或"如何优化性能"时使用
技巧:description中包含触发关键词,比如"当用户问XX"、“解释XX原理”。
坑2:Skill触发太频繁
问题:创建了一个部署Skill,结果每次提到"发布"就要执行部署。
原因:description太宽泛,且没有禁止自动调用。
解决方案:
---
name: deploy
description: 部署到生产环境
disable-model-invocation: true # 禁止Claude自动调用
---
这样只能手动调用/deploy,不会误触发。
坑3:路径问题
问题:在Skill中引用脚本文件,找不到路径。
错误代码:
运行脚本:
```bash
./scripts/helper.sh # ❌ 相对路径不可靠
```
正确做法:
运行脚本:
```bash
python ~/.claude/skills/my-skill/scripts/helper.py # ✅ 绝对路径
```
我的经验:Skill内的脚本都放在Skill目录下,用绝对路径~/.claude/skills/[skill-name]/引用。
坑4:权限问题
问题:Skill需要运行npm install,但被权限拦截。
解决方案:
- 在
.claude/settings.json中配置Bash权限:
{
"permissions": {
"bash": {
"allow": [
"npm *",
"git *"
]
}
}
}
- 或者在Skill中明确声明:
---
allowed-tools: Bash(npm *), Bash(git *), Read, Write
---
坑5:参数传递问题
问题:调用/migrate-component SearchBar React Vue,但$1拿到的是SearchBar React。
原因:参数用空格分隔,如果参数本身包含空格会被拆分。
解决方案:
# ❌ 如果参数有空格会出错
/migrate-component "My Component" React Vue
# ✅ 如果可能有空格,在Skill中用引号处理
# 或者重新设计参数格式,用逗号分隔
/migrate-component MyComponent,React,Vue
然后在Skill中解析:
# 分割参数
# 将 $ARGUMENTS 按逗号分割:component=$0前面, from=$0中间, to=$0后面
实战案例:我常用的几个Skills
1. React组件生成器
---
name: create-react-component
description: 创建符合团队规范的React组件
disable-model-invocation: true
argument-hint: [component-name]
---
创建 **$0** 组件,遵循以下规范:
## 文件结构
```
src/components/$0/
├── index.tsx # 组件主文件
├── $0.module.css # CSS Modules样式
├── $0.test.tsx # 单元测试
└── types.ts # TypeScript类型定义
```
## 代码模板
### index.tsx
```typescript
import React from 'react';
import styles from './$0.module.css';
import { $0Props } from './types';
export const $0: React.FC<$0Props> = (props) => {
return (
<div className={styles.container}>
{/* 组件内容 */}
</div>
);
};
```
### types.ts
```typescript
export interface $0Props {
// TODO: 定义props类型
}
```
### $0.test.tsx
```typescript
import { render, screen } from '@testing-library/react';
import { $0 } from './index';
describe('$0', () => {
it('should render correctly', () => {
render(<$0 />);
// TODO: 添加测试断言
});
});
```
---
创建文件后运行测试确保无报错。
使用:
/create-react-component UserProfile
2. Git提交规范Skill
---
name: commit-with-convention
description: 按照Conventional Commits规范提交代码
disable-model-invocation: true
---
# Git提交规范助手
按照团队的Conventional Commits规范创建commit。
## 提交类型
- **feat**: 新功能
- **fix**: Bug修复
- **docs**: 文档更新
- **style**: 代码格式(不影响功能)
- **refactor**: 重构
- **test**: 测试相关
- **chore**: 构建/工具变动
## 提交步骤
1. 查看当前变更:
```bash
git status
git diff
```
2. 分析变更内容,选择合适的类型
3. 生成commit message(格式:`type(scope): description`)
示例:
```
feat(auth): add password reset functionality
fix(api): handle null response in user endpoint
docs(readme): update installation instructions
```
4. 执行提交:
```bash
git add .
git commit -m "[生成的message]"
```
5. 询问用户是否需要推送到远程。
使用:
/commit-with-convention
3. 代码库可视化Skill(完整版)
这个Skill生成项目结构的交互式HTML树形视图:
目录结构:
~/.claude/skills/codebase-visualizer/
├── SKILL.md
└── scripts/
└── visualize.py
SKILL.md:
---
name: codebase-visualizer
description: 生成项目结构的交互式可视化图表。当需要理解项目结构或识别大文件时使用。
allowed-tools: Bash(python *)
---
# 代码库可视化器
生成展示项目文件结构的交互式HTML树形视图。
## 使用方法
从项目根目录运行:
```bash
python ~/.claude/skills/codebase-visualizer/scripts/visualize.py .
```
这会在当前目录生成 `codebase-map.html` 并自动在浏览器打开。
## 功能特性
- ✅ 可折叠的目录树
- ✅ 文件大小显示
- ✅ 按文件类型颜色编码
- ✅ 目录总大小统计
- ✅ 自动忽略 node_modules, .git 等常见目录
scripts/visualize.py:
#!/usr/bin/env python3
"""生成代码库的交互式树形可视化。"""
import json
import sys
import webbrowser
from pathlib import Path
from collections import Counter
# 忽略的目录
IGNORE = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build'}
def scan(path: Path, stats: dict) -> dict:
"""扫描目录树并收集统计信息。"""
result = {"name": path.name, "children": [], "size": 0}
try:
for item in sorted(path.iterdir()):
# 跳过隐藏文件和忽略目录
if item.name in IGNORE or item.name.startswith('.'):
continue
if item.is_file():
size = item.stat().st_size
ext = item.suffix.lower() or '(no ext)'
result["children"].append({
"name": item.name,
"size": size,
"ext": ext
})
result["size"] += size
stats["files"] += 1
stats["extensions"][ext] += 1
stats["ext_sizes"][ext] += size
elif item.is_dir():
stats["dirs"] += 1
child = scan(item, stats)
if child["children"]: # 只包含非空目录
result["children"].append(child)
result["size"] += child["size"]
except PermissionError:
pass
return result
def format_size(size: int) -> str:
"""格式化文件大小。"""
for unit in ['B', 'KB', 'MB', 'GB']:
if size < 1024:
return f"{size:.1f} {unit}"
size /= 1024
return f"{size:.1f} TB"
def generate_html(data: dict, stats: dict, output: Path) -> None:
"""生成HTML可视化文件。"""
# 扩展名统计(按大小排序)
ext_stats = sorted(
((ext, count, stats["ext_sizes"][ext]) for ext, count in stats["extensions"].items()),
key=lambda x: x[2],
reverse=True
)
ext_table = "\n".join(
f"<tr><td>{ext}</td><td>{count}</td><td>{format_size(size)}</td></tr>"
for ext, count, size in ext_stats[:10] # Top 10
)
html = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>代码库结构 - {data['name']}</title>
<style>
body {{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 20px;
background: #f5f5f5;
}}
h1 {{
color: #333;
}}
.stats {{
background: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}}
.stats table {{
border-collapse: collapse;
width: 100%;
}}
.stats th, .stats td {{
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}}
.tree {{
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}}
.tree ul {{
list-style: none;
padding-left: 20px;
}}
.tree li {{
margin: 5px 0;
}}
.folder {{
cursor: pointer;
color: #2196F3;
font-weight: bold;
}}
.folder:hover {{
text-decoration: underline;
}}
.file {{
color: #666;
}}
.size {{
color: #999;
font-size: 0.9em;
margin-left: 10px;
}}
.ext-js {{ color: #f1e05a; }}
.ext-ts {{ color: #2b7489; }}
.ext-py {{ color: #3572A5; }}
.ext-css {{ color: #563d7c; }}
.ext-html {{ color: #e34c26; }}
.ext-json {{ color: #292929; }}
.collapsed > ul {{
display: none;
}}
.arrow {{
display: inline-block;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #666;
margin-right: 5px;
}}
.collapsed .arrow {{
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid #666;
border-right: 0;
}}
</style>
</head>
<body>
<h1>📁 代码库结构可视化</h1>
<div class="stats">
<h2>📊 统计信息</h2>
<p>
<strong>总文件数:</strong>{stats['files']} |
<strong>总目录数:</strong>{stats['dirs']} |
<strong>总大小:</strong>{format_size(data['size'])}
</p>
<h3>文件类型分布(Top 10)</h3>
<table>
<tr><th>扩展名</th><th>文件数</th><th>总大小</th></tr>
{ext_table}
</table>
</div>
<div class="tree">
<h2>🌲 目录树</h2>
<div id="tree-root"></div>
</div>
<script>
const data = {json.dumps(data, ensure_ascii=False)};
function renderTree(node, parent) {{
const li = document.createElement('li');
if (node.children && node.children.some(c => c.children)) {{
// 目录
li.innerHTML = `
<span class="folder">
<span class="arrow"></span>
📁 ${{node.name}}
<span class="size">(${{formatSize(node.size)}})</span>
</span>
`;
li.querySelector('.folder').onclick = function(e) {{
e.stopPropagation();
li.classList.toggle('collapsed');
}};
const ul = document.createElement('ul');
node.children.forEach(child => renderTree(child, ul));
li.appendChild(ul);
}} else if (node.children) {{
// 只包含文件的目录
li.innerHTML = `
<span class="folder">
<span class="arrow"></span>
📁 ${{node.name}}
<span class="size">(${{formatSize(node.size)}})</span>
</span>
`;
li.querySelector('.folder').onclick = function(e) {{
e.stopPropagation();
li.classList.toggle('collapsed');
}};
const ul = document.createElement('ul');
node.children.forEach(child => {{
const fileLi = document.createElement('li');
const extClass = child.ext ? `ext-${{child.ext.slice(1)}}` : '';
fileLi.innerHTML = `
<span class="file ${{extClass}}">
📄 ${{child.name}}
<span class="size">(${{formatSize(child.size)}})</span>
</span>
`;
ul.appendChild(fileLi);
}});
li.appendChild(ul);
}} else {{
// 文件
const extClass = node.ext ? `ext-${{node.ext.slice(1)}}` : '';
li.innerHTML = `
<span class="file ${{extClass}}">
📄 ${{node.name}}
<span class="size">(${{formatSize(node.size)}})</span>
</span>
`;
}}
parent.appendChild(li);
}}
function formatSize(size) {{
const units = ['B', 'KB', 'MB', 'GB'];
let i = 0;
while (size >= 1024 && i < units.length - 1) {{
size /= 1024;
i++;
}}
return `${{size.toFixed(1)}} ${{units[i]}}`;
}}
const root = document.getElementById('tree-root');
const ul = document.createElement('ul');
renderTree(data, ul);
root.appendChild(ul);
</script>
</body>
</html>"""
output.write_text(html, encoding='utf-8')
if __name__ == '__main__':
target = Path(sys.argv[1] if len(sys.argv) > 1 else '.').resolve()
stats = {
"files": 0,
"dirs": 0,
"extensions": Counter(),
"ext_sizes": Counter()
}
print(f'扫描 {target}...')
data = scan(target, stats)
out = Path('codebase-map.html')
generate_html(data, stats, out)
print(f'✅ 生成了 {out.absolute()}')
print(f'📊 统计: {stats["files"]} 文件, {stats["dirs"]} 目录')
# 在浏览器中打开
webbrowser.open(f'file://{out.absolute()}')
使用示例:
# 在项目根目录
/codebase-visualizer
# 会自动打开浏览器显示交互式目录树
与前端开发的结合点
作为前端开发者,Skills可以帮我们做很多事情:
1. 组件开发模板化
创建Skills来生成常用组件结构(React/Vue/Angular),统一团队规范。
2. API对接规范化
---
name: create-api-client
description: 创建类型安全的API客户端代码
---
为 $ARGUMENTS API 端点创建客户端代码:
1. 定义TypeScript类型(基于API响应)
2. 创建axios包装函数
3. 添加错误处理
4. 提供使用示例
代码风格:
- 使用async/await
- 统一错误处理(toast提示)
- 请求/响应拦截器
3. 性能优化检查
---
name: check-bundle-size
description: 检查打包体积并提供优化建议
---
分析当前项目的打包体积:
1. 运行 `npm run build`
2. 分析 bundle 大小
3. 找出最大的依赖包
4. 提供优化建议:
- 可以Tree-shaking的包
- 可以动态导入的组件
- 可以替换为更小体积的库
4. 与英博云平台结合
如果你在英博云平台部署模型,可以创建部署辅助Skill:
---
name: deploy-to-ebcloud
description: 部署应用到英博云平台
disable-model-invocation: true
---
部署到英博云平台的步骤:
1. 检查环境变量配置
2. 构建Docker镜像
3. 推送到英博云镜像仓库
4. 更新服务配置
5. 健康检查
具体命令:
```bash
# 构建
docker build -t my-app:latest .
# 推送(替换为你的英博云仓库地址)
docker tag my-app:latest registry.ebcloud.com/your-repo/my-app:latest
docker push registry.ebcloud.com/your-repo/my-app:latest
# 部署(使用英博云CLI或API)
# ...
```
检查部署状态并报告结果。
总结:我的核心收获
通过这两天的研究和实践,我总结了几个关键点:
✅ Skills的核心价值
- 提升效率:把重复的指令封装成可复用的模块
- 统一规范:团队共享Skills,确保代码风格一致
- 知识沉淀:把最佳实践固化成Skills,新人直接使用
- 安全可控:通过
allowed-tools限制权限,避免误操作
✅ 创建Skills的原则
- 从实际需求出发:不要为了写Skill而写,解决真实痛点
- 保持简单:一个Skill做好一件事
- 文档清晰:写好description和使用说明
- 充分测试:特别是涉及文件操作的Skill
✅ 我的使用建议
新手推荐路径:
- 先用几个简单的Skill(代码解释、提交规范)
- 观察Claude如何自动触发Skills
- 根据自己的工作流创建定制Skills
- 团队内分享和迭代
进阶建议:
- 探索动态上下文注入(
!command) - 尝试subagent运行模式(
context: fork) - 研究与MCP(Model Context Protocol)的结合
✅ 后续学习计划
- 深入研究Agent Skills标准:Claude Code遵循的agentskills.io开放标准
- 探索更多集成:与CI/CD、监控系统的结合
- 分享实践:把团队常用的Skills开源出来
参考资源
- Claude Code官方文档:关于Skills的详细说明
- Agent Skills开放标准:https://agentskills.io
- 我的Skills仓库(计划开源):包含本文所有示例代码
希望这篇文章能帮到你!如果你也在探索Claude Code或AI辅助开发,欢迎交流踩坑经验。记住,最好的Skill是解决你实际问题的那个,不要过度设计,从简单开始,逐步迭代。
祝你用Claude Code写出更高效的代码! 🚀
更多推荐




所有评论(0)