Skip to main content
Mod 是一個 Claude Code plugin,具有一個進入檔案,稱為 hooks module:一個 JavaScript 或 TypeScript 檔案,其函數在事件發生時由 Claude Code 呼叫。有兩種方式可以建立:
  • 要求 Claude 寫它:在 Claude Code 工作階段中描述你想要的
  • 自己寫:按照教學學習 mod 程式碼的運作方式。你不需要 Node.js、bundler 或建置步驟,因為 Claude Code 直接載入 .js 和 .ts 檔案。
如果你還沒決定 mod 是否是正確的工具,請先閱讀概述上的比較。
Mod 需要 Claude Code v2.1.287 或更新版本。在你的 shell 中,執行 claude --version 來檢查。若要查看 mod 是否可以為你載入,請參閱檢查 mod 是否可以載入。

要求 Claude 寫 mod

在互動式 Claude Code 工作階段中描述你想要的 mod,Claude 會寫出來。Claude 使用名為 plugin-authoring 的內建 skill,它告訴 Claude 在哪裡寫 mod、你的版本有哪些事件和方法,以及 mod 如何被載入。當你要求 mod 時,Claude 可以載入該 skill,或者你可以在 Claude Code 提示符處執行 /plugin-authoring 來自己載入它。 mod 在你批准後執行,除了在mod Claude 寫的無法載入的工作階段中。
1

描述 mod

用你自己的話要求 mod,例如 make a mod that shows the current git branch above the prompt。Claude 在工作階段的 mod 資料夾中的自己的目錄中寫 mod,該資料夾是 ~/.claude/dev-mods/ 後跟工作階段的 ID。mod 的完整路徑看起來像 ~/.claude/dev-mods/3f2a9c1e-5b7d-4e8a-9c21-6d0f4b8a7e13/git-branch/。
在 default 和 acceptEdits permission modes 中,Claude Code 在 Claude 建立 mod 的每個檔案之前詢問,因為 ~/.claude 是受保護的路徑。在每個檔案出現時批准它。
2

批准 mod

當 Claude 儲存第一個檔案時,Claude Code 詢問是否為工作階段啟用熱重新載入。熱重新載入執行此工作階段中 Claude 寫的 mod,並在每個稍後變更它們的轉向結束時選擇每個變更。選擇以下其中一個答案:
  • 為此工作階段啟用:工作階段的 mod 資料夾中的 mod 在轉向結束時載入,並在每個變更它們的轉向結束時重新載入。你的答案在工作階段期間持續,包括在你恢復它之後。
  • 暫時不要:現在什麼都不載入。檔案保留在 Claude 寫的地方,mod 在該工作階段下次啟動時載入。若要防止 mod 永遠載入,請刪除其目錄。
3

檢查 mod 是否已載入

在 Claude Code 提示符處執行 /plugin,然後按 Tab 直到選擇已安裝標籤。它列出 mod,你可以在那裡關閉它。
4

試試 mod

使用你要求的。對於範例提示,目前分支名稱出現在提示框上方。如果 mod 沒有做你想要的,告訴 Claude 要改變什麼。mod 在每個變更其檔案的轉向結束時重新載入,所以你可以在 Claude 完成後立即試試變更。

在其他工作階段中使用 mod

Claude 寫的 mod 只在建立它的工作階段中載入,Claude Code 在該工作階段的 mod 資料夾比 cleanupPeriodDays 更舊後刪除它。若要保留 mod,將其目錄複製出 mod 資料夾到你自己的地方,例如 ~/mods/git-branch。然後選擇如何載入它:
  • 在你啟動的工作階段中:在你的 shell 中,執行 claude --plugin-dir ~/mods/git-branch
  • 對於其他人:將其新增到市場,以便他們可以安裝它

Claude 寫的 mod 無法載入的工作階段

Claude 寫的 mod 只在你批准後載入,在允許 mod 執行的受信任工作區中。在這些工作階段中它不會載入:
  • 沒有人在那裡批准:工作階段無法向你顯示提示,如在 claude -p 執行或 dontAsk mode 中
  • 工作區不受信任:你還沒有接受目錄的信任提示
  • Mod 已停止:你使用 --safe-mode 或 --bare 啟動,你設定了 disableAllHooks,或你的組織的受管設定阻止它

自己寫 mod

在本教學中,你建立一個名為 first-mod 的 mod,它計算 Claude 進行的工具呼叫,在 Claude 工作時在微調器旁邊顯示計數,並新增一個 /tally 命令來列印它。然後你讀取 Claude Code 在 mod 旁邊寫的型別宣告,並執行 claude plugin validate。它們一起向你展示你的版本提供的事件和方法,以及 Claude Code 從你的程式碼中讀取的內容。 此錄製顯示完成的 mod。微調器計算工具呼叫,/tally 列印計數,程式碼的編輯在工作階段執行時生效:
你寫三個檔案:
1

建立 plugin 目錄

建立保存檔案的兩個目錄:
2

寫清單

Mod 是一個 plugin,mod 需要一個清單。此 mod 的清單沒有特殊欄位。將此儲存為 first-mod/.claude-plugin/plugin.json:
first-mod/.claude-plugin/plugin.json
3

告訴 Claude Code 你的程式碼在哪裡

當 Claude Code 載入 plugin 時,它讀取 plugin 的 hooks/hooks.json。該檔案中的 modules 鍵給出你的程式碼的路徑,擁有它是使 plugin 成為 mod 的原因。列出一個路徑,相對於 hooks.json。這裡它指向 register.js,你在下一步中寫它。將此儲存為 first-mod/hooks/hooks.json:
first-mod/hooks/hooks.json
4

寫程式碼

此檔案是 mod 的程式碼,稱為 hooks module。當 mod 載入時,Claude Code 呼叫檔案匯出的 register 函數,並傳遞一個名為 on 的函數。每次呼叫 on 都會為它命名的事件註冊一個事件處理程式,稱為 hook。將此儲存為 first-mod/hooks/register.js:
first-mod/hooks/register.js
檔案在 calls 中保留計數,並註冊四個 hook:
  • session.start 在工作階段啟動時執行,在你的第一個提示之前,以及每次 mod 重新載入時。它將 /tally 命令新增到 Claude Code。
  • tool.call 每次 Claude 即將使用工具時執行。它將一個加到 calls 並要求 Claude Code 再次繪製介面。
  • command.run 當你輸入 /tally 時執行。它返回要列印的文字。
  • ui.render 每次 Claude Code 繪製微調器時執行。它在微調器的單詞後新增計數。
範例 mod 如何運作解釋了每個 hook 採用的三個引數以及每個引數返回的內容。
5

載入 mod

使用 --plugin-dir 旗標啟動 Claude Code,它為一個工作階段載入 plugin 目錄而不安裝它:
6

試試 mod

要求 Claude 做一些需要幾個工具呼叫的事情,例如 list the files here and read the README。當 Claude 工作時,微調器的單詞後跟一個上升的計數,如 Thinking · tool calls: 2…。當 Claude 完成時,輸入 /tally 並按 Enter。文字記錄顯示 first-mod: Claude has made 2 tool calls since this mod loaded,帶有你自己的計數。Claude Code 將 plugin 的名稱放在命令的文字前面。若要在非互動模式下檢查命令,請執行它:
如果 /tally 不在命令列表中,模組沒有載入。請參閱找出為什麼 mod 什麼都不做。
7

在工作階段執行時變更程式碼

保持工作階段開啟。在 register.js 中,在 ui.render hook 中將 ' · tool calls: ' 變更為 ' · tools used: ' 並儲存。突出顯示的行是變更的行:
first-mod/hooks/register.js
文字記錄中的一行說 first-mod 重新載入並列出其 hook,下一個微調器使用新文字,如 Thinking · tools used: 1…。

範例 mod 如何運作

你傳遞給 on 的每個函數都是一個 hook,這是一個事件處理程式。Claude Code 將相同的三個引數傳遞給每個 hook:
  • Mod API,名為 $:mod 可以呼叫以到達自身外部的每個方法,在命名空間中,例如 $.ui 和 $.command
  • 事件,名為 e:事件的輸入作為純資料,例如工具呼叫的名稱和引數
  • 下一個處理程式,名為 next:一個函數,將事件傳遞給其他 mod,然後傳遞給 Claude Code 自己的行為,並返回結果
first-mod 中的 hook 以 hook 可以的三種方式處理它們的事件:
  • 觀察:session.start hook 註冊命令,tool.call hook 計算呼叫並要求重新繪製。兩者都返回 next(e),所以工作階段啟動,工具照常執行。
  • 回答:command.run hook 返回自己的結果,永遠不呼叫 next。on 的第二個引數 { command: 'tally' } 是一個篩選器,稱為匹配器,所以 hook 只對 /tally 執行。
  • 重寫:ui.render hook 呼叫 next 並複製 e,其 suffix 保留計數,所以 Claude Code 繪製其通常的微調器,你的文字在單詞後面
Claude Code 監視使用 --plugin-dir 載入的目錄,當其中的檔案變更時熱重新載入 hooks module。每次重新載入都執行 register 再次,所以 calls 回到 0,/tally 開始再次計數。若要在重新載入中保留值,請參閱保留狀態。

繼續處理 mod

一旦 mod 載入,你可以讓 Claude 變更它,根據你版本的型別定義檢查你的程式碼,列出 Claude Code 在其中找到的事件和呼叫,並測試它。

使用 Claude 變更 mod

若要變更你已經有的 mod,使用 --plugin-dir 指向 mod 的目錄啟動工作階段,以便 Claude 寫的內容在同一工作階段中載入:
然後要求變更,例如 add a /tally-reset command to this mod that sets the tally back to zero。Claude 編輯 hooks module,執行 claude plugin validate,並修復它報告的內容。你使用 --plugin-dir 載入的目錄是受保護的路徑,所以在 default 和 acceptEdits 模式中,你被要求批准 Claude 對 mod 的每個編輯。受保護的路徑表給出其他 permission 模式的結果。 Claude 在其轉向期間儲存的檔案在轉向結束時重新載入,所以你可以在 Claude 完成後立即試試 /tally-reset。

取得你版本的型別定義

每次 Claude Code 從你傳遞給 --plugin-dir 的目錄載入或重新載入 mod,或 mod Claude 為你寫的,它將 TypeScript 宣告檔案(以 .d.ts 結尾)寫入 mod 目錄內的 .claude-plugin/types/。它們描述你執行的 Claude Code 版本中的確切事件、mod API 方法和元素,所以你的編輯器可以自動完成和型別檢查你的 hooks。若要線上瀏覽宣告,請閱讀 Claude Code 儲存庫中的 mods/types/claude-code.d.ts,其第一行命名寫入它的版本。目錄保留這些檔案: 如果你的 mod 沒有自己的 tsconfig.json,Claude Code 在 mod 的根目錄新增一個,擴展生成的,所以你的編輯器和 tsc -p ./first-mod 型別檢查 mod 而無需更多設定。 事件和方法可以在版本之間變更,所以當它們不同意時,信任這些檔案而不是任何頁面,包括這個。 claude-code/index.d.ts 是你的建置的最完整參考,每個 mod API 方法都有註解和範例。若要查找某些內容,在檔案中搜尋其名稱,例如 'tool.call'。

檢查 Claude Code 從你的 mod 讀取的內容

若要看到 Claude Code 看到的 mod 的方式,而不執行你的程式碼或啟動工作階段,請使用 claude plugin validate。它檢查清單,並在 hooks module 的來源上執行相同的靜態分析,Claude Code 在載入 mod 時執行。在你的 shell 中,在 mod 的目錄上執行它:
對於 first-mod,輸出包括這些行。
hooks: 行列出你的模組 hook 的事件,每個都在大括號中有其篩選器。calls: 行列出它呼叫的每個 mod API 方法。讀取或設定環境變數的模組也會取得 env reads: 和 env writes: 行,使用 $.state 的模組會取得 state reads: 和 state writes:。 如果你想 hook 的事件在第一行中遺失,Claude Code 也不會呼叫該 hook。通常的原因是事件名稱拼寫錯誤,命令報告為錯誤,例如 "tool.calls" is not an event。 遵循這些規則,以便靜態分析可以找到每個 hook 和呼叫:
  • 完整拼寫每個 mod API 呼叫:$、命名空間,然後方法,如 $.store.get('notes')。你可以將 $ 傳遞給在同一檔案的頂層宣告的函數,對於你的名為 loadNotes 的函數,calls: 行然後讀取 $.store.get (via loadNotes)。將 $ 傳遞給方法、在 hook 內定義的函數或你從另一個檔案匯入的函數會失敗驗證。$.state 使用的 read 和 update 函數是可以採用它的匯入。不要將 $ 或其命名空間之一指派給變數、解構它或使用計算名稱索引它。const ui = $.ui 失敗,出現 $.ui is used as a value。
  • 在每個 on 呼叫中將事件名稱寫為字串文字,例如 'tool.call'。變數或名稱列表上的迴圈失敗,出現 the event name passed to on() is not a string literal。
  • 在 register 內,不要宣告名為 on 的第二個變數或引數。驗證失敗,出現 "on" is declared again (shadowed)。
  • 僅從 plugin 目錄內的檔案匯入,按相對路徑。允許的唯一裸匯入是 claude-code,用於型別和一些幫助程式。
  • 在檔案頂部使用 import 宣告,如 import { name } from './file.js'。動態 import() 失敗,出現 a dynamic import(); a hooks module imports its own files with an import declaration。
  • 將每個檔案寫為 ES 模組,使用 import 而不是 require。參考列出 Claude Code 載入的檔案副檔名。

測試 mod

你可以為 mod 寫自動化測試,並使用 claude plugin test 從你的 shell 執行它們,沒有工作階段、登入或網路。測試引發你的 hook 處理的事件,並檢查 hook 做了什麼。 此測試引發兩個工具呼叫,執行 /tally,並檢查回覆計算兩者。將其儲存為 first-mod/tests/first-mod.test.ts:
first-mod/tests/first-mod.test.ts
在你的 shell 中,從 first-mod 目錄執行測試:
輸出命名每個測試及其是否通過,時間從執行到執行變化:
測試 mod涵蓋模擬模型呼叫或存放區,以及測試計時器和繪製。

分享你的 mod

Mod 是一個 plugin,所以你在清單中版本化它,人們使用 /plugin 命令安裝和更新它。若要將其提供給其他人,將其新增到市場。 在你這樣做之前,檢查 plugin 的 name:claude plugin validate 失敗一個看起來像 Anthropic 自己的名稱,例如以 claude- 開頭的名稱。事件和方法可以在版本之間變更,所以你的 README 是說明你測試的 Claude Code 版本的地方。 使用 --plugin-dir 針對目錄繼續開發,而不是針對已安裝的副本。Claude Code 按版本快取已安裝的 plugin,所以你的編輯在你提高版本並再次安裝之前不會到達已安裝的副本。

後續步驟