首页 › tutorials › 造脚手架Skill一句话秒出API四件套

造脚手架Skill一句话秒出API四件套

概述

本教程带你从零造一个名为 endpoint-scaffold 的 Claude Code Skill:输入一句 POST /users 创建用户,它自动产出路由、处理器、单元测试、接口文档四个文件——也就是后端开发最重复的"四件套"。在这个过程中,你会真正吃透 Skills 的三个核心机制:渐进式披露(薄入口 + 引用文件)、命名参数($method、$path、$desc)、动态上下文注入(!命令``)。适合已经用过 Claude Code、想从"复制粘贴提示词"升级到"封装可复用工程资产"的开发者。

前置条件

核心概念速记:一个 Skill 就是一个目录,入口是 SKILL.md。它有两种 YAML 块之外的内容——frontmatter(告诉 Claude"何时用、能用什么工具")和正文(告诉 Claude"怎么做")。与 CLAUDE.md 最大的区别是:Skill 正文只在被调用时才加载,长期参考材料几乎零成本。

步骤一:先想清楚 Skill 的"骨架",再动笔

很多人写 Skill 的第一步是打开 SKILL.md 开始堆文字,这是反模式。先在纸上画清楚三件事:

  1. 触发时机:用户说什么话、在什么文件上工作时,这个 Skill 该出场?
  2. 输入参数:调用时需要喂几个值?分别叫什么?
  3. 产出物:会生成或修改哪些文件?哪些是固定模板,哪些需要 Claude 按上下文填充?

对本 Skill 而言,三个答案很清晰:

这一步决定了后续所有设计。把第三项里"固定不变的部分"抽成模板文件,"需要动态填充的部分"留给参数——这就是渐进式披露的雏形。

步骤二:搭目录结构

Skills 存放位置决定作用域。个人级放 ~/.claude/skills/,项目级放 .claude/skills/。脚手架类工具强绑定项目,建议放项目级,跟着代码一起进版本库、被团队共享。

mkdir -p .claude/skills/endpoint-scaffold/templates
mkdir -p .claude/skills/endpoint-scaffold/examples

最终结构:

.claude/skills/endpoint-scaffold/
├── SKILL.md                 # 薄入口:导航 + 流程
├── templates/
│   ├── route.tpl            # 路由声明模板
│   ├── handler.tpl          # 处理器函数模板
│   ├── test.tpl             # 单测模板
│   └── doc.tpl              # 接口文档模板
└── examples/
    └── one-liner-to-files.md # 一句话→四文件的对照样例

预期结果:Claude Code 监视这些目录,文件改动在当前会话内即时生效,无需重启。若新建的是会话启动时并不存在的顶层目录,才需要重启一次。

常见问题:把模板塞进 SKILL.md 而不是单独文件——结果正文膨胀到几百行,每次调用都把模板原文灌进上下文,token 成本飙升。记住官方建议:SKILL.md 控制在 500 行以内,详情挪到引用文件。

步骤三:写模板文件(先写"死"的部分)

模板是"骨架",用占位符标记"活肉"。占位符命名要和参数一一对应,这里统一用 {{METHOD}}、{{PATH}}、{{DESC}}、{{NAME}}(由路径派生)。注意:{{...}} 是给 Claude 看的"提示性占位",真正的参数替换靠步骤四的 $method 机制。

templates/route.tpl:

// Auto-scaffolded by endpoint-scaffold skill
import { {{NAME}}Handler } from '../handlers/{{NAME}}.js';

router.{{METHOD_LOWER}}('{{PATH}}', {{NAME}}Handler);

templates/handler.tpl:

// {{DESC}}
export async function {{NAME}}Handler(req, res) {
  try {
    // TODO: implement business logic for {{METHOD}} {{PATH}}
    res.status(501).json({ error: 'not implemented' });
  } catch (err) {
    res.status(500).json({ error: String(err) });
  }
}

templates/test.tpl:

import { describe, it, expect } from 'vitest';
// import { {{NAME}}Handler } from '../handlers/{{NAME}}';

describe('{{METHOD}} {{PATH}}', () => {
  it('should {{DESC}}', async () => {
    // TODO: wire up request mock and assert response
    expect(true).toBe(true);
  });
});

templates/doc.tpl:

# {{METHOD}} {{PATH}}

{{DESC}}

## Request
TODO

## Response
TODO

预期结果:四个 .tpl 文件躺在 templates/,它们本身不会自动加载进上下文——这正是渐进式披露的好处。只有 SKILL.md 在被调用时进入对话,模板文件是 Claude "按需读取"的资料。

步骤四:写 SKILL.md——把三股力量拧到一起

这是全教程的核心。一份 SKILL.md 同时调度命名参数、动态注入、模板引用三种能力。

.claude/skills/endpoint-scaffold/SKILL.md:

---
name: endpoint-scaffold
description: Scaffold a complete API endpoint (route + handler + unit test + API doc) from a one-line spec. Use when the user asks to add/create a new endpoint, generate CRUD scaffolding, or build out a new route with tests and docs.
when_to_use: triggers on phrases like "加个接口", "新建 endpoint", "生成 CRUD", "scaffold a route", "add an API"
argument-hint: [METHOD path description...]
arguments: [method, path, desc]
allowed-tools: Read, Write, Edit, Glob, Bash(ls *), Bash(test *)
---

## Current request
Scaffold the endpoint: **$method $path** — $desc

## Project context (auto-detected)
- Stack hint: !`cat package.json 2>/dev/null | grep -E '"(express|fastify|koa|next|vitest|jest)"' || echo "no package.json or unknown stack"`
- Existing routes: !`ls src/routes 2>/dev/null || ls routes 2>/dev/null || echo "no routes dir yet"`

## Your task
Produce the "四件套" (four files) for the endpoint above.

1. Derive `{{NAME}}` from `$path`: take the last non-param segment, drop a trailing `/:id`, convert to camelCase (e.g. `/api/users/:id` → `users`; `/api/orders/:id/items` → `orderItems`).
2. Lowercase `$method` for the router call (`{{METHOD_LOWER}}`).
3. Read each template file and fill the placeholders, then write the result:
   - templates/route.tpl   → src/routes/{{NAME}}.js
   - templates/handler.tpl → src/handlers/{{NAME}}.js
   - templates/test.tpl    → tests/{{NAME}}.test.js
   - templates/doc.tpl     → docs/{{NAME}}.md
4. If `src/routes/index.js` (or equivalent registry) exists, append a registration import for the new route.
5. Print a one-line summary: which files were created and a suggested next command.

Keep generated code minimal and idiomatic to the detected stack. When the stack is unknown, default to plain Express-style handlers and note the assumption in the doc file.

## Resources
- For one worked example of input→output, read [examples/one-liner-to-files.md](examples/one-liner-to-files.md)
- Templates live in [templates/](templates/) — read them on demand, do not assume their contents.

逐行拆解这股力量的来源:

命名参数:frontmatter 的 arguments: [method, path, desc] 把 /endpoint-scaffold POST /users 创建用户 拆成三段,正文里 $method→POST、$path→/users、$desc→创建用户。多词描述要用引号包裹,/endpoint-scaffold POST /users "create a guest user" 才能把第三段当整体。

动态上下文注入:!cat package.json ...` 在正文送达 Claude **之前**执行,命令输出原地替换占位符。Claude 看到的不是命令本身,而是真实的项目栈与已有路由——这正是脚手架能"自适应"的原因。多行命令用 ``! 围栏。

模板引用:结尾的"Resources"列出支持文件,并写明何时该读。Claude 不会预读 templates/,只在执行到第 3 步时按需 Read,把占位符成本降到最低。

allowed-tools:预授权 Read/Write/Edit/Glob 与受限的 Bash(ls *)、Bash(test *),省去逐次确认;但不放开任意 Bash,避免 Skill 自我授权执行危险命令。项目级 Skill 的 allowed-tools 在你接受 workspace trust 对话框后才生效——这是反恶意 Skill 的护栏。

预期结果:保存后无需重启,输入 /endpoint-scaffold 应能在补全菜单看到该 Skill,argument-hint 提示 [METHOD path description...]。

常见问题与解决:

现象 原因 解决
菜单里看不到 Skill 目录名拼错或 SKILL.md 不在根 确认路径为 .claude/skills/endpoint-scaffold/SKILL.md
$desc 只取到第一个词 未加引号 多词参数整体加引号
Skill 触发但栈识别错误 ! 命令输出为空 手动检查探测命令能否在项目根跑通
Skill 不被自动触发 description 不含触发短语 把 when_to_use 写满真实触发句

步骤五:补一个对照样例,让 Claude "照着抄"

examples/one-liner-to-files.md 是渐进式披露的另一关键:给 Claude 一个明确的输入→输出映射,减少自由发挥导致的跑偏。

# Input
/endpoint-scaffold POST /api/orders 创建订单

# Derived
NAME = orders
METHOD_LOWER = post

# Output files
- src/routes/orders.js
- src/handlers/orders.js
- tests/orders.test.js
- docs/orders.md

# Sample handler (filled)
export async function ordersHandler(req, res) {
  try {
    res.status(501).json({ error: 'not implemented' });
  } catch (err) {
    res.status(500).json({ error: String(err) });
  }
}

有了这份样例,Claude 遇到边界情况(如路径带 /:id)会更倾向遵循既有派生规则,而非自己发明。

步骤六:跑通第一刀

在项目根目录启动 Claude Code:

claude

两种调用方式都试一次:

/endpoint-scaffold POST /users 注册新用户

或者用自然语言触发(验证 description 是否生效):

帮我加个接口:GET /products 列出所有商品,要带测试和文档

预期结果:Claude 先读取模板,按派生规则填充占位符,写出四个文件,并在 src/routes 注册新路由,最后给出一行总结。整个过程应可逆——若不满意,删掉生成的文件即可。

验证生成的测试能跑:

npx vitest run tests/users.test.js

步骤七:用对照基线迭代

Skill 能触发,不等于它做对了。官方推荐的检验法是带基线对照:收集 3–5 条真实请求,分别在"启用 Skill"和"禁用 Skill"的新会话里跑,比较产物。为什么要新会话?因为编写 Skill 时残留的上下文会掩盖正文写得不够好的缺陷。

若触发准确率不稳,优先改 description 与 when_to_use;若触发准但产物差,改正文步骤或补 examples/。更系统的方式是装官方插件:

/plugin install skill-creator@claude-plugins-official

它会为每个测试用例在隔离子代理里跑、记录 token 与耗时、生成 benchmark.json,支持两个 Skill 版本的盲测 A/B——改动是否真的是改进,用数据说话。

实战案例:从 1 个接口到 N 个接口

假设要给一个电商后端快速铺底。按下面顺序喂同一句式:

/endpoint-scaffold POST   /api/orders         创建订单
/endpoint-scaffold GET    /api/orders/:id     查询订单详情
/endpoint-scaffold PATCH  /api/orders/:id     更新订单状态
/endpoint-scaffold DELETE /api/orders/:id     取消订单
/endpoint-scaffold GET    /api/products       商品列表

每次 !ls src/routes` 注入的"已有路由"清单会随轮次增长,Claude 能据此决定是否需要新建注册条目还是复用现有orders` 文件。一轮下来你拿到 20 个文件(5 组四件套),每个 handler 都是可编译的 501 占位实现,测试是可运行的红绿骨架。接下来把精力集中到业务逻辑即可——这正是脚手架类 Skill 的价值:把"从零搭壳"的时间压缩到接近零。

进阶可叠加的能力:在正文里加 ultrathink 触发更深推理,处理复杂派生;或加 context: fork 让 Skill 在隔离子代理里执行,避免污染主会话上下文——后者适合那些需要大段探索的生成任务。但要记住官方警告:context: fork 只适合"有明确任务的 Skill",纯参考类 Skill 放进子代理会因没有可执行任务而无功而返。

工作流程全景

flowchart TD
    A["用户输入<br/>/endpoint-scaffold POST /users 注册新用户"] --> B{"Claude Code<br/>匹配 description/when_to_use"}
    B -->|命中| C["frontmatter 解析<br/>arguments: method path desc"]
    C --> D["动态注入预执行<br/>!`cat package.json` → 真实栈<br/>!`ls src/routes` → 已有路由"]
    D --> E["SKILL.md 正文进入会话<br/>模板文件尚未加载"]
    E --> F["Claude 执行步骤1-2<br/>派生 NAME / METHOD_LOWER"]
    F --> G["按需 Read templates/*.tpl<br/>渐进式披露: 只读需要的文件"]
    G --> H["Write 四件套<br/>route/handler/test/doc"]
    H --> I["注册路由 + 输出总结"]
    I --> J["基线对照迭代<br/>skill-creator 跑 benchmark.json"]
    B -->|未命中| K["降级为普通对话<br/>或检查 description 触发短语"]

延伸阅读

训练营适用性评估

参考来源

  1. Extend Claude with skills — Claude Code Docs — 官方权威文档,frontmatter 字段、字符串替换、动态注入、支持文件、子代理执行与 skill-creator 评测机制的完整规范来源
  2. How to Build Claude Code Skills: 5 Examples (2026) — SKILL.md 规范、安全控制与可直接套用的五个实战示例
  3. Create-Skill — Scaffolding Claude Code Skills — Skills 作为可复用提示模块的设计哲学与目录约定
  4. Project Scaffolding Skill for Claude Code — 一个真实的脚手架 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学通信知识星球海报-扫码加入