- 要求 Claude 寫它:在 Claude Code 工作階段中描述你想要的
- 自己寫:按照教學學習 mod 程式碼的運作方式。你不需要 Node.js、bundler 或建置步驟,因為 Claude Code 直接載入
.js和.ts檔案。
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執行或dontAskmode 中 - 工作區不受信任:你還沒有接受目錄的信任提示
- Mod 已停止:你使用
--safe-mode或--bare啟動,你設定了disableAllHooks,或你的組織的受管設定阻止它
自己寫 mod
在本教學中,你建立一個名為first-mod 的 mod,它計算 Claude 進行的工具呼叫,在 Claude 工作時在微調器旁邊顯示計數,並新增一個 /tally 命令來列印它。然後你讀取 Claude Code 在 mod 旁邊寫的型別宣告,並執行 claude plugin validate。它們一起向你展示你的版本提供的事件和方法,以及 Claude Code 從你的程式碼中讀取的內容。
此錄製顯示完成的 mod。微調器計算工具呼叫,/tally 列印計數,程式碼的編輯在工作階段執行時生效:
1
建立 plugin 目錄
建立保存檔案的兩個目錄:
- Bash or Zsh
- PowerShell
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 繪製微調器時執行。它在微調器的單詞後新增計數。
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.starthook 註冊命令,tool.callhook 計算呼叫並要求重新繪製。兩者都返回next(e),所以工作階段啟動,工具照常執行。 - 回答:
command.runhook 返回自己的結果,永遠不呼叫next。on的第二個引數{ command: 'tally' }是一個篩選器,稱為匹配器,所以 hook 只對/tally執行。 - 重寫:
ui.renderhook 呼叫next並複製e,其suffix保留計數,所以 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
first-mod 目錄執行測試:
分享你的 mod
Mod 是一個 plugin,所以你在清單中版本化它,人們使用/plugin 命令安裝和更新它。若要將其提供給其他人,將其新增到市場。
在你這樣做之前,檢查 plugin 的 name:claude plugin validate 失敗一個看起來像 Anthropic 自己的名稱,例如以 claude- 開頭的名稱。事件和方法可以在版本之間變更,所以你的 README 是說明你測試的 Claude Code 版本的地方。
使用 --plugin-dir 針對目錄繼續開發,而不是針對已安裝的副本。Claude Code 按版本快取已安裝的 plugin,所以你的編輯在你提高版本並再次安裝之前不會到達已安裝的副本。
後續步驟
- 在介面中繪製:開啟窗格、在提示上方繪製,以及新增按鈕和文字欄位
- 對事件做出反應:hook 工具呼叫、提示和轉向
- 使用 mod API:新增命令和工具、呼叫模型,以及在計時器上執行工作
- 測試 mod:模擬 Claude Code 會回答的內容,以及測試計時器和繪製
- 對 mod 進行故障排除:mod 什麼都不做的原因,以及偵錯日誌
- 讀取內建 mod 的來源:完整的 plugin,每個都有其 hooks module 和測試