Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 17 章:Slash 命令与 Skill 系统 — Agent 的交互扩展

核心问题:一个 CLI Agent 如何在保持核心精简的同时,支持 50+ 内置命令、用户自定义 Skill、第三方插件和 MCP prompt 扩展?

命令系统是 Agent 与用户之间的“操作面板“。用户输入 /commit,Agent 自动生成 git 提交;输入 /model,弹出交互式模型选择器;输入 /review,AI 开始逐段审查 PR。这背后是一套精心设计的三层类型体系、多来源注册机制和可扩展的 Skill 框架。

Claude Code 的命令系统不只是“一组快捷键“ — 它是 Agent 交互能力的完整扩展层,从简单的信息查询到复杂的 AI 驱动工作流,全部统一在同一个调度框架下。本章将逐层拆解这套系统。


17.1 概述:命令系统在 Agent 交互中的角色

Agent 的核心能力是“理解意图 → 调用工具 → 生成响应“,但很多操作不需要 AI 推理 — 查看费用、切换模型、清空上下文,这些应该是即时的、确定性的。命令系统提供了这条“快车道“,让用户绕过 AI 推理直接触发特定行为。

Agent 交互的两条路径
════════════════════════════════════════════════════
                    用户输入
                      │
              ┌───────┴───────┐
              │               │
         普通消息          / 命令
              │               │
              ▼               ▼
        AI 推理循环      命令调度系统
        (Agentic Loop)   (Slash Command)
              │               │
              │          ┌────┴────┐
              │          │    │    │
              │       local  jsx  prompt
              │          │    │    │
              │          │    │    └──→ AI 推理
              │          │    │         (注入 prompt)
              ▼          ▼    ▼
           AI 响应    即时结果/交互 UI

命令系统的架构核心在于两个正交维度的设计:Type(如何执行)和 Source(从哪来)。

小结:命令系统是 Agent 交互模型的补充层 — 它为确定性操作提供直达路径,为 AI 工作流提供标准化的触发入口,为扩展能力提供统一的注册框架。


17.2 命令类型体系:local / local-jsx / prompt

三种命令类型不是任意划分的,而是由执行模型的根本差异驱动的。理解这三者的区别是理解整个命令系统的基础。

类型分发的代码证据

命令分发函数 dB1() (推测名: dispatchCommand) 使用 switch 精确分为 3 个 case:

// cli.js - dB1() (dispatchCommand) 命令分发
switch (j.type) {
  case "local":       // --> synchronous execution, return data
  case "local-jsx":   // --> JSX rendering, return React element
  case "prompt":      // --> Skill path, inject AI prompt
}

没有第四种类型。

三种类型的对比

维度locallocal-jsxprompt
返回值{type, value} 纯数据JSX 元素(React 组件树)prompt 内容注入 AI
生命周期调用 → 返回 → 结束挂载 → 交互 → 回调 → 卸载构造 prompt → AI 推理
用户交互无键盘选择、输入、滚动通过 AI 间接交互
渲染引擎不需要Ink(React for CLI)不需要
典型命令/cost, /vim, /clear/model, /config, /permissions/commit, /review, /init

设计决策:local 和 local-jsx 的分离不是因为功能差异,而是因为执行模型根本不同。local 是同步的纯函数调用,local-jsx 是异步的 React 组件生命周期。这种分离让调度器可以为两者采用完全不同的调用协议。

执行流程对比

/cost 的执行流程(local):
  load().call(args, ctx)
    --> calculate cost data
    --> return { type: "text", value: "Session cost: $0.42\n..." }
    --> display in terminal --> done

/model 的执行流程(local-jsx):
  load().call(onDone, ctx, args)
    --> return <ModelSelector models={...} onSelect={...} />
    --> Ink mounts component --> renders selection list
    --> user presses arrow keys --> component state updates --> re-render
    --> user presses Enter --> onDone(selectedModel)
    --> Ink unmounts component --> done

/commit 的执行流程(prompt):
  getPromptForCommand(args, ctx)
    --> build commit instructions prompt
    --> return [{ type: "text", text: "..." }]
    --> inject into AI conversation (shouldQuery: true)
    --> AI analyzes git status, stages files, creates commit

Type 与 Source 的正交设计

这是理解命令系统的关键。Type 决定命令如何执行,Source 决定命令从哪来,两者是正交的:

维度含义可能取值例子
type命令如何执行local / local-jsx / prompt/cost 是 local,/model 是 local-jsx
source命令从哪来builtin / bundled / plugin / mcp / userSettings/cost 来源 builtin,自定义 Skill 来源 userSettings

一个命令同时拥有 type 和 source 两个属性:

  • /cost:type = local,source = builtin
  • /commit:type = prompt,source = builtin
  • 用户自定义 Skill:type = prompt,source = userSettings
Type × Source 矩阵(已知组合)
═══════════════════════════════════════════
           builtin    bundled    plugin    mcp    userSettings
local        /cost       -         -        -         -
             /clear
             /vim

local-jsx    /model      -         -        -         -
             /config
             /plugin

prompt       /commit    (bundled   (plugin   MCP    user
             /review     skills)   skills)  prompts  SKILL.md
═══════════════════════════════════════════

所有用户自定义的 Skill(包括 plugin、mcp、userSettings 来源)的 type 都是 prompt。这是因为外部扩展只能通过 prompt 注入来驱动 AI 行为 — 它们无法注册原生的 local 或 local-jsx 命令。

小结:三层类型体系 local → local-jsx → prompt 从简到繁覆盖了所有交互场景。Type 和 Source 的正交设计让命令调度器只需关心执行方式,而注册机制独立管理来源。


17.3 命令注册与调度链:Tg_() → gB1() → dB1() → TH9()

命令从用户输入到最终执行,经过一条清晰的调度链。理解这条链路是理解命令系统运行时行为的关键。

调度链总览

用户输入 "/commit fix bug"
         │
         ▼
    ┌──────────┐
    │  Tg_()   │  parseSlashInput -- parse command name + args
    │          │  --> { commandName: "commit", args: "fix bug", isMcp: false }
    └────┬─────┘
         │
         ▼
    ┌──────────┐
    │  gB1()   │  handleSlashCommand -- main entry
    │          │  --> gfH() check existence
    │          │  --> dispatch to dB1()
    └────┬─────┘
         │
         ▼
    ┌──────────┐
    │  dB1()   │  dispatchCommand -- type switch
    │          │  --> case "prompt": TH9()
    └────┬─────┘
         │
         ▼
    ┌──────────┐
    │  TH9()   │  executeSkill -- build prompt, inject into AI
    │          │  --> getPromptForCommand()
    │          │  --> return { messages, shouldQuery: true }
    └──────────┘

第一步:输入解析 — Tg_() (parseSlashInput)

// 13_ui_rendering.js:64436 - Tg_() (parseSlashInput)
function Tg_(H) {
    let _ = H.trim();
    if (!_.startsWith("/")) return null;   // must start with /
    let $ = _.slice(1).split(" ");
    if (!$[0]) return null;

    let K = $[0],       // command name
        O = !1,          // isMcp flag
        T = 1;

    // detect "(MCP)" marker: "/commandName (MCP) args"
    if ($.length > 1 && $[1] === "(MCP)")
        K = K + " (MCP)", O = !0, T = 2;

    let z = $.slice(T).join(" "); // arguments part
    return { commandName: K, args: z, isMcp: O }
}

注意 MCP 命令的特殊语法:/promptName (MCP) args。(MCP) 标记被追加到命令名中,形成如 "deploy (MCP)" 这样的复合名称。

第二步:命令查找 — YF() / gfH() / ohH()

// 16_commands_slash.js:35474 - YF() (findCommand)
function YF(H, _) {
    // H = command name, _ = command list
    return _.find((q) =>
        q.name === H ||          // exact name match
        OK(q) === H ||           // userFacingName match
        q.aliases?.includes(H)   // alias match
    )
}

// gfH() (hasCommand) - boolean check
function gfH(H, _) {
    return YF(H, _) !== void 0
}

// ohH() (getCommandOrThrow) - must exist, throws if not found
function ohH(H, _) {
    let q = YF(H, _);
    if (!q) throw ReferenceError(`Command ${H} not found...`)
    return q
}

三层查找策略:精确名称 → 用户面向名称 → 别名。例如 /settings 能匹配到 name: "config" 的命令,因为 "settings" 在其 aliases 中。

第三步:主入口 — gB1() (handleSlashCommand)

// 13_ui_rendering.js:64692 - gB1() (handleSlashCommand)
async function gB1(H, _, q, $, K, O, T, z, A) {
    // H = raw input, K = toolUseContext, O = setAboveFold, T = uuid

    let f = Tg_(H);  // parse "/command args"
    if (!f) {
        // not a valid command format
        return { messages: [...], shouldQuery: false }
    }

    let { commandName: w, args: Y, isMcp: D } = f;

    // check if command exists
    if (!gfH(w, K.options.commands)) {
        // unknown command handling:
        // 1. check if it's a file path (e.g., /etc/hosts)
        // 2. if looks like a command name (alphanumeric only), report error
        // 3. otherwise treat as normal user input
        let S = false;
        try {
            await f_().stat(`/${w}`);  // check filesystem
            S = true;
        } catch {}

        if (KH9(w) && !S) {
            return { messages: ["Unknown skill: " + w], shouldQuery: false }
        }
        // treat as normal user message
        return { messages: [d_({content: H})], shouldQuery: true }
    }

    // dispatch to type-specific handler
    let { messages, shouldQuery, ... } =
        await dB1(w, Y, O, K, _, q, z, A, T);
    ...
}

设计决策:未知命令的 fallback 逻辑非常巧妙 — 它区分“看起来像命令的字符串“和“恰好以 / 开头的文件路径“。如果 /etc/hosts 在文件系统中存在,就不报错而是当作普通消息发给 AI。这避免了用户讨论 Linux 路径时的误报。

第四步:类型分发 — dB1() (dispatchCommand)

// 13_ui_rendering.js:64830 - dB1() (dispatchCommand)
async function dB1(H, _, q, $, K, O, T, z, A) {
    let f = ohH(H, $.options.commands);  // find command object

    // intercept: skills not user-invocable
    if (f.userInvocable === false) {
        return { messages: ["This skill can only be invoked by Claude..."] }
    }

    switch (f.type) {
        case "local-jsx":
            // Promise wrapper, completed via onDone callback
            return new Promise((w) => {
                let D = (msg, opts) => {
                    w({ messages: [...],
                        shouldQuery: opts?.shouldQuery ?? false })
                };
                f.load().then((j) => j.call(D, $, _))
                 .then((j) => {
                    // return JSX element --> render in terminal
                    q({ jsx: j, shouldHidePromptInput: true })
                 })
            });

        case "local":
            // direct call, handle return value types
            let M = await (await f.load()).call(_, $);
            if (M.type === "skip")
                return { messages: [], shouldQuery: false };
            if (M.type === "compact") {
                // special: /compact returns compaction result
                return { messages: jo(M.compactionResult),
                         shouldQuery: false }
            }
            return { messages: [...], shouldQuery: false,
                     resultText: M.value };

        case "prompt":
            // Skill execution: check fork context
            if (f.context === "fork")
                return await BB1(f, _, $, K, q, z); // fork execution
            return await TH9(f, _, $, K, O, A);     // standard Skill path
    }
}

注意 local 命令的返回值有三种子类型:skip(无输出)、compact(压缩结果)和默认的文本。/compact 命令的特殊返回类型在这里被处理。

第五步:Skill 执行 — TH9() (executeSkill)

// 13_ui_rendering.js:65030 - TH9() (executeSkill)
async function TH9(H, _, q, $ = [], K = [], O) {
    // H = command object, _ = user args, q = toolUseContext

    // 1. get prompt content
    let T = await H.getPromptForCommand(_, q);

    // 2. register Skill hooks if applicable
    if (H.hooks && z) {
        oe7(q.setAppState, sessionId, H.hooks, H.name, H.skillRoot)
    }

    // 3. record Skill usage for frequency sorting
    v2H(H.name, source, content, agentId);

    // 4. build loading metadata
    let w = cB1(H, _);  // "<command-name>...<loading-status>..."

    // 5. merge allowed tools
    let Y = vE(H.allowedTools ?? []);

    // 6. return message sequence (inject into AI conversation)
    return {
        messages: [
            d_({ content: w, uuid: O }),           // loading indicator
            d_({ content: D, isMeta: true }),       // prompt content
            ...j,                                    // instructions
            N7({ type: "command_permissions",        // permission override
                 allowedTools: Y, model: H.model })
        ],
        shouldQuery: true,  // trigger AI response
        allowedTools: Y,
        model: H.model,
        effort: H.effort,
        command: H
    }
}

Skill 执行的关键是 shouldQuery: true — 这告诉 Agentic Loop “这些消息注入后,请立即触发 AI 推理”。Skill 的 prompt 被作为对话消息注入,AI 看到这些指令后会自行执行相应操作。

小结:调度链的五个环节各司其职 — 解析 → 查找 → 入口分发 → 类型分发 → Skill 执行。整条链路清晰可追踪,每一步都有明确的输入输出契约。


17.4 50+ 内置命令完整注册表

所有内置命令在模块初始化时通过惰性求值函数 g$8 (推测名: getBuiltinCommands) 组装。这意味着命令对象在首次访问时才被创建,避免启动开销。

注册机制

// 16_commands_slash.js:35630 - g$8 (getBuiltinCommands)
g$8 = $6(() => [
    CT9,    // add-dir         pL9,    // advisor
    ZZ9,    // agents          rG9,    // branch
    T68,    // btw             bL9,    // chrome
    AU_,    // clear           E68,    // color
    p68,    // compact         FA9,    // config
    I68,    // copy            sz9,    // desktop
    CU_,    // cost            wf9,    // context (jsx)
    Yf9,    // context (local) bf9,    // diff
    Ow9,    // doctor          Uk9,    // effort
    A8_,    // exit            $G9,    // fast
    L98,    // files           Z88,    // help
    Uw9,    // ide             lw9,    // init
    v88,    // keybindings     aY9,    // install-github-app
    _D9,    // install-slack   _j9,    // mcp
    Rw9,    // memory          rq8,    // mobile
    jk9,    // model           Sk9,    // remote-env
    NZ9,    // plugin          jJ9,    // pr-comments
    eq8,    // release-notes   CZ9,    // reload-plugins
    VJ9,    // rename          SX9,    // resume
    x78,    // session         KW9,    // skills
    hv9,    // stats           AW9,    // status
    D$8,    // statusline      t98,    // stickers
    Wk9,    // tag             Y68,    // feedback
    fl_,    // review          lX9,    // ultrareview
    uZ9,    // rewind          $09,    // security-review
    z09,    // terminal-setup  el_,    // upgrade
    xk9,    // rate-limit      $98,    // usage
    AwK,    // insights        O98,    // vim
    // ... conditionally registered commands
    i09,    // permissions     j98,    // plan
    JG9,    // privacy         BG9,    // hooks
    GL9,    // sandbox         $Y9,    // logout
    _Y9(),  // login           fG9,    // passes
    eW9,    // tasks
])

完整命令清单

以下按功能分组列出全部命令,包含类型、别名和可见性信息。

核心命令

命令类型描述别名可见性
/helplocal-jsxShow help and available commands—始终可见
/clearlocalClear conversation history and free up contextreset, new始终可见
/compactlocalClear history but keep summary—始终可见
/configlocal-jsxOpen config panelsettings始终可见
/exitlocal-jsxExit the REPLquit始终可见
/modellocal-jsxSet the AI model (dynamic description)—始终可见
/statuslocal-jsxShow version, model, account, tool statuses—始终可见
/costlocalShow total cost and duration—条件隐藏
/versionlocalPrint the running version—已禁用

文件与编辑

命令类型描述别名可见性
/difflocal-jsxView uncommitted changes and per-turn diffs—始终可见
/fileslocalList all files currently in context—已禁用
/planlocal-jsxEnable plan mode or view current session plan—始终可见
/renamelocal-jsxRename the current conversation—始终可见
/copylocal-jsxCopy Claude’s last response to clipboard—始终可见

AI Skill 命令

命令类型描述来源可见性
/initpromptInitialize CLAUDE.md with codebase documentationbuiltin始终可见
/init-verifierspromptCreate verifier skills for automated verificationbuiltin始终可见
/reviewpromptReview a pull requestbuiltin始终可见
/commitpromptCreate a git commitbuiltin始终可见
/commit-push-prpromptCommit, push, and open a PRbuiltin始终可见
/pr-commentspromptGet comments from a GitHub pull requestbuiltin始终可见
/security-reviewpromptSecurity review of pending branch changesbuiltin始终可见
/insightspromptGenerate usage report analyzing sessionsbuiltin始终可见
/statuslinepromptSet up Claude Code’s status line UIbuiltin始终可见

会话管理

命令类型描述别名可见性
/resumelocal-jsxResume a previous conversationcontinue始终可见
/branchlocal-jsxCreate a branch of current conversationfork始终可见
/sessionlocal-jsxShow remote session URL and QR coderemote条件显示
/rewindlocalRestore code/conversation to a previous pointcheckpoint始终可见
/taglocal-jsxToggle a searchable tag on current session—已禁用

工具与权限

命令类型描述别名可见性
/permissionslocal-jsxManage allow & deny tool permission rulesallowed-tools始终可见
/hookslocal-jsxView hook configurations for tool events—始终可见
/sandboxlocal-jsxConfigure sandbox settings—条件显示
/agentslocal-jsxManage agent configurations—始终可见
/taskslocal-jsxList and manage background tasksbashes始终可见

插件与 Skill 管理

命令类型描述别名可见性
/pluginlocal-jsxManage Claude Code pluginsplugins, marketplace始终可见
/reload-pluginslocalActivate pending plugin changes—始终可见
/skillslocal-jsxList available skills—始终可见
/mcplocal-jsxManage MCP servers—始终可见

用户体验

命令类型描述别名可见性
/vimlocalToggle between Vim and Normal editing—始终可见
/themelocal-jsxChange color theme—始终可见
/colorlocal-jsxSet prompt bar color for this session—始终可见
/effortlocal-jsxSet effort level—始终可见
/fastlocal-jsxToggle fast mode—条件显示
/btwlocal-jsxQuick side question without interrupting—始终可见
/terminal-setuplocal-jsxInstall Shift+Enter for newlines—条件显示

账户与系统

命令类型描述别名可见性
/loginlocal-jsxSign in with Anthropic account—始终可见
/logoutlocal-jsxSign out from Anthropic account—始终可见
/upgradelocal-jsxUpgrade to Max for higher rate limits—条件显示
/usagelocal-jsxShow plan usage limits—始终可见
/feedbacklocal-jsxSubmit feedback about Claude Codebug条件显示
/doctorlocal-jsxDiagnose and verify installation—始终可见
/memorylocal-jsxEdit Claude memory files (CLAUDE.md)—始终可见
/privacy-settingslocal-jsxView and update privacy settings—条件显示
/statslocal-jsxShow usage statistics and activity—始终可见
/stickerslocalOrder Claude Code stickers—始终可见
/mobilelocal-jsxQR code for Claude mobile appios, android始终可见
/release-noteslocalView release notes—始终可见

高级 / 远程

命令类型描述别名可见性
/ultrareviewlocal-jsx~10-20 min bug hunting in the cloud—条件显示
/remote-envlocal-jsxConfigure default remote environment—条件显示
/chromelocal-jsxClaude in Chrome (Beta) settings—条件显示
/idelocal-jsxManage IDE integrations—始终可见
/add-dirlocal-jsxAdd a new working directory—始终可见
/desktoplocal-jsxContinue session in Claude Desktopapp条件显示
/advisorlocalConfigure the advisor model—条件显示
/passeslocal-jsxShare a free week with friends—条件显示
/voicelocalToggle voice mode—条件显示
/keybindingslocalOpen keybindings configuration file—条件显示
/contextlocal-jsx/localVisualize current context usage—条件显示

内部 / 调试命令

命令类型描述可见性
/heapdumplocalMemory diagnostics隐藏
/bridge-kicklocalInject bridge failure states隐藏
/thinkback-playlocalPlay thinkback animation隐藏
/output-stylelocal-jsxDeprecated: use /config隐藏
/rate-limit-optionslocal-jsxShow options when rate limited隐藏

可见性控制机制

命令的可见性由两个独立属性控制:

// Command visibility control
{
    isEnabled: () => boolean,   // false = completely disabled, not registered
    isHidden: () => boolean,    // true = registered but hidden from /help
}
  • 始终可见:isEnabled 始终返回 true,isHidden 返回 false
  • 条件显示:isHidden 根据当前状态动态决定(如 /cost 在 API 登录时隐藏)
  • 已禁用:isEnabled 返回 false,命令不会出现在命令列表中
  • 隐藏:isHidden 始终返回 true,仅开发者/内部使用

小结:50+ 内置命令通过惰性求值列表注册,按功能清晰分组。可见性由 isEnabled / isHidden 双重机制控制,支持从完全禁用到条件显示的灵活策略。


17.5 Skill 系统:SKILL.md 解析、$ARGUMENTS 替换、4 种来源

Skill 系统是命令系统中最具扩展性的部分。它允许任何人通过编写一个 Markdown 文件来创建新的 AI 驱动工作流 — 无需修改源码,无需编译,只需一个 SKILL.md 文件。

4 种 Skill 来源

Skill 来源体系
══════════════════════════════════════════
来源            加载路径                   典型场景
──────────────────────────────────────────
builtin         source code hardcoded      /commit, /review, /init
bundled         Nz() registration          officially bundled workflows
userSettings    .claude/skills/*/SKILL.md  user's custom skills
plugin          plugin-dir/skills/         third-party plugins
mcp             MCP server prompts         remote prompt providers
══════════════════════════════════════════

builtin — 内置 Skill

直接在源码中定义,source: "builtin":

// 15_hooks_system.js:13638 - /commit Skill definition
Ye1 = {
    type: "prompt",
    name: "commit",
    description: "Create a git commit",
    allowedTools: [
        "Bash(git add:*)",
        "Bash(git status:*)",
        "Bash(git commit:*)"
    ],
    contentLength: 0,
    progressMessage: "creating commit",
    source: "builtin",
    async getPromptForCommand(H, _) {
        let q = we1();  // build commit prompt
        return [{ type: "text", text: await Tc(q, ...) }]
    }
}

内置 Skill 完整列表:/init, /init-verifiers, /review, /commit, /commit-push-pr, /pr-comments, /security-review, /insights, /statusline

userSettings — 用户自定义 Skill

从 .claude/skills/ 目录加载:

// 16_commands_slash.js:4308 - scan skills subdirectories
if (_) return q.filter((K) => K.isDirectory())
    .map((K) => eD.join(H, K.name, "SKILL.md"));

目录结构:

.claude/
├── skills/
│   ├── my-deploy/
│   │   └── SKILL.md          <-- entry file
│   ├── code-review/
│   │   └── SKILL.md
│   └── ...

bundled — 捆绑 Skill

通过 Nz() (推测名: registerBundledSkill) 函数注册:

// 16_commands_slash.js:27433 - Nz() (registerBundledSkill)
function Nz(H) {
    let K = {
        type: "prompt",
        name: H.name,
        description: H.description,
        aliases: H.aliases,
        allowedTools: H.allowedTools ?? [],
        disableModelInvocation: H.disableModelInvocation ?? false,
        userInvocable: H.userInvocable ?? true,
        contentLength: 0,
        source: "bundled",
        loadedFrom: "bundled",
        hooks: H.hooks,
        skillRoot: q,
        context: H.context,
        agent: H.agent,
        ...
    };
    gL9.push(K)  // add to global list
}

捆绑 Skill 支持附带文件(自动解压到临时目录):

// if Skill definition includes files field
if (_ && Object.keys(_).length > 0) {
    q = cL9(H.name);  // generate temp path
    // wrap getPromptForCommand to inject file content
    $ = async (z, A) => {
        O ??= JTK(H.name, _);  // extract files to temp dir
        let f = await O;
        ...
    }
}

mcp — MCP 服务器 Prompt

MCP 服务器提供的 prompt 作为 Skill 暴露给用户:

// 13_ui_rendering.js:1139 - MCP prompt as Skill
{
    type: "prompt",
    name: "serverName:promptName",  // compound naming
    disableModelInvocation: yGH(H["disable-model-invocation"]),
}

SKILL.md 文件解析

Frontmatter 解析 — ___() (parseSkillFile)

___() 函数将 SKILL.md 文件转换为命令对象:

// 14_html_parser.js:33636 - ___() (parseSkillFile)
function ___(H, _, q, $, K, O, T = { isSkillMode: false }) {
    let { frontmatter: z, content: A } = _;

    // parse all frontmatter fields
    let f = ou(z.description, H);            // description
    let Y = z["allowed-tools"];               // allowed-tools
    let D = gg(Y);                            // parse tool rules
    let M = z["argument-hint"];               // argument-hint
    let J = cE_(z.arguments);                 // arguments list
    let P = z.when_to_use;                    // when_to_use
    let X = z.version;                        // version
    let R = z.name;                           // display name
    let W = z.model;                          // model (inherit/specific)
    let Z = z.effort;                         // effort level
    let v = yGH(z["disable-model-invocation"]); // disable-model-invocation
    let y = z["user-invocable"];              // user-invocable
    let S = yZ_(z.shell, H);                 // shell config

    return {
        type: "prompt",
        name: H,
        description: w,
        allowedTools: D,
        argumentHint: M,
        argNames: J.length > 0 ? J : undefined,
        whenToUse: P,
        model: W,
        effort: k,
        disableModelInvocation: v,
        userInvocable: E,
        source: "plugin",  // or "userSettings" depending on context
        ...
    }
}

支持的 Frontmatter 字段

---
description: "What this skill does"
allowed-tools: Bash(git:*), Read, Edit
argument-hint: "<pr-number>"
arguments: [arg1, arg2]
when_to_use: "When the user asks to deploy..."
version: "1.0"
name: "display-name"
model: "claude-sonnet-4-6"   # or "inherit"
effort: "high"                 # low/medium/high/max
disable-model-invocation: true # AI cannot auto-invoke
user-invocable: true
shell: "bash"
---

Your skill prompt content here...
Use $ARGUMENTS to reference user input.

$ARGUMENTS 变量替换

Skill 内容支持多种参数替换模式:

// 12_computer_use.js:15962 - argument substitution

// 1. $ARGUMENTS[N] -- positional by index
H = H.replace(/\$ARGUMENTS\[(\d+)\]/g, (T, z) => {
    let A = parseInt(z, 10);
    return K[A] ?? ""
})

// 2. $N -- shorthand positional
H = H.replace(/\$(\d+)(?!\w)/g, (T, z) => {
    let A = parseInt(z, 10);
    return K[A] ?? ""
})

// 3. $ARGUMENTS -- full argument string
H = H.replaceAll("$ARGUMENTS", _)

// 4. if no substitution occurred and args exist, append
if (H === O && q && _)
    H = H + "\n\nARGUMENTS: " + _

替换示例:

用户输入: /deploy staging --force

$ARGUMENTS        --> "staging --force"
$ARGUMENTS[0]     --> "staging"
$ARGUMENTS[1]     --> "--force"
$0                --> "staging"
$1                --> "--force"

特殊变量

除了 $ARGUMENTS,还支持两个环境变量:

// 14_html_parser.js:33690
// ${CLAUDE_SKILL_DIR} -- resolves to the directory containing SKILL.md
if (T.isSkillMode) {
    let C = sD.dirname(_.filePath);
    B = B.replace(/\$\{CLAUDE_SKILL_DIR\}/g, C)
}

// ${CLAUDE_SESSION_ID} -- current session UUID
B = B.replace(/\$\{CLAUDE_SESSION_ID\}/g, v_())

这让 Skill 可以引用自身目录中的文件(如模板、配置),实现更复杂的工作流。

Skill 排序与优先级

完整命令列表的组装顺序决定了同名命令的优先级:

// 16_commands_slash.js:35631 - dN9 (getAllCommands)
dN9 = $6(async (H) => {
    let [{
        skillDirCommands: _,    // user .claude/skills/
        pluginSkills: q,        // plugin skills
        bundledSkills: $,       // bundled skills
        builtinPluginSkills: K  // builtin plugin skills
    }, O, T] = await Promise.all([
        fwK(H),               // load skill directories
        RwH(),                 // load plugin commands
        BN9 ? BN9(H) : []     // extra command sources
    ]);

    // merge order: bundled -> builtinPlugin -> skillDir -> extra -> plugin -> builtin
    return [...$, ...K, ..._, ...T, ...O, ...q, ...g$8()]
})
命令优先级(先注册的先匹配)
════════════════════════════════
bundled         <-- highest priority
builtinPlugin
skillDir        <-- user skills here
extra
plugin
builtin         <-- lowest priority
════════════════════════════════

Skill 使用频率排序

用户可见的 Skill 列表按使用频率加权排序:

// 13_ui_rendering.js:64472 - so6() (getSkillFrequencyScore)
function so6(H) {
    let q = z_().skillUsage?.[H];
    if (!q) return 0;
    let $ = (Date.now() - q.lastUsedAt) / 86400000;  // days since last use
    let K = Math.pow(0.5, $ / 7);  // 7-day half-life decay
    return q.usageCount * Math.max(K, 0.1)
}

设计决策:使用 7 天半衰期的指数衰减函数,既考虑了使用频次也考虑了时间因素。一周前用过 10 次的命令和今天用过 5 次的命令,权重大致相当。这确保了 Skill 列表始终反映用户的当前工作习惯。

Skill 可发现性

AI 自动发现 Skill 的过滤逻辑精确控制了哪些 Skill 出现在系统提示中:

// 16_commands_slash.js:35641 - iE (getAiDiscoverableSkills)
// Skills AI can auto-invoke (via Skill tool)
iE = $6(async (H) => {
    return (await mW(H)).filter((q) =>
        q.type === "prompt" &&
        !q.disableModelInvocation &&    // not disabled for AI
        q.source !== "builtin" &&        // not builtin (handled separately)
        (q.loadedFrom === "bundled" ||
         q.loadedFrom === "skills" ||
         q.loadedFrom === "commands_DEPRECATED" ||
         q.hasUserSpecifiedDescription ||
         q.whenToUse)                    // has discoverability metadata
    )
})

小结:Skill 系统通过 SKILL.md 文件实现了“零代码扩展“。4 种来源覆盖从内置到第三方的全部场景,$ARGUMENTS 替换提供了参数化能力,频率衰减排序确保了最常用的 Skill 始终在最前面。


17.6 插件系统:manifest 格式、加载/验证/刷新

插件系统是 Skill 的进一步封装 — 一个插件可以同时提供多个 Skill、Agent 定义、生命周期 Hooks、MCP 服务器和 LSP 服务器。

插件目录结构

plugin-directory/
├── .claude-plugin/
│   ├── marketplace.json     <-- marketplace-published manifest
│   └── plugin.json          <-- local development manifest
├── skills/
│   ├── my-skill/
│   │   └── SKILL.md
│   └── another-skill/
│       └── SKILL.md
├── commands/                <-- legacy (commands_DEPRECATED)
│   └── my-command.md
├── agents/
│   └── my-agent.md
└── hooks/
    └── hooks.json

Plugin Manifest 格式

两种 manifest 格式对应不同的分发渠道:

// 16_commands_slash.js:25384 - marketplace.json validation schema
WOK = pH(() => h.object({
    entries: h.record(h.string(), h.string())
}))
GOK = pH(() => h.object({
    userId: h.string(),
    version: h.number(),
    lastModified: h.string(),
    checksum: h.string(),
    content: WOK()
}))

marketplace.json 包含签名信息(userId、checksum),用于验证插件来源的可信性。plugin.json 用于本地开发,不需要签名。

插件加载与刷新 — wYH() (refreshPlugins)

// 16_commands_slash.js:25414 - wYH() (refreshPlugins)
async function wYH(H) {
    // 1. clear all plugin caches
    j5(), QS7();

    // 2. get enabled/disabled plugin lists
    let _ = await d2();
    let [q, $] = await Promise.all([
        RwH(),                // load plugin commands
        lE(s6())              // load agent definitions
    ]);

    // 3. for each enabled plugin, load MCP and LSP servers
    let [z, A] = await Promise.all([
        Promise.all(K.map(async (j) => {
            let M = await HqH(j, T);      // MCP servers
            if (M) j.mcpServers = M;
            return M ? Object.keys(M).length : 0
        })),
        Promise.all(K.map(async (j) => {
            let M = await LoH(j, T);      // LSP servers
            if (M) j.lspServers = M;
            return M ? Object.keys(M).length : 0
        }))
    ]);

    // 4. update app state
    H((j) => ({
        ...j,
        plugins: { enabled: K, disabled: O, commands: q, ... },
        agentDefinitions: $,
        mcp: { ...j.mcp,
               pluginReconnectKey: j.mcp.pluginReconnectKey + 1 }
    }));

    // 5. load plugin hooks
    await DF();

    return { enabled_count, disabled_count, command_count, ... }
}

插件提供的组件

组件来源目录说明
Skillsskills/*/SKILL.mdPrompt 型 Skill
Commandscommands/*.md旧式命令(deprecated)
Agentsagents/*.md自定义 Agent 配置
Hookshooks/hooks.json生命周期钩子
MCP Serversmanifest 中配置MCP 服务器连接
LSP Serversmanifest 中配置LSP 语言服务器

插件验证

// 16_commands_slash.js:4317 - l29() (validatePlugin)
async function l29(H) {
    let _ = [];
    let q = [
        ["skill", eD.join(H, "skills")],
        ["agent", eD.join(H, "agents")],
        ["command", eD.join(H, "commands")]
    ];
    for (let [K, O] of q) {
        let T = await Q29(O, K === "skill");
        for (let z of T) {
            let f = O7K(z, A, K);  // parse and validate
            if (f.errors.length > 0 || f.warnings.length > 0)
                _.push(f)
        }
    }
    // validate hooks.json
    let $ = await T7K(eD.join(H, "hooks", "hooks.json"));
    ...
}

验证检查包括:Frontmatter 必须存在、YAML 解析成功、description 字段必填、Hooks 配置格式正确。

/reload-plugins 实现

// 16_commands_slash.js:25508
var ZOK = async (H, _) => {
    let q = await wYH(_.setAppState);
    // output summary
    let K = `Reloaded: ${[
        YYH(q.enabled_count, "plugin"),
        YYH(q.command_count, "skill"),
        YYH(q.agent_count, "agent"),
        YYH(q.hook_count, "hook"),
        YYH(q.mcp_count, "plugin MCP server"),
        YYH(q.lsp_count, "plugin LSP server")
    ].join(" . ")}`;
    ...
}

/reload-plugins 是开发插件时的必备命令 — 它清除缓存、重新加载所有插件组件、重连 MCP/LSP 服务器,然后输出加载统计。

小结:插件系统将 Skill、Agent、Hooks、MCP/LSP 统一打包,通过 manifest 管理分发和验证。/reload-plugins 提供了开发时的热刷新能力。


17.7 记忆系统:CLAUDE.md 分层(User/Project/Local/Managed/AutoMem/TeamMem)

记忆系统是命令系统的“持久层“。用户的偏好、项目的规则、团队的约定,都通过分层的 CLAUDE.md 文件持久化。命令系统中的 /memory、/init、/config 等命令直接操作这套记忆体系。

记忆文件路径体系

// 04_git_operations.js:16309 - y1H() (getMemoryFilePath)
function y1H(H) {
    let _ = s6();           // s6() = originalCwd
    switch (H) {
        case "User":        // global user memory
            return mz.join(i6(), "CLAUDE.md");   // ~/.claude/CLAUDE.md
        case "Local":       // local memory (not committed)
            return mz.join(_, "CLAUDE.local.md"); // ./CLAUDE.local.md
        case "Project":     // project memory (committable)
            return mz.join(_, "CLAUDE.md");       // ./CLAUDE.md
        case "Managed":     // managed/policy memory
            return mz.join(RM(), "CLAUDE.md");    // managed-root/CLAUDE.md
        case "AutoMem":     // auto-generated memory
            return tK_();                          // auto-memory directory
    }
    return g2$.getTeamMemEntrypoint();             // team memory entrypoint
}

6 层记忆层次

记忆层次(优先级从高到低)
══════════════════════════════════════════════════════════
层级            路径                           说明
──────────────────────────────────────────────────────────
Managed         <managed-root>/CLAUDE.md      organization policy
                                              cannot be excluded
                                              by claudeMdExcludes

User            ~/.claude/CLAUDE.md           global personal prefs
                                              applies to all projects

Project         ./CLAUDE.md                   project-level rules
                                              committed to Git

Local           ./CLAUDE.local.md             local overrides
                                              not committed to Git

AutoMem         ~/.claude/projects/           AI auto-generated
                <sanitized-cwd>/memory/       learns from sessions

TeamMem         team memory entrypoint        multi-user collaboration
                                              shared team rules

@-imported      @path references in           nested file inclusion
                any CLAUDE.md                 arbitrary depth
══════════════════════════════════════════════════════════

设计决策:Managed 类型不可被 claudeMdExcludes 排除。这是为了确保组织级策略(如安全规则、合规要求)始终生效,即使用户试图绕过。这体现了“安全策略 > 用户偏好“的设计原则。

记忆加载 — CY() (loadMemoryFiles)

CY() 是记忆系统的核心加载函数,被多个模块调用:

CY() 调用点分布
═══════════════════════════════════════════
调用位置                        场景
───────────────────────────────────────────
14_html_parser.js:29327        Skill loading - get memory context
15_hooks_system.js:21373       /memory command - file list
15_hooks_system.js:21905       /memory UI component
13_ui_rendering.js:45544       system prompt construction
16_commands_slash.js:11570     rules/policy checking
18_sdk_examples.js:15841       SDK mode
═══════════════════════════════════════════

返回值包含每个记忆文件的:

  • path — 文件绝对路径
  • content — 文件内容
  • type — 记忆类型(User/Project/Local/Managed/AutoMem)
  • exists — 是否已存在
  • parent — 父文件路径(用于 @-import 嵌套)
  • isNested — 是否为嵌套导入

记忆在系统提示中的注入

// 16_commands_slash.js:43874 - system prompt construction
let {claudeMd} = await Promise.all([ZoH(H), pP(_), Yz(), iA()]);
let z = K.claudeMd?.length ?? 0;
// claudeMd content injected as "# claudeMd" section

系统提示中,CLAUDE.md 内容以明确的来源标注注入:

# claudeMd
Contents of ~/.claude/CLAUDE.md (user's private global instructions):
[user memory content]

Contents of ./CLAUDE.md (project instructions, checked into the codebase):
[project memory content]

/memory 命令 — 记忆文件编辑 UI

// 15_hooks_system.js:21924 - /memory command
i6K = {
    type: "local-jsx",
    name: "memory",
    description: "Edit Claude memory files",
    load: () => Promise.resolve().then(() => (Gw9(), Ww9))
}

/memory 的 UI 组件 Q6K 渲染一个交互式选择列表:

/memory UI 展示的文件列表
══════════════════════════════════════
  User memory      ~/.claude/CLAUDE.md
  Project memory   ./CLAUDE.md
  Local memory     ./CLAUDE.local.md
  @-imported files (nested)
  Auto-memory folder
  Team memory folder (if enabled)
  Agent memory (if applicable)
══════════════════════════════════════

选择文件后,通过 DV() (推测名: openInEditor) 调用系统编辑器:

// editor detection order: $VISUAL > $EDITOR > code > vi > nano
// YV() (detectEditor) checks availability in this order

自动记忆(Auto-Memory)

// toggle auto-memory
J8("userSettings", { autoMemoryEnabled: RH });

// auto-memory directory configuration
autoMemoryDirectory: h.string().optional()
    .describe("Custom directory path for auto-memory storage. "
        + "Supports ~/ prefix. When unset, defaults to "
        + "~/.claude/projects/<sanitized-cwd>/memory/.")
  • AI 在会话中自动学习并写入记忆文件
  • 目录可通过 autoMemoryDirectory 设置自定义
  • 通过 /memory UI 的开关切换启用/禁用

记忆排除:claudeMdExcludes

// 04_git_operations.js:8285
claudeMdExcludes: h.array(h.string()).optional()
    .describe('Glob patterns or absolute paths of CLAUDE.md files '
        + 'to exclude. Only applies to User, Project, and Local '
        + 'memory types (Managed/policy files cannot be excluded).')
// example: "/home/user/monorepo/CLAUDE.md", "**/code/CLAUDE.md"

Rules 目录

除了 CLAUDE.md 文件,还支持 rules/ 目录存放规则文件:

// 04_git_operations.js:16331
function H3_() {           // getUserRulesDir
    return mz.join(i6(), "rules")    // ~/.claude/rules/
}

function e5_() {           // getManagedRulesDir
    return mz.join(RM(), ".claude", "rules")  // managed rules
}

小结:记忆系统通过 6 层 CLAUDE.md 文件实现了从全局到本地的配置级联。Managed 层不可排除确保了安全策略的强制性,Auto-Memory 让 AI 自主学习用户偏好,@-import 支持任意深度的嵌套引用。


17.8 CLI 入口:40+ 命令行参数、yargs 解析

命令系统不仅在交互式 REPL 中运行,还通过 CLI 参数支持非交互调用。这使得 Claude Code 可以集成到 CI/CD 管道、脚本自动化和 IDE 插件中。

入口点:19_tail.js

// 19_tail.js:1184-1209
let H = process.argv.slice(2);
let _ = H.includes("-p") || H.includes("--print");     // print mode
let q = H.includes("--init-only");                       // init only
let $ = H.some((A) => A.startsWith("--sdk-url"));       // SDK mode
let K = _ || q || $ || !process.stdout.isTTY;            // non-interactive

// entry type detection
let T = (() => {
    if (lH(process.env.GITHUB_ACTIONS))            return "github-action";
    if (process.env.CLAUDE_CODE_ENTRYPOINT === "sdk-ts")
                                                    return "sdk-typescript";
    if (process.env.CLAUDE_CODE_ENTRYPOINT === "sdk-py")
                                                    return "sdk-python";
    if (process.env.CLAUDE_CODE_ENTRYPOINT === "sdk-cli")
                                                    return "sdk-cli";
    if (process.env.CLAUDE_CODE_ENTRYPOINT === "claude-vscode")
                                                    return "claude-vscode";
    if (process.env.CLAUDE_CODE_ENTRYPOINT === "local-agent")
                                                    return "local-agent";
    if (process.env.CLAUDE_CODE_ENTRYPOINT === "claude-desktop")
                                                    return "claude-desktop";
    if (A) return "remote";
    return "cli";
})();

入口检测支持 8 种运行环境,从标准 CLI 到 GitHub Actions、VS Code 插件和桌面应用。

Commander.js 程序定义 — pyK() (defineProgram)

pyK() 使用嵌入的 Commander.js 定义所有 CLI 选项。以下按功能分组列出完整参数清单。

核心运行选项

参数类型说明
[prompt]positional初始提示文本
-p, --printflag打印模式(非交互,适合管道)
-d, --debug [filter]optional调试模式,支持类别过滤
--debug-file <path>string调试日志输出到指定文件
--verboseflag详细输出模式
--bareflag极简模式(跳过 hooks/LSP/插件等)

模型与推理

参数类型说明
--model <model>string设置模型(别名或完整名)
--effort <level>choice推理力度:low/medium/high/max
--thinking <mode>choice思考模式:enabled/adaptive/disabled
--fallback-model <model>string过载时的后备模型
--agent <agent>string设置当前 Agent
--betas <betas...>arrayBeta headers(API key 用户)

输入输出格式

参数类型说明
--output-format <format>choicetext/json/stream-json
--input-format <format>choicetext/stream-json
--json-schema <schema>string结构化输出的 JSON Schema
--include-partial-messagesflag流式输出包含部分消息

会话管理

参数类型说明
-c, --continueflag继续最近会话
-r, --resume [id]optional恢复指定会话
--fork-sessionflag恢复时创建新会话 ID
--session-id <uuid>string指定会话 UUID
-n, --name <name>string设置会话名称
--no-session-persistenceflag禁用会话持久化
--from-pr [value]optional恢复 PR 关联会话

工具与权限

参数类型说明
--allowed-tools <tools...>array允许的工具列表
--disallowed-tools <tools...>array禁止的工具列表
--tools <tools...>array可用工具集
--dangerously-skip-permissionsflag跳过所有权限检查
--permission-mode <mode>choice权限模式

系统提示

参数类型说明
--system-prompt <prompt>string自定义系统提示
--system-prompt-file <file>string从文件读取系统提示
--append-system-prompt <prompt>string追加到默认系统提示
--append-system-prompt-file <file>string从文件追加系统提示

MCP 与插件

参数类型说明
--mcp-config <configs...>arrayMCP 服务器配置
--strict-mcp-configflag仅使用 CLI 指定的 MCP
--plugin-dir <path>repeatable额外插件目录
--settings <file-or-json>string额外设置文件
--disable-slash-commandsflag禁用所有 Skill

运行限制

参数类型说明
--max-turns <n>number最大 Agent 循环轮次
--max-budget-usd <amount>number最大 API 花费(美元)
--task-budget <tokens>numberAPI 端任务预算

其他

参数类型说明
--add-dir <dirs...>array添加额外工作目录
--agents <json>string自定义 Agent 定义
--ideflag启动时连接 IDE
--chrome / --no-chromeflag启用/禁用 Chrome 集成
--file <specs...>array启动时下载的文件
--init / --init-onlyflag执行初始化 hooks

--bare 模式

// 19_tail.js:1268
if (w.bare) process.env.CLAUDE_CODE_SIMPLE = "1";

极简模式跳过的组件:

--bare 模式跳过的组件
══════════════════════════
  hooks              lifecycle hooks
  LSP                language servers
  plugins            plugin sync
  attribution        source attribution
  auto-memory        AI learning
  background fetch   prefetching
  keychain read      credential store
  CLAUDE.md discovery auto file loading
══════════════════════════

设计决策:--bare 模式通过单个环境变量 CLAUDE_CODE_SIMPLE=1 控制所有简化行为。这意味着任何模块都可以通过检查这个环境变量来决定是否启用某个功能,无需传递复杂的配置对象。

Stdin 管道输入处理

// 19_tail.js:1210 - myK() (handleStdinInput)
async function myK(H, _) {
    if (!process.stdin.isTTY && !process.argv.includes("mcp")) {
        // non-TTY and not MCP mode
        process.stdin.setEncoding("utf8");
        let q = "";
        process.stdin.on("data", ($) => { q += $ });

        // 3-second timeout waiting for stdin
        let K = await sw8(process.stdin, 3000);
        if (K) process.stderr.write("Warning: no stdin data in 3s...");

        // merge prompt argument and stdin content
        return [H, q].filter(Boolean).join("\n");
    }
    return H;
}

这使得管道用法成为可能:

# pipe file content as context
cat buggy.py | claude -p "Fix the bugs in this file"

# pipe git diff as context
git diff | claude -p "Review these changes"

preAction Hook

// 19_tail.js:1240 - preAction hook
_.hook("preAction", async (f) => {
    await Promise.all([YW8(), aZq()]);    // MDM + init
    await FV9();                            // init settings
    if (!lH(process.env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE))
        process.title = "claude";
    // load plugin directories
    let Y = f.getOptionValue("pluginDir");
    if (Array.isArray(Y) && Y.length > 0)
        wt_(Y);
    // execute migrations
    SyK();
    // remote settings
    SI7(); uF6();
});

preAction 在任何命令执行前运行,负责初始化设置、加载插件目录、执行数据库迁移。

子命令

Commander.js 还注册了几个子命令:

claude mcp     # MCP server management
claude config  # Configuration management
claude api     # Direct API calls

小结:CLI 入口通过 40+ 参数支持从简单的管道调用到复杂的自动化场景。--bare 模式提供最小运行环境,--print 模式支持管道集成,入口检测自动适配 8 种运行环境。


17.9 设计启示:命令系统的可扩展性与插件化设计

回顾整个命令系统的架构,可以提炼出几个对构建可扩展 Agent 系统具有普遍意义的设计模式。

启示 1:正交分类胜过层级分类

Claude Code 没有将命令分为“系统命令 / 用户命令 / AI 命令“这样的层级结构,而是采用了 Type × Source 的正交设计。这意味着:

  • 添加新的来源(如 MCP)不需要修改类型分发逻辑
  • 添加新的类型(如果需要)不需要修改注册机制
  • 两个维度可以独立演化
反模式(层级分类)              正确模式(正交分类)
══════════════════              ══════════════════
SystemCommand                   Type: local | local-jsx | prompt
├── CostCommand                      ×
├── VersionCommand              Source: builtin | bundled | plugin
└── ...                                | mcp | userSettings
UserCommand
├── MySkill
└── ...
AICommand
├── CommitSkill
└── ...

启示 2:Prompt 注入是最安全的扩展方式

所有外部扩展(用户 Skill、插件 Skill、MCP prompt)都通过 type: "prompt" 路径执行。它们不能注册原生的 local 或 local-jsx 命令,只能通过 prompt 注入来驱动 AI 行为。

这有两个好处:

  1. 安全:外部代码不会直接操作系统状态,一切行为都经过 AI 的判断
  2. 一致:所有扩展的执行路径完全一致,调试和监控变得简单

启示 3:惰性加载是大规模命令系统的必需

50+ 命令如果在启动时全部初始化,会显著拖慢冷启动速度。Claude Code 使用两层惰性:

第一层:命令列表本身是惰性的
  g$8 = $6(() => [...])  // $6 = lazy evaluation wrapper

第二层:每个命令的实现是惰性的
  load: () => Promise.resolve().then(() => (init(), module))

只有当用户实际输入了某个命令时,对应的实现代码才会被加载和执行。

启示 4:频率衰减排序反映真实使用习惯

score = usageCount * max(0.5^(daysSinceLastUse / 7), 0.1)

这个简单的公式比单纯的“最近使用“或“最常使用“更准确。7 天半衰期意味着:

  • 昨天用了 10 次的命令权重 ≈ 10 × 0.91 = 9.1
  • 一周前用了 10 次的命令权重 ≈ 10 × 0.50 = 5.0
  • 一个月前用了 10 次的命令权重 ≈ 10 × 0.10 = 1.0(底部截断)

启示 5:分层记忆解决了“谁说了算“问题

在多人协作的项目中,配置冲突是常见问题。Claude Code 的 6 层记忆体系通过明确的优先级解决了这个问题:

Managed (organization) > User (individual)
                       > Project (team)
                       > Local (personal override)

关键设计:Managed 层不可被排除,确保了安全策略的强制性。

启示 6:命令即文档

SKILL.md 文件既是命令的实现(prompt 内容),也是命令的文档(frontmatter 描述)。这种“代码即文档“的设计减少了维护负担 — 不存在“文档过时“的问题,因为文档就是实现本身。

---
description: "Deploy to staging environment"  # <-- this IS the help text
allowed-tools: Bash(kubectl:*), Bash(docker:*)
when_to_use: "When the user asks to deploy"   # <-- this IS the AI hint
---

Deploy the current branch to staging...        # <-- this IS the prompt

小结:命令系统的架构展示了构建可扩展 Agent 的关键模式 — 正交分类、prompt 注入安全边界、惰性加载、频率衰减排序和分层配置。这些模式对任何需要支持大量用户自定义行为的 Agent 系统都有参考价值。


速查表

命令类型与执行方式

类型执行方式返回值适用场景
local同步调用 load().call(args, ctx){type, value} 纯数据信息查询、简单切换
local-jsx异步 React/Ink 渲染JSX 元素 + onDone 回调交互式 UI、多步选择
promptgetPromptForCommand() → AI 推理prompt 注入 + shouldQuery: trueAI 驱动的工作流

命令调度链函数索引

混淆名推测英文名位置作用
Tg_()parseSlashInput13_ui_rendering.js:64436解析 /command args 格式
gB1()handleSlashCommand13_ui_rendering.js:64692主入口:查找 → 分发
YF()findCommand16_commands_slash.js:35474name/alias 三层匹配查找
gfH()hasCommand16_commands_slash.js:35480命令存在性布尔检查
ohH()getCommandOrThrow16_commands_slash.js:35484查找命令(不存在抛异常)
dB1()dispatchCommand13_ui_rendering.js:64830type switch 类型分发
TH9()executeSkill13_ui_rendering.js:65030Skill prompt 构造与注入
BB1()executeForkSkill13_ui_rendering.js:64586Fork 上下文 Skill 执行
KH9()looksLikeCommand13_ui_rendering.js:64689字符串是否像命令名

Skill 系统函数索引

混淆名推测英文名位置作用
g$8getBuiltinCommands16_commands_slash.js:35630内置命令惰性列表
dN9getAllCommands16_commands_slash.js:35631合并所有来源的命令列表
Nz()registerBundledSkill16_commands_slash.js:27433注册捆绑 Skill
gL9bundledSkillsList16_commands_slash.js:27455捆绑 Skill 全局数组
___()parseSkillFile14_html_parser.js:33636SKILL.md → 命令对象转换
iEgetAiDiscoverableSkills16_commands_slash.js:35641AI 可自动发现的 Skill
MTHgetSystemPromptSkills16_commands_slash.js:35650系统提示中列出的 Skill
so6()getSkillFrequencyScore13_ui_rendering.js:64472使用频率评分(7天半衰期)
fwK()loadSkillDirectories16_commands_slash.js:35644加载 .claude/skills/

插件系统函数索引

混淆名推测英文名位置作用
wYH()refreshPlugins16_commands_slash.js:25414插件加载/刷新主函数
RwH()loadPluginCommands16_commands_slash.js:~25400加载插件命令
HqH()loadPluginMcpServers16_commands_slash.js:~25440加载插件 MCP 服务器
LoH()loadPluginLspServers16_commands_slash.js:~25445加载插件 LSP 服务器
l29()validatePlugin16_commands_slash.js:4317插件验证
DF()loadPluginHooks16_commands_slash.js:~25450加载插件 hooks

记忆系统函数索引

混淆名推测英文名位置作用
CY()loadMemoryFiles多处调用加载所有记忆文件(核心)
y1H()getMemoryFilePath04_git_operations.js:16309按类型返回记忆文件路径
i6()getUserConfigDir01_runtime_bootstrap.js:~2060~/.claude/ 目录
s6()getOriginalCwd01_runtime_bootstrap.js:2076原始工作目录
H3_()getUserRulesDir04_git_operations.js:16331~/.claude/rules/ 目录
DV()openInEditor15_hooks_system.js:21744调用系统编辑器
YV()detectEditor15_hooks_system.js:21733检测可用编辑器

CLI 入口函数索引

混淆名推测英文名位置作用
pyK()defineProgram19_tail.js:1227Commander.js 程序定义
myK()handleStdinInput19_tail.js:1210Stdin 管道输入处理
ty9()parseRemoteArgs16_commands_slash.js:47644远程控制参数解析

$ARGUMENTS 替换模式

模式语法示例输入 /deploy staging --force替换结果
完整参数$ARGUMENTS—"staging --force"
按索引$ARGUMENTS[0]—"staging"
简写位置$0—"staging"
自动追加无占位符时—追加 \nARGUMENTS: staging --force

Skill 扩展方式对比

方式入口组件复杂度适用场景
SKILL.md.claude/skills/*/SKILL.md单个 prompt 文件★☆☆简单自定义工作流
Plugin.claude-plugin/ + manifestSkills + Agents + Hooks + MCP/LSP★★☆完整功能包
MCP Server--mcp-config远程 prompt provider★★★外部工具/数据源集成
BundledNz() 代码注册内嵌 Skill + 附带文件★★☆官方维护的扩展

记忆层次优先级

层级路径可排除提交到 Git
Managed<managed-root>/CLAUDE.md不可排除N/A
User~/.claude/CLAUDE.md可排除否
Project./CLAUDE.md可排除是
Local./CLAUDE.local.md可排除否
AutoMem~/.claude/projects/<cwd>/memory/可排除否
TeamMemteam memory entrypoint可排除是

本章总结:Claude Code 的 Slash 命令系统是一个多层次、可扩展的命令框架。三层类型体系(local / local-jsx / prompt)覆盖从即时查询到 AI 驱动工作流的全部场景;Type × Source 的正交设计让执行逻辑和注册机制独立演化;SKILL.md 文件系统实现了“零代码扩展“;插件系统将多种组件统一打包;分层记忆确保了配置的一致性和安全性;CLI 入口的 40+ 参数支持从管道脚本到 IDE 集成的各种自动化场景。理解这套系统,就理解了如何为 Agent 构建一个真正可扩展的交互层。