AIDive

別再重打 Claude Code 提示:4 項工作變 4 個檔案

AIDive · 發布

編碼 agent自動化與工作流程

你一直重打的四個提示,變成四個檔案

Claude Code 擴充功能,就是你放進 repo 裡的檔案,讓你不必再重打同一段提示:skill、hook、subagent 和 MCP server。我們在一個真實的 repo 上跑了四項重複出現的工作,那是一個用 JSON 檔當資料庫的小型請款 API。每項工作一開始都給了錯的擴充功能,而選錯的結果每次都在畫面上失敗。接著,每項工作都變成一個提交進 repo 的檔案。本頁涵蓋這四個動作,以及決定該用哪一種的選擇卡。

有兩個結果是下面所有內容的背景。hook 常被說成保證,記憶檔裡的規則則被說成請求,但我們的第一個 hook 確實執行了、印出了警告,寫入卻照樣通過。hook 章節會講,是什麼讓「會執行的 hook」變成「會擋下的 hook」。我們接上的第一個文件 server 什麼都沒改變,真正有回答的是該工具自己的文件 server。另外,大多數人照抄的 hook 做法還需要一個獨立的腳本檔,我們的則完全放得進設定檔。

在寫下這四個檔案之前,你得先知道工作階段已經載入了什麼。

這四種是什麼,以及你的工作階段已載入什麼

Claude Code 擴充功能,是你加進 repo 的檔案,讓你不必再把同樣的指示重打進提示框。一共有四種,已經熟悉的讀者可以直接跳到下一節。

  • skill 是歸檔在你 repo 裡的作業手冊。Claude 只在那項工作出現時才載入它的步驟,你也可以輸入它的名稱來啟動。
  • hook 就像 git 的 commit hook,只是對象是 Claude 自己的動作。它是一支在事件發生時執行的腳本,例如一次編輯,不管 Claude 原本打算做什麼。
  • subagent 是一位桌面空無一物的外包人員。它拿到你的簡報,自己去閱讀,然後交回一份報告,而不是那一大堆資料。
  • MCP server 是 Claude 可以呼叫的 API 用戶端,用來取得不在你磁碟上的資料,例如資料庫或某個工具的文件。

要測量任何東西,都得先有基準線。開啟一個全新的工作階段,執行 context 指令。它會印出一張表,列出在你說第一個字之前就已載入的所有東西。在我們的測試環境中,總量是 26.2k token,視窗為 1m,而且完全沒有記憶檔那一行,也沒有 MCP 那一行。從現在起,你交給 Claude 的每一項工作,不是在這張表上多加一行,就是不動它。

第一項工作:發佈檢查清單變成 skill

skill 是歸檔在自己資料夾裡的檢查清單,只有你呼叫時 Claude 才會讀。第一項工作是一份你一直貼進提示框的發佈檢查清單:型別檢查、測試、升版號、加一行 changelog、commit,然後打 tag。

最顯眼的位置是記憶檔,但那是錯的選擇,因為那個檔案裡的所有內容,每個工作階段的每一輪都會載入。我們把步驟放進去,再讀一次 context 表。它多了一行 210 token 的 Memory files,不管你有沒有在發佈都會載入。文件也是這麼說的:當那個檔案的某一節長成了一套程序,它就該搬進 skill。

正確的選擇是在 skills 目錄下建一個資料夾,把步驟寫在 .claude/skills/release/SKILL.md,頂端放一段簡短說明,再加一行 frontmatter:disable-model-invocation: true。這一行會讓 skill 不出現在 Claude 自己的清單裡,只有你能啟動它,而這正是會 commit 和打 tag 的工作所需要的。之後你輸入斜線和名稱,檢查清單就會執行。

context 讀數 總量 Memory files 那一行
基準線,全新工作階段 26.2k / 1m 無
檢查清單放在記憶檔 26.4k / 1m 210 token
檢查清單做成 skill 26.2k / 1m 無,skill 未列出

實際執行時,Claude 在一分鐘內完成了全部六個步驟:型別檢查、34 個測試、版號從 0.4.0 升到 0.4.1、一行 changelog、commit 和 tag。它還抓到我們自己清單裡的一個缺陷。照寫的 commit 指令會略過未追蹤的檔案,所以 Claude 先把新的 changelog 加進暫存區,並且說明了這件事。現在發佈變成一個你輸入的指令,它存在 repo 裡,整個團隊都能用,而在你輸入之前,不佔任何 context。

第二項工作:必須成立的規則變成 hook

hook 是 Claude Code 在工具觸發之前執行的腳本,這裡指的是任何編輯或寫入之前,而這支腳本的回應決定接下來會發生什麼。第二項工作是一條絕不能破的規則:在這個 repo 裡,儲存的資料檔絕不手動編輯,每一次變更都要經過 migration。

把這條規則用大寫寫在記憶檔裡,並不能強制執行它。文件說得很直接:那個檔案是 context,不是強制性的設定,像「never edit this file」這樣的指示是請求,不是保證,而擋下編輯的 hook 才是強制。

最顯而易見的第一個 hook,就是我們寫的那個。它在設定檔裡監看對資料檔的寫入,印出一則警告,然後以代碼零結束,就像一支記錄用的腳本。接著我們要求 Claude 直接在檔案裡修改一筆請款金額,不走 migration。hook 執行了,警告也印出來了,但寫入還是通過:第三張請款單的單價從 8000 變成 12000。Claude 的回覆完全沒提到 hook,因為一個乾淨結束又什麼都不印的 hook 沒有做出任何決定,它的警告也永遠不會傳到 Claude 那裡。

保證不在於 hook 有沒有執行,而在於它回傳的答案。修正的方式是保留同一個 hook,讓它回傳 deny 決定:一行簡短的 JSON,帶著你希望 Claude 讀到的理由。以代碼二結束也會同樣擋下。整個 hook 就是 .claude/settings.json 裡的一條內嵌指令,沒有腳本檔:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c 'if (.tool_input.file_path // \"\") | test(\"data/.*\\\\.json$\") then {hookSpecificOutput: {hookEventName: \"PreToolUse\", permissionDecision: \"deny\", permissionDecisionReason: \"Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions).\"}} else empty end'"
          }
        ]
      }
    ]
  }
}

同樣的要求,這次編輯被拒絕了,資料檔毫髮無傷。Claude 看到的錯誤是:PreToolUse:Edit hook error: Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions). 它表示什麼都沒改,並問我們要覆寫這道防護,還是改寫一個 migration。

限制是 Claude 自己點出來的:這個 hook 只監看編輯和寫入工具,而在之後的一次執行中,Claude 提議改用 shell 來完成變更。hook 必須連 shell 也一併涵蓋,或是讓 shell 不在你的允許清單上,因為只守一扇門的防護,仍然只是請求。這個 hook 不佔任何 context,因為它在你的對話之外執行。

第三項工作:灌爆對話的稽核變成 subagent

subagent 是一個獨立的 Claude 工作階段,擁有自己空白的 context。它收到你的簡報,讀取它需要的內容,只有摘要會回來。第三項工作是會灌爆你對話串的稽核:檢查原始碼資料夾下的每個檔案是否符合 README 的慣例,並列出每一處違規的檔案與行號。

直接在主對話裡問,Claude 會把每個檔案都讀進你的對話,而這些內容會在整個工作階段中一直留著。在我們的執行中,Claude 讀了全部 19 個原始檔,context 表的 Messages 那一行暴增,結果也被埋在那一堆內容底下。

正確的選擇是 .claude/agents/ 下的一個檔案,這裡是 .claude/agents/conventions-auditor.md,裡面有名稱、何時使用的說明、可以使用的工具,以及固定的模型。固定模型很重要,因為 subagent 否則會繼承你工作階段所用的模型,而大多數閱讀型工作並不需要那個大模型。

我們把完全相同的問題再問一次,Claude 還是自己讀檔。兩次嘗試中,即使它已列在清單上,Claude 都沒有呼叫這個 agent:2 次中委派 0 次。有效的做法是在提示開頭指名它:「use the conventions auditor subagent」。結果只發出一次呼叫,回來的是一份簡短的摘要。

執行 總 context Messages 那一行
直接稽核 46.1k 19.3k
指名 subagent 34.1k 7.2k

發現的問題品質相當:subagent 抓到了直接稽核漏掉的一個路徑 bug,也漏掉了直接稽核找到的一個。所以是檔案讓 subagent 存在,是你的提示讓 Claude 去用它;在 Claude 自己會選它之前,你得指名。還有一個限制:帳單沒有變。兩次執行花費相同,因為閱讀仍然會發生,只是不在你的視窗裡。

第四項工作:Claude 碰不到的資料變成 MCP server

MCP server 是 Claude 可以呼叫的 API 用戶端,它存在的目的,是提供比模型還新的資料,或是放在你磁碟之外的資料。這裡的直覺選擇是錯的,所以我們先選了它。

我們為測試用的函式庫接上一個公開的文件 server,並請 Claude 寫一個使用 fake timer 的測試。什麼都沒改變:Claude 本來就認識那個函式庫,而且只有在我們指名時才會呼叫該 server。模型已經知道的文件,並不是它碰不到的資料。

真正的測試,是問一個關於 Claude Code 本身的問題,關於一個比模型還新的 hook 設定:哪個設定會讓失敗的 hook 擋下動作、是哪個版本加入的、確切的 JSON 是什麼。沒有 server 時,Claude 讀了自己安裝版本的設定 schema,什麼都沒找到,然後回答說它找不到那個設定,也不會亂猜。這個回答誠實卻沒用,因為那個設定確實存在,只是它是在模型的知識之後才出現的。

修正的方法,是把 Claude Code 自己的文件 server 加進 repo,並使用 project 範圍,這樣設定會寫進 repo 根目錄的一個檔案,你的整個團隊都會拿到:

claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp

這會寫出 .mcp.json。Claude Code 會把這個 server 列為 pending,直到你在下一個工作階段核准它,之後它的工具就能供 Claude 使用。我們用平常的說法問了同一個問題,沒有指名 server。Claude 搜尋了文件、找到頁面,並回答了設定、版本,以及要加入的 JSON,還附上連結。

那個設定是 "onFailure": "block",它讓失敗的 hook 擋下動作,而不是放行。它是在 v2.1.295 加入的,而我們安裝的還是 2.1.294。這就是限制:Claude 從未說我們安裝的版本無法使用,因為它沒有檢查版本,所以版本要你自己檢查。在 context 表中,這個 server 只會以工具名稱出現,並且在 Claude 去用其中一個之前,都是按需載入。

四個檔案,一張選擇卡

四項工作做完後,git status 恰好顯示四個檔案,因為 hook 不需要自己的腳本:

  • .claude/skills/release/SKILL.md
  • .claude/settings.json
  • .claude/agents/conventions-auditor.md
  • .mcp.json

把它們 commit 之後,這個 repo 的下一個工作階段就擁有全部這些檔案,任何 clone 它的人也是。

每次選對的原因,是文件附帶的一張表,你可以把它留作決策卡:

情境 擴充功能
你又要貼一次的程序 Skill
必須每次都發生、而且不用詢問的事 Hook
輸出多到灌爆對話、你之後不會再看的附帶工作 Subagent
你一直從 Claude 看不到的地方複製過來的資料 MCP server

這幾種也可以組合。文件把 skill 和 MCP server 配成一對:server 提供連線,skill 教 Claude 如何好好使用它。skill 也可以在分叉出來的 subagent 裡執行,讓它的閱讀留在你的視窗之外。當另一個 repo 需要同樣的設定時,plugin 就是把這些全部一起送出的那個盒子。

這張卡決定的是種類,不是品質。只記錄的 hook、你從不指名的 subagent,以及為模型已認識的文件而接的 server,都屬於對的種類,卻都失敗了。從卡上選出種類,再讓檔案真的給出回答,而不只是存在。

結論:何時用哪個、何時都不用、唯一的規則

你以前一直重打的四項工作,全都先用錯的方式試過,在畫面上失敗,現在都變成 repo 裡有效的檔案。發佈是一個你輸入的指令。資料規則是一個拒絕編輯、並讓 Claude 來詢問的 hook。稽核以摘要的形式回來。文件問題則得到了 Claude 自己找不到的設定與版本。

我們一開始用的那個 hook,也就是執行了卻放行寫入的那個,教會了貫穿這一切的規則:hook 只憑它的指令回傳什麼來做決定,所以只記錄的 hook,是穿著戲服的請求。

有些情況這幾種都用不上:

  • Claude 一直做錯的慣例,仍然屬於記憶檔,以一行的形式,而不是一套程序。
  • 需要你來回調整、而且要看著歷史紀錄的工作,留在主對話串,不要放進 subagent。
  • 為模型已認識的函式庫接文件 server,只會耗掉 context,什麼都不會改變。要連的是模型不可能擁有的資料,而不是它已經有的。

要記住的規則:給你每一項重打的工作一個自己的檔案,從卡上選出種類,並且知道在這幾種之中,只有 hook 從不詢問。

免費資源

來源

常見問題

我該用 Claude Code 的 skill、hook、subagent 還是 MCP server?
一直貼的程序用 skill,必須每次都發生、而且不用詢問的事用 hook,會灌爆對話的附帶工作用 subagent,Claude 看不到的資料用 MCP server。文件把這些整理成一張決策表。
為什麼我的 Claude Code hook 執行了,卻沒有擋下編輯?
hook 只憑它的指令回傳什麼來做決定。印出警告後以代碼 0 結束的 hook 沒有做出任何決定,所以編輯會通過;回傳 permissionDecision 為 deny,或以代碼 2 結束,才會擋下。
發佈檢查清單該放在 CLAUDE.md 還是 skill?
放在 skill。記憶檔裡的所有內容,每個工作階段的每一輪都會載入(我們的六步驟檢查清單是 210 token),而設有 disable-model-invocation 的 skill,在你輸入它的名稱之前不佔任何 context。
為什麼 Claude Code 不會自動呼叫我的 subagent?
即使說明幾乎與我們的提示逐字相符,Claude 在 2 次執行中仍有 2 次自己讀檔。在提示開頭指名這個 subagent 後,它才委派,Messages 那一行也從 19.3k 降到 7.2k token。
什麼時候值得為 Claude Code 加上 MCP server?
當資料比模型還新,或放在你的磁碟之外時。為模型已認識的函式庫接文件 server 沒有任何改變,而 Claude Code 文件 server 則回答了一個關於 hook 設定的問題,那個設定在安裝版本自己的 schema 裡並不存在。
我要怎麼把 Claude Code 文件 MCP server 加進 repo?
執行 claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp。它會在 repo 根目錄寫出 .mcp.json,而這個 server 會顯示為 pending,直到你在下一個工作階段核准它。

相關影片