前言¶
寫 hooks 是 agent 工作流裏最常見的定製手段:工具執行前攔截危險命令、任務結束時發通知、會話啓動時注入上下文。如果你在 Claude Code、Codex 或 opencode 裏寫過這類聲明,切到 DeepSeek Harness(dsh)時會遇到一個現實問題——這些配置跟着原 harness 的格式走,dsh 不能直接識別,要麼重寫一遍,要麼在幾套配置之間手動同步。
下面介紹的 hooks-adapter 處理的就是這個問題:它讀取已有的 hooks 配置文件,把各家的事件映射到 dsh 擴展點上,原有聲明不做改寫,就能在 dsh 裏繼續跑。
這是什麼¶
hooks-adapter(v0.1.0,MIT 許可證,作者 JohnXuXianyu22786)定位是通用的 hooks 兼容層:讀取 .claude/settings.json、.codex/hooks.json、opencode.json 的 hooks 部分,以及原生配置(~/.config/hooks-adapter/hooks.json、<project>/.dsh-hooks.json),把各 harness 的生命週期事件映射爲規範事件(如 session:start、tool:before),再綁定到 dsh 擴展點(如 agent/session-start、tools/pre-execute),並以 shell、webhook、oracle、proxy 四種 handler 執行。
幾個設計決策值得先說清楚:
- 配置只讀、不遷移:現有 hooks 聲明保持不變。
- 零運行時依賴:要求 Node >= 18,純 ESM + JSDoc 類型。
- 失敗不阻塞啓動:缺失的配置文件靜默跳過;已有文件有問題時只產生診斷(diagnostics),絕不阻塞 dsh 啓動。
核心功能¶
配置來源與發現¶
插件按固定順序自動發現併合並 9 個配置文件位置(全局 / 項目 / 本地):
| 順序 | 文件 | 方言 |
|---|---|---|
| 1 | ~/.claude/settings.json |
claude |
| 2 | ~/.codex/hooks.json |
codex |
| 3 | ~/.config/opencode/opencode.json |
opencode |
| 4 | ~/.config/hooks-adapter/hooks.json |
native |
| 5 | <project>/.claude/settings.json |
claude |
| 6 | <project>/.codex/hooks.json |
codex |
| 7 | <project>/opencode.json |
opencode |
| 8 | <project>/.dsh-hooks.json |
native |
| 9 | <project>/.claude/settings.local.json |
claude |
合併規則:同名事件由後讀的文件追加組;disableAllHooks 遵循最具體的文件。兩個環境變量可以改變行爲:HOOKS_ADAPTER_CONFIG(同 --config)與 HOOKS_ADAPTER_HOME(同 --home)。配置文件必須是嚴格 JSON,不允許註釋。
四種 handler¶
配置裏的 type 字段沿用各 harness 的習慣寫法,內部歸一化爲四種 kind:
| 配置 type | 內部 kind | 行爲 | 默認超時 |
|---|---|---|---|
command |
shell |
啓動 shell 進程,從 stdin 喂入 JSON 契約 | 600s |
http |
webhook |
POST JSON 到 URL,響應體作爲 decision | 600s |
prompt |
oracle |
調用 LLM 端點評估,{ok:false} 表示拒絕 |
30s |
agent / subagent |
proxy |
委託給子代理運行器(命令可配置) | 60s |
超時控制與失敗降級策略內建;validate 子命令提供友好的配置校驗。
事件映射與攔截行爲¶
各 harness 的事件名先映射爲規範事件,再綁定到 dsh 擴展點:
| 規範事件 | claude | codex | opencode | dsh 擴展點 |
|---|---|---|---|---|
session:start |
SessionStart |
SessionStart |
session.created |
agent/session-start |
session:end |
SessionEnd |
SessionEnd |
session.deleted |
session/disposed |
prompt:submit |
UserPromptSubmit |
UserPromptSubmit |
chat.message |
agent/pre-step |
tool:before |
PreToolUse |
PreToolUse |
tool.execute.before |
tools/pre-execute |
tool:after |
PostToolUse / PostToolUseFailure |
PostToolUse |
tool.execute.after |
tools/post-execute |
turn:stop |
Stop |
Stop |
session.idle |
agent/turn-stopping |
subagent:start |
SubagentStart |
SubagentStart |
tool.execute.before.subagent |
subagent/start |
subagent:end |
SubagentStop |
SubagentStop |
tool.execute.after.subagent |
subagent/end |
notice |
Notification |
Notification |
notification |
manual / stdio |
compact:before |
PreCompact |
— | experimental.session.compacting |
manual / stdio |
行爲上的關鍵點:
PreToolUse是攔截點:handler 退出碼 2,或返回 JSONdecision: "block",會阻止工具調用(或轉爲人工確認)。PostToolUse/PostToolUseFailure(互斥觸發)可拒絕寫回作爲結果反饋,或附加上下文。UserPromptSubmit/SessionStart/Stop/SubagentStart/SubagentStop/SessionEnd可注入上下文、拒絕提示、強制模型繼續。Notification與PreCompact(opencode 方言對應compact:before)僅支持 manual / stdio 觸發。
三種集成模式¶
- dsh 插件(Cordis
apply):推薦方式,裝完自動生效。 - stdio JSON-lines 協議:任意 host 可接入。
- 一次性 CLI:
validate、run、dump、list。
安裝與啓用¶
從 GitHub 倉庫安裝:
dsh plugin --profile demo add github:JohnXuXianyu22786/hooks-adapter
這個包是一個 dsh bundle(dsh.bundle.patch → cordis.patch.yml),添加後會插入插件樹。之後啓動 dsh:
dsh --profile demo
插件會自動發現項目目錄和用戶目錄下的 hooks 配置。也可以從本地 checkout 目錄安裝:
dsh plugin --profile demo add ./hooks-adapter
dsh --profile demo
卸載用:
dsh plugin --profile demo remove hooks-adapter
典型用法¶
沿用現有 hooks 聲明¶
假設你在 .claude/settings.json 裏已經有這樣的聲明:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "guard.sh", "timeout": 10 }
]
}
],
"Stop": [
{ "hooks": [ { "type": "command", "command": "notify-send done" } ] }
]
}
}
含義:Bash 工具執行前先跑 guard.sh(超時 10 秒),可通過退出碼攔截;每次 Stop 事件觸發 notify-send done。裝好插件後這份配置不用改,dsh 下次運行時自動生效。
覆蓋插件配置¶
需要調整行爲時,在 profile 的 cordis.patch.yml 中 replace id: hooks-adapter:
- replace:
- id: hooks-adapter
config:
configPath: /abs/path/to/hooks.json # 固定單個文件,跳過發現
discover: false
llm: { baseUrl: "https://api.example.com/v1", model: "eval-small" }
proxy: { command: "dsh run --quiet" }
configPath 固定單個配置文件並跳過自動發現;discover: false 關閉發現;llm 配置 oracle handler 使用的 LLM 端點;proxy 配置 proxy handler 委託的子代理運行器命令。
stdio 協議與一次性 CLI¶
想在 dsh 之外的宿主程序裏複用同一套 hooks 執行器,走 stdio JSON-lines 協議:
echo '{"op":"ping"}' | node lib/index.js listen --config hooks.json
echo '{"op":"dispatch","event":"PreToolUse","payload":{"tool_name":"Bash","tool_input":{}}}' | node lib/index.js listen
調試和檢查用一次性 CLI。先做校驗,再看合併結果,是比較穩的順序:
node lib/index.js validate # 校驗所有可發現的配置,退出碼 0/1
node lib/index.js run --event PreToolUse --payload payload.json
node lib/index.js dump # 打印合並後的生效配置
node lib/index.js list # 列出發現的配置文件
經過上面的步驟,配置是否被正確發現、事件是否按預期觸發,都可以在不啓動完整 dsh 會話的情況下確認。更多格式細節見倉庫的 docs/ 與 examples/ 目錄。
適用場景與注意¶
適合的場景:
- 從 Claude Code / Codex / opencode 遷到 dsh,已有的 hooks 邏輯想原樣複用。
- 多個 harness 並行使用,希望維護一份 hooks 聲明而不是幾份。
- 想把 hooks 執行器嵌進自己的宿主程序(stdio 協議)。
使用前注意:
- 需要 Node >= 18;配置文件必須爲嚴格 JSON,不允許註釋。
- opencode 方言的
Notification與PreCompact僅支持 manual / stdio 觸發。 - 安全方面:插件以當前 dsh 進程的權限運行,hooks 裏聲明的命令、webhook 和 LLM 調用也在這個權限範圍內執行。安裝任何第三方插件前,建議通讀源碼並確認許可證(本項目爲 MIT)。
結尾¶
hooks-adapter 做的事情不復雜:把各家 harness 的 hooks 聲明翻譯成 dsh 能執行的事件綁定,配置只讀不改寫,裝上即用,卸掉即回。對從其他 harness 遷移過來的開發者,它省掉的是重寫和同步多份配置的成本。
- GitHub:https://github.com/JohnXuXianyu22786/hooks-adapter
- 社區插件目錄:https://www.skillhub.cn/plugins/JohnXuXianyu22786/hooks-adapter (目錄爲社區獨立站點維護,與 DeepSeek / 幻方無官方從屬關係)