导语:经过上一篇对《上下文管理》的深度剖析,我们已经知道 Claude Code 是如何精打细算地处理超长对话的。接下来,我们将进入 Claude Code 极具扩展性的核心模块——命令系统与 SKILL 调用。了解这部分内容,你将掌握如何为 AI Agent 编写自定义技能,以及它是如何将自然语言转化为实际行动的。
参考仓库(源码地址):https://github.com/ChinaSiro/claude-code-sourcemap
历史文章:
深度解析 Claude Code 源码(一):整体架构与核心数据流
6.1 命令的三种类型
命令系统的核心定义在 types/command.ts,Command 是一个联合类型:
Command = CommandBase & (PromptCommand | LocalCommand | LocalJSXCommand)
getPromptForCommand() → 注入对话,触发 API
/commit,
/review, Skills
local 本地执行,返回纯文本
load() →
call() →
{type: ‘text’, value}
/compact,
/cost
local-jsx 本地执行,渲染 React UI
load() →
call() → ReactNode, 渲染到终端
/help,
/config,
/mcp
6.2 命令注册机制
commands.ts 是命令注册中心,getCommands() 按以下顺序合并所有来源:
getCommands(cwd) ├── bundledSkills —— 内置 Skills (commit, simplify 等) ├── builtinPluginSkills —— 内置插件提供的 Skills ├── skillDirCommands —— 用户 .claude/skills/ 目录下的自定义 Skills ├── workflowCommands —— Workflow 脚本 ├── pluginCommands —— 第三方插件命令 ├── pluginSkills —— 第三方插件 Skills └── COMMANDS() —— 硬编码的 40+ 内置命令
Feature Flag 门控: 很多命令通过 feature() 做编译期死代码消除:
const voiceCommand = feature(‘VOICE_MODE’) ? require(‘./commands/voice/index.js’).default : null
当 VOICE_MODE 为 false 时,整个 voice 命令代码在构建时被移除。
6.3 命令执行链路
用户输入 /commit fix bug 后的完整路径:
用户输入 “/” ▼ processUserInput() ← processUserInput.ts │ 检测到 “/” 开头 ▼ processSlashCommand() ← processSlashCommand.tsx │ 1. parseSlashCommand() 解析命令名和参数 │ 2. hasCommand() 检查命令是否存在 │ 3. getCommand() 获取命令定义 ▼ getMessagesForSlashCommand() ← 核心分发逻辑 │ ├── case ‘local-jsx’: │ command.load() → mod.call(onDone, context, args) │ 返回 React 组件 → setToolJSX() 渲染到终端 │ 用户操作完成后 onDone() 回调 → resolve Promise │ ├── case ‘local’: │ command.load() → mod.call(args, context) │ 返回 {type: ‘text’, value} 或 {type: ‘compact’} │ 包装成 message 返回 │ └── case ‘prompt’:
├── context === 'fork'? → executeForkedSlashCommand() │ 启动子 Agent 执行,隔离上下文 └── 否则 → getMessagesForPromptSlashCommand() command.getPromptForCommand(args, context) → 生成提示词内容 → 包装成 UserMessage → shouldQuery: true (触发 API 调用)
6.4 三个典型命令精读
1. /help - local-jsx 型 (最简单)
// commands/help/index.ts: const help = { type: ‘local-jsx’, name: ‘help’, description: ‘Show help and available commands’, load: () => import(‘./help.js’), // 懒加载 } satisfies Command
// commands/help/help.tsx: export const call: LocalJSXCommandCall = async (onDone, { options: { commands } }) => { return
模式: load() 懒加载模块 → call() 返回 React 组件 → 渲染到终端 → 用户关闭时 onDone() 回调。
2. /compact - local 型 (中等复杂度)
// commands/compact/index.ts: const compact = { type: ‘local’, name: ‘compact’, isEnabled: () => !isEnvTruthy(process.env.DISABLE_COMPACT), supportsNonInteractive: true, load: () => import(‘./compact.js’), } satisfies Command
call() 返回 {type: ‘compact’, compactionResult},这是特殊返回类型,processSlashCommand 对 compact 结果做特殊处理 (重建消息列表)。
3. /commit - prompt 型 (最有代表性)
// commands/commit.ts: const command = ] }, }
关键设计:
allowedTools: 限制模型只能使用 git 相关命令。executeShellCommandsInPrompt: 提示词中的 `git status` 会被预执行,结果内联。shouldQuery: true: 提示词注入对话,触发一次 Claude API 调用。
6.5 命令系统设计总结
┌────────────────────────────────────────────────────────┐ │ Command 统一接口 │ │ name / description / isEnabled / load │ ├───────────────┬───────────────┬────────────────────────┤ │ local-jsx │ local │ prompt │ │ 渲染 UI │ 返回文本 │ 注入提示词 │ │ 不触发模型 │ 不触发模型 │ 触发模型调用 │ │ /help │ /compact │ /commit │ │ /config │ /cost │ /review │ │ /mcp │ /clear │ 所有 Skills │ └───────────────┴───────────────┴────────────────────────┘
核心设计点:
- 懒加载: 所有命令都用
load: () => import(…)延迟加载,启动时只注册元数据。 - Skills 即命令: Skills 本质上就是
type: ‘prompt’的命令,模型通过 SkillTool 调用。 - 可用性控制: availability 控制“谁能看到”,isEnabled 控制“是否开启”。
- Bridge 安全: 远程控制 (手机/桌面端) 只能执行白名单命令,防止越权操作。
Skills 是 Claude Code 的可扩展能力单元。它复用 Command 接口的 type: ‘prompt’ 分支,但来源更多、调用方更广、配置更灵活。
7.1 Skill 与 Command 的根本区别
/) 用户 (
/) 和模型 (
SkillTool) 都能调用 注册方式: import 进数组 注册方式: 5 种来源并行加载 无 allowedTools 可声明 allowedTools 临时授权工具 无 context: fork 可 fork 到子 Agent 隔离执行
7.2 Skill 的 5 种来源
getCommands() ──┬─ Bundled Skills ──────── 编译期内嵌
│ (skills/bundled/) registerBundledSkill() 注册 │ ├─ Builtin Plugin Skills ─ 内置插件提供 │ (plugins/builtinPlugins.ts) │ ├─ Skill Dir Skills ────── 磁盘 Markdown 文件 │ 三级搜索路径: │ ├── ~/.claude/skills/ (用户级) │ ├── .claude/skills/ (项目级) │ └── managed/.claude/skills/ (企业策略级) │ ├─ Plugin Skills ───────── 第三方插件 │ 通过 plugin install 安装 │ └─ MCP Skills ──────────── MCP 服务器提供 存在 AppState.mcp.commands 中
7.3 Skill 的完整生命周期 (以 /simplify 为例)
- 注册阶段 (启动时):
registerBundledSkill()将其包装成 Command 对象并推入bundledSkills[]数组。 - 用户调用路径 (
/simplify): 解析命令 →getPromptForCommand→ 返回提示词 → 包装成 UserMessage → 触发 Claude API 调用。 - 模型调用路径 (Claude 自主调用):
SkillTool.call→ 检查权限 → 判断 fork 模式 → 生成提示词 → 注入当前对话 → 返回 ToolResult。
7.4 磁盘 Skill: 加载与提示词生成
磁盘 Skill 支持目录格式(推荐):
.claude/skills/my-skill/ ├── SKILL.md ← 主文件 (文件名固定) ├── scripts/ ← 资源文件 └── templates/
SKILL.md Frontmatter 示例:
— description: “做什么的” allowed-tools:
- Bash(git:*) when_to_use: “何时使用” context: fork paths: [“src/*/.ts”] —
Skill 提示词正文
你是一个…
提示词生成核心步骤:
- 拼上 baseDir 前缀:告诉模型 Skill 目录在哪,方便访问资源文件。
- 变量替换:精确匹配
\({CLAUDE_SKILL_DIR}、\){CLAUDE_SESSION_ID}、\(1、\)2 等。 - 执行内嵌 Shell 命令:提示词中的 `command` 会在发给模型前预执行,嵌入实时数据。
7.5 Skill 的三个特殊能力
- allowedTools (临时工具授权):执行期间,模型获得额外工具权限,结束后收回。
- context: ‘fork’ (子 Agent 隔离执行):启动子 Agent 隔离执行,不污染主对话上下文,只返回结果文本。
- paths (条件激活):只有当模型操作了匹配路径的文件时,该 Skill 才被激活。
7.6 动态 Skill 发现
模型对某个文件执行读写操作时,系统会向上遍历目录寻找 .claude/skills/,动态加载新 Skills 并通知缓存清除。
7.7 /skills 命令的展示范围
/skills 是一个 local-jsx 型管理命令,展示用户自己添加的 Skills。内置的 bundled Skills 不在此列表中。
skills
.claude/skills/ 目录 ✅
commands_DEPRECATED
.claude/commands/ ✅
plugin 第三方插件 ✅
mcp MCP 服务器 ✅
bundled 内置 Skills ❌
7.8 Skill 注册字段完整参考 (节选)
- 身份与展示类:
name,description,whenToUse,argumentHint - 模型交互类:
getPromptForCommand,allowedTools,model,effort - 访问控制类:
userInvocable,disableModelInvocation,isEnabled,paths - 执行模式类:
context,agent,shell - 生命周期钩子类:
hooks,files
7.9 Skills 系统架构总图
┌────────────────────────────────────────────────────────────┐ │ getCommands(cwd) │ │ 合并所有来源,过滤 availability + isEnabled, 去重 │ └─┬──────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ 用户输入 “/” │ │ SkillTool │ │ 系统提示词 │ │ │ │ (模型主动调用) │ │(告知模型有哪些Skill) │ ┌─▼────────────┐ │ └─┬────────────────┘ └──────────────────┘ │ │processSlash..│ │ │ │ └─┬────────────┘ │ │ │ │ │ │ │ ┌─▼────────────────────────────────────────┐ │ │ │ getPromptForCommand(args, context) │ │ │ │ │ │ │ │ ├── Bundled: 直接返回硬编码提示词 │ │ │ │ └── 磁盘: 读 SKILL.md -> 变量替换 │ │ │ │ -> 执行 `!command` 内嵌命令 │ │ │ │ │ │ │ │ 提示词注入对话 -> shouldQuery: true │ │ │ │ │ │ │ │ ▼ │ │ │ │ Claude API 调用 │ │ │ │ ▼ │ │ │ │ 模型根据提示词执行任务 │ │ └─┴────────────────────────────────────────┴─┘
以内置 Skill /simplify 为例,从用户按回车到终端渲染结果的完整追踪。
8.1 全景流程图
用户在终端输入 “/simplify” 并按回车 ▼ ① TextInput 组件 (Ink) onSubmit 回调 ▼ ② handlePromptSubmit() ← handlePromptSubmit.ts ▼ ③ executeUserInput() ← handlePromptSubmit.ts (防并发) ▼ ④ processUserInput() ← processUserInput.ts ▼ ⑤ processSlashCommand() ← processSlashCommand.tsx ▼ ⑥ getMessagesForPromptSlashCommand() (生成提示词) ▼ ⑦ onQuery() ← REPL.tsx (构建 systemPrompt) ▼ ⑧ query() → queryLoop() ← query.ts (调用 API) 终端渲染 Claude 的回复
8.2 逐层详解 (核心代码)
⑥ getMessagesForPromptSlashCommand → 提示词生成 (核心)
async function getMessagesForPromptSlashCommand(command, args, context, …) ), // 消息1: 元数据 (用户可见)
createUserMessage({ content: result, isMeta: true }), // 消息2: 提示词正文 (模型可见) createAttachmentMessage({ type: 'command_permissions', allowedTools: ... }), // 权限声明
] return { messages, shouldQuery: true, allowedTools: additionalAllowedTools, command } }
8.3 最终 API 请求结构
调用 API 时,/simplify 生成的消息在请求中大致如下:
,
] }
8.4 关键设计总结
isMeta: true 的 UserMessage,用户隐藏,模型可见
权限临时授权
allowedTools 写入 AppState,仅本 turn 有效
并发保护
QueryGuard 保证同一时刻只有一个
executeUserInput 在运行
可中断 每次执行创建新的
AbortController,用户按 ESC 触发 abort
一句话总结 Skill 的本质:
提示词注入器 —— 把预写好的提示词作为用户消息注入对话,触发一次 Claude API 调用。Skill 本身不执行任何逻辑,所有工作都是模型读到提示词后自主完成的。
结语:至此,我们完整走通了 Skill 的端到端执行链路,揭开了 Claude Code 强大扩展能力的神秘面纱。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/263970.html