> ## Documentation Index
> Fetch the complete documentation index at: https://felimet-hub.jmcores.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 02-5 Skills / Hooks / Subagents / Plugins 機制總覽

> 這四個機制把 Claude Code 從會聊天的代理變成貼合工作流的自動化系統。本單元建立選型判準，逐一拆解格式、放置位置、優先序與安全邊界。

export const MechanismPicker = ({lang = "zh"}) => {
  const t = {
    zh: {
      q1: {
        text: "你想要的效果，比較像哪一種？",
        context: "例如「每次存檔後自動跑 lint」vs「需要時請 Claude 幫我 review 程式碼」",
        yes: "像前者：必須每次都發生，不依賴 Claude 有沒有想到",
        no: "像後者：需要時才觸發，Claude 判斷或我主動叫它"
      },
      q2: {
        text: "這個任務需要大量讀取或探索嗎？",
        context: "例如「掃整個 codebase 找出哪些函式違反命名規範」這種，會產生很多中間內容，如果都丟進主對話你的指令會被稀釋",
        yes: "是：任務會產生大量中間內容，只需要最終結論回來就好",
        no: "否：主對話處理就夠了，不會太吵"
      },
      q3: {
        text: "這個流程需要分給其他人或跨專案共用嗎？",
        context: "例如「整個團隊都要裝這套設定」或「這是我個人工作流，只在我自己的環境用」",
        yes: "是：要打包讓團隊一次安裝，或放到市集分享",
        no: "否：就我自己用，或只在這個專案用"
      },
      hook: "Hook",
      subagent: "Subagent",
      plugin: "Plugin",
      skill: "Skill",
      hookDesc: "Hook 是事件驅動、由 Claude Code 強制執行的機制，不靠模型自覺。「每次存檔後自動格式化」「擋掉包含明文密鑰的 git push」「每次 session 結束前跑驗證」這類必須保證發生的動作，掛在 PreToolUse / PostToolUse / Stop 等事件上，不管 Claude 這一輪有沒有記得，都一定會執行。",
      subagentDesc: "Subagent 給子任務一個乾淨的 context window。「掃整個 repo 找安全問題、只給我結論」「讀一百個檔案整理成摘要」這類探索性任務，放進主上下文會讓雜訊稀釋你的指令；丟給 subagent，它在隔離環境跑完只傳結論回來，省 token 又提升品質。",
      pluginDesc: "Plugin 把 skills / agents / hooks / MCP 打包成一個可安裝單位。「讓整個團隊一次裝好這套工作流設定」「我做好的一套工具想放到市集分享」這類要打包分發的情境，用 plugin 是正確選項——一個 /plugin install 讓所有人拿到一致的設定。",
      skillDesc: "Skill 是可重用的流程，用 SKILL.md 定義步驟。「幫我依實驗室格式整理文獻」「按這套 checklist 審查 PR」這類我想要 Claude 照步驟執行的任務，用 Skill——session 啟動時只佔一行描述，被觸發後全文才載入，可以裝幾十個不撐爆 context。",
      reset: "重新選擇",
      learnMore: "了解更多",
      paths: {
        hook: "/code-agent/customization/hooks",
        subagent: "/code-agent/customization/subagents",
        plugin: "/code-agent/customization/plugins",
        skill: "/code-agent/customization/skills"
      }
    },
    en: {
      q1: {
        text: "Which outcome are you looking for?",
        context: "For example: 'run lint automatically every time I save' vs 'have Claude review my code when I need it'",
        yes: "Like the first: must happen every time, regardless of whether Claude remembers to do it",
        no: "Like the second: triggered when needed, Claude decides or I invoke it explicitly"
      },
      q2: {
        text: "Does this task involve heavy reading or open-ended exploration?",
        context: "For example: 'scan the entire codebase to find functions that violate naming conventions' -- a task that generates a lot of intermediate content. If all of that lands in the main conversation, it dilutes your instructions.",
        yes: "Yes: the task produces a lot of intermediate content; I only need the final conclusion",
        no: "No: the main conversation can handle it fine without too much noise"
      },
      q3: {
        text: "Does this workflow need to be shared with others or used across projects?",
        context: "For example: 'the whole team needs this setup installed' vs 'this is my personal workflow, just for my own environment'",
        yes: "Yes: package it so the team can install it in one step, or share it on a marketplace",
        no: "No: just for me, or just for this project"
      },
      hook: "Hook",
      subagent: "Subagent",
      plugin: "Plugin",
      skill: "Skill",
      hookDesc: "Hooks are event-driven and enforced by Claude Code itself -- not dependent on the model remembering. 'Auto-format after every save,' 'block a git push that contains a plaintext secret,' 'run a validation check at the end of every session' -- these must-always-happen actions attach to PreToolUse, PostToolUse, Stop, and similar events. They fire whether or not Claude thought of it this turn.",
      subagentDesc: "A subagent gives a subtask its own clean context window. 'Scan the whole repo for security issues and give me only the summary,' 'read a hundred files and condense them into a digest' -- exploration-heavy tasks that would flood the main conversation with noise. Offload them to a subagent: it runs in isolation and returns only the conclusion, saving tokens and improving quality.",
      pluginDesc: "A plugin bundles skills, agents, hooks, and MCP into one installable unit. 'Get the whole team set up with this workflow in a single step,' 'I built a useful toolset and want to publish it on the marketplace' -- these distribution use cases are exactly what plugins are for. One /plugin install and everyone gets a consistent configuration.",
      skillDesc: "A skill is a reusable process defined in a SKILL.md. 'Format my references in the lab style,' 'review a PR against this checklist' -- tasks where you want Claude to follow a defined sequence of steps. At session start it occupies only one line of description (progressive disclosure); the full body loads only when triggered, so you can have dozens installed without blowing up context.",
      reset: "Start over",
      learnMore: "Learn more",
      paths: {
        hook: "/en/code-agent/customization/hooks",
        subagent: "/en/code-agent/customization/subagents",
        plugin: "/en/code-agent/customization/plugins",
        skill: "/en/code-agent/customization/skills"
      }
    }
  };
  const labels = t[lang] || t.zh;
  const resultMeta = {
    hook: {
      color: "#d64c1a",
      icon: "M13 10V3L4 14h7v7l9-11h-7z"
    },
    subagent: {
      color: "#5a7fbf",
      icon: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 1 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 1 21 16z"
    },
    plugin: {
      color: "#bf7551",
      icon: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82zM7 7h.01"
    },
    skill: {
      color: "#4e9b6a",
      icon: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
    }
  };
  const [step, setStep] = useState(0);
  const [result, setResult] = useState(null);
  const handleQ1 = yes => {
    if (yes) {
      setResult("hook");
      setStep(99);
    } else {
      setStep(2);
    }
  };
  const handleQ2 = yes => {
    if (yes) {
      setResult("subagent");
      setStep(99);
    } else {
      setStep(3);
    }
  };
  const handleQ3 = yes => {
    setResult(yes ? "plugin" : "skill");
    setStep(99);
  };
  const reset = () => {
    setStep(0);
    setResult(null);
  };
  const cs = {
    root: "mp-root",
    card: "mp-card",
    question: "mp-question",
    context: "mp-context",
    btns: "mp-btns",
    btn: "mp-btn",
    resultCard: "mp-result-card",
    resultHeader: "mp-result-header",
    resultIcon: "mp-result-icon",
    resultTitle: "mp-result-title",
    resultDesc: "mp-result-desc",
    resultFooter: "mp-result-footer",
    resetBtn: "mp-reset-btn",
    learnBtn: "mp-learn-btn",
    stepDots: "mp-step-dots",
    dot: "mp-dot",
    dotActive: "mp-dot-active"
  };
  const css = `
    .mp-root { font-family: inherit; margin: 1.5rem 0; }
    .mp-card {
      background: var(--mp-bg, #faf8f4);
      border: 1.5px solid var(--mp-border, #e8e0d6);
      border-radius: 10px;
      padding: 1.4rem 1.75rem;
    }
    .dark .mp-card {
      --mp-bg: #232120;
      --mp-border: #3a342e;
    }
    .mp-question {
      font-size: 1rem;
      font-weight: 700;
      color: var(--mp-text, #2a1f18);
      margin-bottom: 0.35rem;
    }
    .dark .mp-question { --mp-text: #ede8e0; }
    .mp-context {
      font-size: 0.84rem;
      color: var(--mp-muted, #7a6a58);
      margin-bottom: 1rem;
      line-height: 1.55;
    }
    .dark .mp-context { --mp-muted: #9a8878; }
    .mp-btns { display: flex; gap: 0.75rem; flex-wrap: wrap; }
    .mp-btn {
      padding: 0.6rem 1.15rem;
      border-radius: 7px;
      border: 1.5px solid #bf7551;
      background: transparent;
      color: #bf7551;
      font-size: 0.88rem;
      cursor: pointer;
      transition: background 0.15s, color 0.15s;
      text-align: left;
      line-height: 1.4;
    }
    .mp-btn:hover { background: #bf7551; color: #fff; }
    .dark .mp-btn { border-color: #d4896a; color: #d4896a; }
    .dark .mp-btn:hover { background: #d4896a; color: #1a1410; }
    .mp-result-card {
      border-radius: 10px;
      padding: 1.4rem 1.75rem;
      background: var(--mp-res-bg, #fdf9f5);
      border: 2px solid var(--mp-res-border, #bf7551);
    }
    .dark .mp-result-card {
      --mp-res-bg: #201c19;
      --mp-res-border: #d4896a;
    }
    .mp-result-header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; }
    .mp-result-icon {
      width: 36px; height: 36px;
      border-radius: 50%;
      display: flex; align-items: center; justify-content: center;
      flex-shrink: 0;
    }
    .mp-result-title { font-size: 1.15rem; font-weight: 700; }
    .mp-result-desc { font-size: 0.91rem; line-height: 1.65; color: var(--mp-desc, #5a4a3a); margin-bottom: 1rem; }
    .dark .mp-result-desc { --mp-desc: #c0b09a; }
    .mp-result-footer { display: flex; gap: 0.75rem; flex-wrap: wrap; }
    .mp-reset-btn {
      padding: 0.45rem 1rem;
      border-radius: 6px;
      border: 1.5px solid var(--mp-border2, #c8bdb0);
      background: transparent;
      color: var(--mp-reset-text, #7a6a5a);
      font-size: 0.88rem;
      cursor: pointer;
    }
    .dark .mp-reset-btn { --mp-border2: #4a4038; --mp-reset-text: #9a8a7a; }
    .mp-reset-btn:hover { border-color: #bf7551; color: #bf7551; }
    .mp-learn-btn {
      padding: 0.45rem 1rem;
      border-radius: 6px;
      background: #bf7551;
      color: #fff;
      font-size: 0.88rem;
      text-decoration: none;
      border: none;
      cursor: pointer;
    }
    .mp-learn-btn:hover { background: #a85f3f; color: #fff; }
    .mp-step-dots { display: flex; gap: 6px; margin-bottom: 1rem; }
    .mp-dot {
      width: 7px; height: 7px; border-radius: 50%;
      background: var(--mp-dot, #d6cec4);
      transition: background 0.2s;
    }
    .dark .mp-dot { --mp-dot: #4a3e34; }
    .mp-dot-active { background: #bf7551 !important; }
    @media (max-width: 500px) {
      .mp-btns { flex-direction: column; }
      .mp-btn { width: 100%; }
    }
  `;
  const questionMap = {
    0: {
      q: labels.q1,
      handler: handleQ1
    },
    2: {
      q: labels.q2,
      handler: handleQ2
    },
    3: {
      q: labels.q3,
      handler: handleQ3
    }
  };
  const currentQ = questionMap[step];
  const meta = result ? resultMeta[result] : null;
  const stepNum = step === 0 ? 1 : step === 2 ? 2 : step === 3 ? 3 : 3;
  return <div className={cs.root}>
      <style>{css}</style>
      {step !== 99 && currentQ && <div className={cs.card}>
          <div className={cs.stepDots}>
            {[1, 2, 3].map(n => <div key={n} className={`${cs.dot}${n <= stepNum ? " " + cs.dotActive : ""}`} />)}
          </div>
          <div className={cs.question}>{currentQ.q.text}</div>
          <div className={cs.context}>{currentQ.q.context}</div>
          <div className={cs.btns}>
            <button className={cs.btn} onClick={() => currentQ.handler(true)}>
              {currentQ.q.yes}
            </button>
            <button className={cs.btn} onClick={() => currentQ.handler(false)}>
              {currentQ.q.no}
            </button>
          </div>
        </div>}
      {step === 99 && result && meta && <div className={cs.resultCard} style={{
    borderColor: meta.color
  }}>
          <div className={cs.resultHeader}>
            <div className={cs.resultIcon} style={{
    background: meta.color + "22"
  }}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={meta.color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <path d={meta.icon} />
              </svg>
            </div>
            <div className={cs.resultTitle} style={{
    color: meta.color
  }}>{labels[result]}</div>
          </div>
          <div className={cs.resultDesc}>{labels[result + "Desc"]}</div>
          <div className={cs.resultFooter}>
            <button className={cs.resetBtn} onClick={reset}>{labels.reset}</button>
            <a className={cs.learnBtn} href={labels.paths[result]}>{labels.learnMore}</a>
          </div>
        </div>}
    </div>;
};

export const LearnerPrimer = ({items = [], lang = "zh"}) => {
  const t = lang === "en" ? {
    title: "Before this unit, be honest with yourself",
    sub: "If you can't answer these, that gap is exactly what this unit closes."
  } : {
    title: "讀這個單元前，先誠實面對",
    sub: "這幾題答不出來，正是這個單元要替你補的洞。"
  };
  const css = `
  .lp-root{--lp-bg:#FAF7F1;--lp-surface:rgba(191,117,81,0.05);--lp-border:rgba(0,0,0,0.09);--lp-edge:rgba(191,117,81,0.42);--lp-text:#2b2722;--lp-dim:#6f6a62;--lp-accent:#bf7551;border:1px solid var(--lp-border);border-left:3px solid var(--lp-edge);border-radius:13px;background:var(--lp-bg);color:var(--lp-text);overflow:hidden;margin:1.25rem 0;}
  .dark .lp-root{--lp-bg:#1b1a18;--lp-surface:rgba(207,138,104,0.07);--lp-border:rgba(255,255,255,0.08);--lp-edge:rgba(207,138,104,0.5);--lp-text:#e7e3da;--lp-dim:#a8a299;--lp-accent:#cf8a68;}
  .lp-head{display:flex;align-items:center;gap:9px;padding:13px 18px 11px;border-bottom:1px solid var(--lp-border);background:var(--lp-surface);}
  .lp-ic{color:var(--lp-accent);flex-shrink:0;}
  .lp-htx{display:flex;flex-direction:column;gap:1px;min-width:0;}
  .lp-title{font-size:14px;font-weight:650;line-height:1.3;letter-spacing:.01em;}
  .lp-sub{font-size:12px;color:var(--lp-dim);line-height:1.4;}
  .lp-list{list-style:none;margin:0;padding:10px 18px 14px;display:flex;flex-direction:column;gap:0;}
  .lp-item{display:flex;align-items:baseline;gap:11px;padding:7px 0;font-size:14px;line-height:1.6;border-top:1px solid var(--lp-border);}
  .lp-item:first-child{border-top:none;}
  .lp-mark{flex-shrink:0;color:var(--lp-accent);font-size:13px;font-weight:700;line-height:1.55;font-variant-numeric:tabular-nums;opacity:.85;}
  .lp-q{flex:1 1 0;min-width:0;color:var(--lp-text);}
  @media (max-width:620px){.lp-head{padding:12px 14px 10px;}.lp-list{padding:8px 14px 12px;}}
  `;
  return <div className="lp-root">
      <style>{css}</style>
      <div className="lp-head">
        <svg className="lp-ic" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><circle cx="12" cy="12" r="6" /><circle cx="12" cy="12" r="2" /></svg>
        <span className="lp-htx">
          <span className="lp-title">{t.title}</span>
          <span className="lp-sub">{t.sub}</span>
        </span>
      </div>
      <ul className="lp-list">
        {items.map((q, i) => <li className="lp-item" key={i}>
            <span className="lp-mark">{String(i + 1).padStart(2, "0")}</span>
            <span className="lp-q">{q}</span>
          </li>)}
      </ul>
    </div>;
};

<LearnerPrimer
  lang="zh"
  items={[
"要它保證發生用 Hook，要它可能發生用 Skill",
"格式化寫進 CLAUDE.md 祈禱模型遵守？模型會漏",
"審查型 subagent 給寫入工具，違反最小權限",
"探索任務丟主上下文，雜訊先稀釋你的指令",
"高 star plugin 不等於安全，star 反映行銷觸及",
"你 hook 從環境變數讀 file_path，讀不到的",
"把 skills/ 放進 .claude-plugin/ 目錄，plugin 載不到",
]}
/>

<Info>
  **這個單元解決什麼問題**

  這四個機制把 Claude Code 從「會聊天的代理」變成「貼合你工作流的自動化系統」。它們常被混用：該保證一定發生的事寫成 Skill 求模型照做、該隔離的子任務塞進主上下文、該打包分發的設定靠手動複製。這個單元先給你「何時用哪一個」的判準，再逐一拆每個機制的格式、放置位置、優先序與安全邊界。深入製作留給 Part IV，這裡建立的是選型總覽。
</Info>

## 學習目標

* [ ] 能說明 Skill / Hook / Subagent / Plugin 各自解決什麼問題，給一個任務能判斷該用哪一個。
* [ ] 能讀懂 `SKILL.md` 與 subagent 的 frontmatter 主要欄位。
* [ ] 能列出主要 Hook 事件與 handler 類型，並說出一個確定性把關的實用範例。
* [ ] 能從官方與社群市集安全地安裝 plugin，並知道安裝前該掃描什麼。

<Warning>
  **時效聲明**

  機制與欄位查證截至 2026-05；Claude Code 演進快，精確欄位與事件清單以官方文件為準，製作細節見 Part IV 各專屬單元。
</Warning>

***

## 1. 先決定用哪一個：四機制選型

四個機制不是平行的替代品，它們回答的是不同問題。先看這張選型表，再往下讀各自細節：

| 你要的是                              | 用            | 為什麼                                  |
| --------------------------------- | ------------ | ------------------------------------ |
| 一個可重用的**流程**，要 Claude 按步驟處理某類任務   | **Skill**    | body 隨需載入，平時只佔一行描述，省 token           |
| 一件**保證一定發生**的確定性動作（格式化、擋危險指令）     | **Hook**     | 事件驅動、由 Claude Code 強制執行，不靠模型自覺       |
| 把一個**子任務隔離**到乾淨上下文（探索、審查），主代理只收結論 | **Subagent** | 獨立 context window，省主線 token 又提升品質    |
| 把上述元件**打包分發**給團隊或他人               | **Plugin**   | 一次安裝帶齊 skills / agents / hooks / MCP |

選型原則：**要「保證發生」用 Hook，要「可重用流程」用 Skill，要「隔離上下文」用 Subagent，要「打包分發」用 Plugin。** 它們正交但可組合，一個 plugin 可以同時帶 skill、hook 與 subagent。

<Tip>
  **最常見的選錯：把該用 Hook 的事寫成 Skill 或 CLAUDE.md**

  「每次存檔後格式化」「禁止寫入某些路徑」這類要保證發生的事，寫進 `CLAUDE.md` 或 Skill 是求模型照做，模型可能漏。要它必然發生，用 Hook（見第 3 節與 [01-6](/code-agent/foundations/harness-engineering) 的策略 vs 規則分界）。
</Tip>

### 互動選型工具

用下方工具回答幾個問題，直接給出機制建議：

<MechanismPicker lang="zh" />

***

## 2. Skills：可重用的流程

Skill 是以 `SKILL.md`（YAML frontmatter + Markdown 本體）定義的可重用流程。和 `CLAUDE.md` 開機即全文載入不同，Skill 走 **progressive disclosure**：session 啟動時只有它的 `description` 進 context，被觸發後 `SKILL.md` 全文才作為一條訊息載入 \[1]。這讓你能裝幾十個 Skill 而不撐爆 context。

**主要 frontmatter 欄位**（全部 optional，只有 `description` 建議必填）\[1]：

| 欄位                                   | 用途                                                      |
| ------------------------------------ | ------------------------------------------------------- |
| `description`                        | 用途與觸發時機，Claude 據此決定是否自動載入（與 `when_to_use` 合計上限 1536 字元） |
| `allowed-tools` / `disallowed-tools` | 此 Skill 活躍期間免詢問可用 / 移除的工具                               |
| `model` / `effort`                   | 此 Skill 活躍期間覆寫模型或 effort 等級，當輪結束恢復                      |
| `disable-model-invocation`           | `true` 則 Claude 不自動載入、描述也不進 context，只能手動 `/name`        |
| `user-invocable`                     | `false` 則不出現在 `/` 選單，但 Claude 仍可自動載入                    |
| `context: fork` + `agent`            | 在 forked subagent 裡執行，`agent` 指定 subagent 類型            |
| `paths`                              | glob，僅在操作到符合路徑的檔案時才自動觸發                                 |

<Note>
  **一個最小 SKILL.md**

  ```markdown theme={null}
  ---
  name: tidy-refs
  description: 依本實驗室格式整理文獻清單。當使用者要整理參考文獻、bib 條目時觸發。
  allowed-tools: Read, Edit
  ---

  # 整理文獻
  1. 讀取使用者指定的文獻檔。
  2. 依 IEEE 編號制重排，三位以上作者用 et al.。
  3. 缺年份的條目標記 `n.d.`（no date），不臆造。
  ```

  放在 `~/.claude/skills/tidy-refs/SKILL.md`（個人）或 `.claude/skills/tidy-refs/SKILL.md`（專案）。觸發後 Claude 才讀到這套步驟。
</Note>

**放置與優先序**（高到低）：企業受管理（managed policy）> 個人 `~/.claude/skills/` > 專案 `.claude/skills/` > plugin（plugin skill 用 `plugin-name:skill-name` 命名空間，不與其他層衝突）\[1]。

**動態 context 注入**：`SKILL.md` 內可放會在載入前先執行、並用輸出替換的指令，讓你把即時資訊（git 狀態、日期）注入流程 \[1]。行首語法如下，另也支援以三個反引號加驚嘆號起始的多行區塊：

```text theme={null}
!`git status --short`
```

可用 `settings.json` 的 `disableSkillShellExecution: true` 停用此行為。

**與舊式 commands 的關係**：`.claude/commands/<name>.md` 仍支援且生成同樣的 `/name`；與同名 Skill 衝突時 **Skill 優先** \[1]。Command 與 Skill 的取捨見 [04-3](/code-agent/customization/commands)、[04-4](/code-agent/customization/skills)。

***

## 3. Hooks：事件驅動的確定性把關

Hook 是掛在生命週期事件上的自訂指令。它和 Skill / CLAUDE.md 的根本差別是**強制性**：CLAUDE.md 是「請你遵守」，Hook 是「我來確保」。需要保證發生的事用 Hook，不要寫進指令祈禱模型照做。

**事件**：Claude Code 截至 2026-06 有 30 個 hook 事件 \[2]，總覽階段你會先用到這幾個：

| 事件                 | 觸發時機         | 典型用途                |
| ------------------ | ------------ | ------------------- |
| `SessionStart`     | session 開始   | 注入專案上下文、環境檢查        |
| `UserPromptSubmit` | 你送出 prompt 後 | 注入動態 context、攔截     |
| `PreToolUse`       | 工具執行前        | 擋危險指令、改寫參數          |
| `PostToolUse`      | 工具執行後        | 自動格式化 / lint / 型別檢查 |
| `Stop`             | 回合結束         | 確定性收尾驗證（收斂哨兵）       |
| `SessionEnd`       | session 結束   | 清理、最終驗證             |

完整事件清單（含 `PermissionRequest`、`SubagentStart` / `SubagentStop`、`PreCompact` 等）見官方與 [04-6](/code-agent/customization/hooks)。

**handler 類型**：`command`（執行 shell 指令 / 腳本）、`http`（POST 事件 JSON 到 URL）、`mcp_tool`（呼叫 MCP 工具）、`prompt`（以 LLM 評估）、`agent`（帶工具的 agentic verifier）\[2]。

**協定**：hook 從 stdin 收一段 JSON（含 `session_id`、`tool_name`、`tool_input` 等）；exit code 2 是阻擋性錯誤（stderr 顯示給 Claude、動作被擋）；exit 0 時解析 stdout 的 JSON 取得決策 \[2]。`PreToolUse` 要擋一個工具呼叫，回傳：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Database writes not allowed"
  }
}
```

<Note>
  **存檔後自動格式化的 PostToolUse hook**

  在 `settings.json` 的 `hooks` 鍵掛一個指向腳本的 PostToolUse，matcher 用 `Edit|Write`：

  ```json theme={null}
  {
    "hooks": {
      "PostToolUse": [
        {
          "matcher": "Edit|Write",
          "hooks": [{ "type": "command", "command": ".claude/hooks/format.sh" }]
        }
      ]
    }
  }
  ```

  hook 腳本從 stdin 的 JSON 取得被改動的檔案路徑（`tool_input.file_path`），對它執行 formatter。注意 Claude Code 並未提供 `$CLAUDE_FILE_PATHS` 這類環境變數帶路徑（截至 2026-05）\[2]，路徑要從 stdin JSON 讀。
</Note>

***

## 4. Subagents：隔離上下文的子代理

Subagent 是定義在 `.claude/agents/*.md`（YAML frontmatter + 系統提示）的子代理，用 `/agents` 管理。它的核心價值是**上下文隔離**：把探索性或大量讀取的子任務丟給一個乾淨上下文的 subagent，主代理只收最終結論，既省主線 token 又避免無關內容稀釋（呼應 [01-4](/code-agent/foundations/context-engineering)）\[3]。

**主要 frontmatter 欄位**（只有 `name`、`description` 必填）\[3]：

| 欄位                          | 用途                                                          |
| --------------------------- | ----------------------------------------------------------- |
| `name` / `description`      | 識別符與「何時委派」的依據                                               |
| `tools` / `disallowedTools` | 工具白名單 / 黑名單；省略 `tools` 則繼承主對話全部工具                           |
| `model`                     | `sonnet` / `opus` / `haiku` / 完整 ID / `inherit`（預設 inherit） |
| `skills`                    | 啟動時直接注入完整內容的 Skill 清單                                       |
| `memory`                    | `user` / `project` / `local`，各對應不同的 agent-memory 目錄         |
| `isolation`                 | 唯一有效值 `worktree`，在臨時 git worktree 執行                        |

**放置與優先序**（高到低）：受管理 > `--agents` CLI > 專案 `.claude/agents/` > 使用者 `~/.claude/agents/` > plugin \[3]。

**內建 subagent**：`Explore`（Haiku、唯讀、跳過 CLAUDE.md，用於搜尋分析）、`Plan`（唯讀規劃）、`general-purpose`（全工具、複雜多步任務）\[3]。一個重要限制：**subagent 不能再生成 subagent**（無巢狀委派）。

<Note>
  **一個唯讀 review subagent**

  ```markdown theme={null}
  ---
  name: kb-reviewer
  description: 審查知識庫單元是否符合撰寫規格。標記單元完成前使用。
  tools: Read, Grep, Glob, Bash
  model: inherit
  ---
  你是唯讀品質審查者。依 writing-spec.md 檢查語氣、全形標點、死連結、時效標註，
  回傳分級問題清單，不修改任何檔案。
  ```

  給它唯讀工具就是最小權限的落地。主代理委派後只收這份清單，不讓審查過程的大量讀取稀釋主上下文（完整 subagent 製作見 [04-5](/code-agent/customization/subagents)）。
</Note>

***

## 5. Plugins 與 Marketplaces：打包與分發

Plugin 把 skills / agents / hooks / MCP server 打包成一個可安裝單位，讓團隊一次裝齊一致的設定。

**市集與安裝**（截至 2026-05）\[4]：

* **官方市集** `claude-plugins-official` 啟動時自動可用：`/plugin install <name>@claude-plugins-official`，瀏覽於 `claude.com/plugins`。
* **社群市集** `anthropics/claude-plugins-community`：先 `/plugin marketplace add anthropics/claude-plugins-community`，再 `/plugin install <name>@claude-community`。
* **任意市集**：`/plugin marketplace add owner/repo`（GitHub）、Git URL 或本地路徑（該 repo 需含 `.claude-plugin/marketplace.json`）。

**plugin 結構**：根目錄的 `.claude-plugin/plugin.json` 是 manifest（唯一放在此目錄的檔案），元件放在外層的 `skills/`、`agents/`、`commands/`、`hooks/hooks.json`、`.mcp.json`、`.lsp.json`、`monitors/monitors.json`、`bin/`，外加 plugin 自身的 `settings.json`（僅 `agent` 與 `subagentStatusLine` 兩個 key 生效）\[4]。

官方明確警告：**不要**把 `commands/`、`agents/`、`skills/`、`hooks/` 放進 `.claude-plugin/` 目錄裡，只有 `plugin.json` 放那。

完整目錄結構：

<Tree>
  <Tree.Folder name="my-plugin/" defaultOpen>
    <Tree.Folder name=".claude-plugin/" defaultOpen>
      <Tree.File name="plugin.json · 唯一放這裡的檔" />
    </Tree.Folder>

    <Tree.Folder name="skills/">
      <Tree.File name="skill-name/SKILL.md" />
    </Tree.Folder>

    <Tree.Folder name="agents/">
      <Tree.File name="agent-name.md" />
    </Tree.Folder>

    <Tree.Folder name="hooks/">
      <Tree.File name="hooks.json" />
    </Tree.Folder>

    <Tree.Folder name="commands/">
      <Tree.File name="command-name.md" />
    </Tree.Folder>

    <Tree.File name=".mcp.json" />

    <Tree.File name="settings.json · 僅 agent / subagentStatusLine 生效" />
  </Tree.Folder>
</Tree>

<Warning>
  **安裝前先掃描：plugin 與 Skill 是供應鏈資產**

  社群 Skill / plugin 等於把別人的程式碼與指令拉進你的 agent。安裝前掃描：隱藏 Unicode（提示注入）、`curl | bash` 之類的外連執行、過寬的工具權限、`ANTHROPIC_BASE_URL` 覆寫、`enableAllProjectMcpServers` 自動核准。star 數高不等於安全或有維護。完整的威脅模型、掃描指令與 CVE 見 [03-3](/code-agent/judgment/security-privacy-supply-chain)，正確使用見 [04-7](/code-agent/customization/plugins)。
</Warning>

***

## 工具對照

四機制在其他工具的對應參差不齊（截至 2026-05，精確機制以各官方文件為準，詳見 [02-6](/code-agent/configuration/other-tools-comparison)）：

| 概念                     | Anthropic Claude（主範本）                          | OpenAI (Codex)         | Google (Gemini CLI) | GitHub Copilot        | Cursor                |
| ---------------------- | ---------------------------------------------- | ---------------------- | ------------------- | --------------------- | --------------------- |
| 可重用流程（Skill / command） | `SKILL.md` + `.claude/commands/` \[1]          | prompt / 自訂指令（以官方文件為準） | 自訂指令（以官方文件為準）       | `.prompt.md`（以官方文件為準） | `.cursor/rules/*.mdc` |
| 事件驅動 Hook              | `hooks` 事件（約 30 個）\[2]                         | 以官方文件為準                | 以官方文件為準             | 以官方文件為準               | 無對等的 Hook 機制          |
| 子代理 / 上下文隔離            | `.claude/agents/*.md` + 內建 Explore / Plan \[3] | 以官方文件為準                | 以官方文件為準             | 以官方文件為準               | 以官方文件為準               |
| Plugin / 擴充市集          | plugin + marketplace \[4]                      | 以官方文件為準                | extensions（以官方文件為準） | 以官方文件為準               | 以官方文件為準               |

<Note>
  **對照只給座標**

  各家對機制的命名與成熟度差異大，精確細節以各官方文件為準。Claude Code 提供約 30 個 hook 事件與內建 subagent 上下文隔離 \[2, 3]；多數其他工具偏「指令 / 規則」層，無對等的確定性事件機制。深入對照見 [02-6](/code-agent/configuration/other-tools-comparison)。
</Note>

***

## 動手做

<Steps>
  <Step title="寫一個最小 Skill">
    照第 2 節範例，在 `~/.claude/skills/` 下建一個 `SKILL.md`（例如「依本實驗室格式整理文獻」），只給 `description` 與步驟。觸發它，確認 Claude 真的按步驟做。
  </Step>

  <Step title="加一個 PostToolUse Hook 在存檔後跑 lint / 格式化">
    照第 3 節範例，在 `settings.json` 掛 `Edit|Write` matcher 的 PostToolUse，指向一個從 stdin JSON 讀 `tool_input.file_path` 的腳本。改一個檔，確認 hook 真的執行。
  </Step>

  <Step title="建一個唯讀 review subagent">
    照第 4 節範例，在 `.claude/agents/` 建一個只給 `Read` / `Grep` 的審查 subagent，用 `/agents` 確認它載入，派它審查一段內容、只收結論。
  </Step>
</Steps>

***

## 常見誤區

<Warning>
  **反模式清單**

  * **把該用 Hook 保證的事寫進 CLAUDE.md 祈禱模型遵守**：格式化、擋危險指令這類要保證發生的事用 Hook，CLAUDE.md 與 Skill 都靠模型自覺。
  * **裝高 star 但無維護、權限過寬的 plugin**：star 反映行銷觸及，不反映安全與維護。安裝前掃描（見 [03-3](/code-agent/judgment/security-privacy-supply-chain)）。
  * **subagent 給過多工具權限**：審查型 subagent 給寫入工具違反最小權限。唯讀任務就只給唯讀工具。
  * **用 Skill 做該隔離的探索任務**：大量讀取的探索丟給主上下文會稀釋它，該用 subagent 隔離、只收結論。
  * **把元件放進 `.claude-plugin/` 目錄**：只有 `plugin.json` 放那，`skills/`、`agents/`、`hooks/` 放外層 \[4]。
</Warning>

***

## 自我檢核

<Check>
  **通過本單元的標準**

  1. 給你一個重複任務（例如「每次提交前跑測試並擋掉失敗的提交」），你能判斷該用 Skill、Hook 還是 Subagent 嗎？依據是什麼？
  2. `disable-model-invocation: true` 與 `user-invocable: false` 兩個 Skill 欄位，效果差在哪？
  3. 你要 Claude Code 在每次存檔後一定執行格式化，你會用哪個 hook 事件？為什麼不寫進 CLAUDE.md？
  4. 一個審查型 subagent 該給哪些工具權限？給了寫入工具會違反什麼原則？
  5. 從社群市集裝一個 plugin 前，你會掃描哪幾類風險訊號？
</Check>

***

## 來源與延伸閱讀

事實主張依官方文件，快變動項標註截至 2026-05。

<div className="references">
  * \[1] Anthropic, "Skills," Claude Code Docs.（`SKILL.md` frontmatter 欄位；progressive disclosure 隨需載入；放置優先序企業 > 個人 > 專案 > plugin；`` !`command` `` 動態注入與 `disableSkillShellExecution`；與 `.claude/commands/` 同名時 Skill 優先） [https://code.claude.com/docs/en/skills](https://code.claude.com/docs/en/skills) （截至 2026-05）

  * \[2] Anthropic, "Hooks," Claude Code Docs.（約 30 個 hook 事件；handler 類型 command / http / mcp\_tool / prompt / agent；stdin JSON 協定、exit code 2 阻擋、exit 0 + JSON 決策；`PreToolUse` 的 `permissionDecision: deny`；matcher 語法；未提供 `$CLAUDE_FILE_PATHS` 環境變數，路徑由 stdin JSON `tool_input.file_path` 取得） [https://code.claude.com/docs/en/hooks](https://code.claude.com/docs/en/hooks) （截至 2026-05）

  * \[3] Anthropic, "Subagents," Claude Code Docs.（`.claude/agents/*.md` frontmatter；放置優先序受管理 > `--agents` > 專案 > 使用者 > plugin；內建 Explore / Plan / general-purpose；上下文隔離只回傳結論；subagent 不能巢狀；`isolation: worktree`） [https://code.claude.com/docs/en/sub-agents](https://code.claude.com/docs/en/sub-agents) （截至 2026-05）

  * \[4] Anthropic, "Plugins," Claude Code Docs.（官方市集 `claude-plugins-official` 自動可用、社群 `anthropics/claude-plugins-community`；`/plugin install`、`/plugin marketplace add`；plugin 結構 `.claude-plugin/plugin.json` + 外層 `skills/` `agents/` `hooks/hooks.json` `.mcp.json`；只有 plugin.json 放 `.claude-plugin/`） [https://code.claude.com/docs/en/plugins](https://code.claude.com/docs/en/plugins) （截至 2026-05）
</div>

* 銜接：[01-6](/code-agent/foundations/harness-engineering) 策略 vs 規則分界（Hook 的設計起點）、[04-3](/code-agent/customization/commands) Command、[04-4](/code-agent/customization/skills) Skill、[04-5](/code-agent/customization/subagents) Subagent、[04-6](/code-agent/customization/hooks) Hooks、[04-7](/code-agent/customization/plugins) Plugin 建置細節、[03-3](/code-agent/judgment/security-privacy-supply-chain) 安全與供應鏈威脅模型。
