Skip to content

D363 — Crush gets PreToolUse hooks and project mcp/hook cells

Decision. KB hooks reach Crush through the hooks key of ~/.config/crush/crush.json: the files go to .config/crush/hooks/<name>/ and one entry {name: "cartographer-<hook>", matcher, command} is upserted under hooks.PreToolUse, found and removed by that name; every other entry and key is kept. Only PreToolUse is registered, any other event installs the files and warns. The registered matcher is the KB matcher prefixed with (?i). Crush has no session event, so noSessionStartEvent is set: no bootstrap hook, the sync trigger stays the timer, and the write-findings hook is not offered. In a workspace the mcp cell is the project .crush.json and the hook cell is .crush/hooks/<name>/ registered in that same file; agent and instructions stay unsupported. This amends D225, which marked the hook and the project cells unsupported.

Why. Probed on Crush v0.98.0 (#478): hooks in the global crush.json and in a project .crush.json fire, and of six events only PreToolUse does; exit 2 blocks the tool and its stderr reaches the model. A project .crush.json mcp entry is listed by the session. Tool names are lowercase (bash), the KB's matchers are Claude's (Edit|Write), and Crush is Go, so (?i) makes the same alternation match.

Alternatives rejected. Matching the KB matcher verbatim: never fires on Edit. Lower-casing it: breaks a character class or a regex escape (\S). Registering other events by analogy: not probed, would be a silent no-op. Deleting .crush.json or crush.json when the last hook goes: it is the user's configuration (only the project file, emptied of our mcp entry, is removed, as for every JSON provider). Mapping the payload fields of Claude's tool_input onto Crush's: probed for bash only, so a hook reading tool_input.file_path is its author's concern.

Consequences. PreToolUse KB hooks now reach Crush on the next sync. registerMCPServer takes the scope and writes the project cell of the destination matrix in a workspace; removeMCPServer takes the managed path, and mcpProviderFromPath recognises .crush.json and .mcp.json. A tracked .crush.json makes the workspace hygiene check refuse, as for .mcp.json. A new Crush event or tool-feedback channel is added by a probe, not by inference.