Installing a hook: event translation
How agents name hook events
Section titled “How agents name hook events”Claude Code runs a hook before a tool call on the PreToolUse event. Gemini CLI calls the same moment BeforeTool, and Cursor calls it preToolUse. A hook copied across unchanged would never fire. Tool names differ too: Claude Code’s shell tool is Bash, while Gemini CLI’s is run_shell_command.
What HarnessKit does
Section titled “What HarnessKit does”- Read. HarnessKit reads the hook’s event, matcher and command from the source agent. Nothing else travels, such as a timeout.
- Translate the event. HarnessKit looks the event up in a table keyed by Claude Code’s names. If the target has no equivalent, the install fails. The detail panel says only “Failed to install to Hermes”. The reason, such as “Hook event ‘Stop’ is not supported by hermes”, shows only in the summary of a bulk install.
- Append. HarnessKit adds the command under the translated event in the target’s hook file. A command that is already there is not added twice.
Some real pairs from that table:
| Claude Code event | Target agent | Target’s name |
|---|---|---|
PreToolUse | Gemini CLI | BeforeTool |
PreToolUse | Cursor | preToolUse |
PreToolUse | Hermes | pre_tool_call |
UserPromptSubmit | Gemini CLI | BeforeAgent |
Stop | Devin Desktop | post_cascade_response |
Stop | Hermes | none, so the install fails |
Ten agents have hooks in HarnessKit: Claude Code, Codex, Gemini CLI, Cursor, Copilot, Devin Desktop, Hermes, Kiro, Grok Build and Qoder CN. Codex, Copilot, Kiro, Grok Build and Qoder CN use Claude Code’s names for the events they share with it.
Devin Desktop has 12 hook events, and HarnessKit maps only two of them on purpose. Devin Desktop splits tool use into reading code, writing code, running commands and MCP calls. Mapping any one of these to PreToolUse would change how often the hook fires, so HarnessKit leaves them unmapped.
Here is a Claude Code hook that checks shell commands:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": "~/bin/check-command.sh" }] } ] }}After you install it to Gemini CLI, Gemini CLI’s settings file gains this entry:
{ "hooks": { "BeforeTool": [ { "hooks": [ { "command": "~/bin/check-command.sh", "type": "command" } ], "matcher": "Bash" } ] }}The event became BeforeTool. The matcher is still Bash, and Gemini CLI has no tool by that name. Change it to run_shell_command and the hook fires.
Enable and disable
Section titled “Enable and disable”Grok Build keeps a disabled-hooks file, and Kiro has an enabled flag on each hook. HarnessKit uses those. On the other agents, disabling removes the hook from its file. HarnessKit keeps a snapshot, an exact copy, in its database, as for MCP servers.
Limitations
Section titled “Limitations”Under the hood
Section titled “Under the hood”crates/hk-core/src/adapter/hook_events.rsholds the event tables, keyed by Claude Code’s names.crates/hk-core/src/service.rstranslates the event during an install, and nothing else.crates/hk-core/src/deployer.rshas one writer per hook format and decides which formats keep the matcher.crates/hk-core/src/manager.rsenables and disables hooks.src/lib/agent-capabilities.tsgreys out Install to Agent tiles by hook and scope support, not by event.