feat: full hook coverage for Claude Code and Cursor (+ fix WorktreeCreate breakage)#48
Merged
Merged
Conversation
We were registering only 4 of the 20 hook events Cursor exposes (https://cursor.com/docs/hooks), so most of the Agent + Tab flow was invisible to PromptConduit. Expand `buildCursorHooks` to cover the full set: Session lifecycle: sessionStart, sessionEnd Generic tool use (Agent): preToolUse, postToolUse, postToolUseFailure Subagent (Task tool): subagentStart, subagentStop Shell: beforeShellExecution, afterShellExecution MCP: beforeMCPExecution, afterMCPExecution File access (Agent): beforeReadFile, afterFileEdit Prompts and agent output: beforeSubmitPrompt, afterAgentResponse, afterAgentThought Context window: preCompact Stop: stop Tab (inline completions, separate policy from Agent): beforeTabFileRead, afterTabFileEdit We register both the generic `preToolUse`/`postToolUse` AND the specific-tool variants (`beforeShellExecution`, `beforeMCPExecution`, `beforeReadFile`, `afterFileEdit`). The specific events carry richer payload (actual command / file path / MCP server name); the generic ones backfill any tool kind without a dedicated hook. Platform dedupes server-side by event id. `uninstall cursor` already recursively removes any hook entry whose value contains "promptconduit", so the new keys clean up without further changes — verified end-to-end against a fake HOME (20 hooks written, 20 removed). https://claude.ai/code/session_019CWBC2E8pQuShejfsKYrvp
…egistration
Two changes to buildClaudeCodeHooks, plus an idempotency fix to install:
1. Add the 3 events from the current spec we weren't registering:
- Setup (--init-only / -p --init / -p --maintenance)
- UserPromptExpansion (slash-command expansion — covers /skillname
direct invocations, a path PreToolUse does not capture)
- PostToolBatch (fires once per resolved batch of parallel tool calls)
2. Remove WorktreeCreate. Per the canonical reference, configuring a
WorktreeCreate hook *replaces* the default `git worktree` behavior —
the hook must print the new worktree path on stdout, and Claude Code
uses that as the working directory for the isolated session. Our
generic hook handler always prints `{"continue": true}`, which would
cause `claude --worktree` and `isolation: "worktree"` subagents to
fail outright. Until our handler can detect WorktreeCreate events
and return the correct path, we don't register for that event.
(Source: https://code.claude.com/docs/en/hooks)
Also tidies up:
- Matchers dropped from no-matcher events (TaskCreated, TaskCompleted,
TeammateIdle, PostToolBatch). The spec says matchers on those are
silently ignored; we were just emitting noisy JSON.
- install is now self-healing: before merging the current hook set
into the user's settings.json, it strips any of OUR previously-
installed entries (anything whose value contains "promptconduit").
That means an old WorktreeCreate registration left behind by a
prior install gets cleaned up on re-install. Verified against a
fake HOME: planted stale WorktreeCreate + a user-owned hook,
re-installed, stale entry gone, user hook preserved.
Net coverage: 28 of 29 events from the current spec (the missing one
is WorktreeCreate, by design).
https://claude.ai/code/session_019CWBC2E8pQuShejfsKYrvp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings hook coverage up to spec for both Claude Code and Cursor, and fixes a real bug where our
WorktreeCreateregistration was breakingclaude --worktreefor users.Claude Code
Diffed
buildClaudeCodeHooksagainst the canonical hooks reference.Added 3 events that the spec exposes but we weren't registering:
Setup--init-only,-p --init, or-p --maintenance(CI / scripted one-time setup)UserPromptExpansion/skillnameslash command expands into a prompt — captures a pathPreToolUsedoes notPostToolBatchRemoved 1 event because our handler is wrong for it:
WorktreeCreategit worktreebehavior — the hook must print the new worktree path on stdout. Our hook handler prints{"continue": true}, which Claude Code interprets as the path. Result:claude --worktreeandisolation: "worktree"subagents fail for any user who installed our hooks. Until the handler can detectWorktreeCreateand return a real path, we don't register.Tidied up:
matcher: "*"from events the spec marks as no-matcher (TaskCreated,TaskCompleted,TeammateIdle,PostToolBatch). The matcher was silently ignored — just noisy JSON.Made
installidempotent (self-healing): before merging the current hook set into the user's~/.claude/settings.json, we strip any entry whose value already references"promptconduit". That means hook events we used to register but no longer ship (likeWorktreeCreate) get cleaned up on re-install. User-owned hooks are untouched. Same fix applies toinstall cursor.Coverage: 28 of 29 documented Claude Code events (the only omission is
WorktreeCreate, by design).Cursor
Previously registered 4 of 20 events. Expand
buildCursorHooksto the full set from cursor.com/docs/hooks:sessionStart,sessionEndpreToolUse,postToolUse,postToolUseFailuresubagentStart,subagentStopbeforeShellExecution,afterShellExecutionbeforeMCPExecution,afterMCPExecutionbeforeReadFile,afterFileEditbeforeSubmitPrompt,afterAgentResponse,afterAgentThoughtpreCompactstopbeforeTabFileRead,afterTabFileEditWe register both
preToolUse/postToolUseand the tool-specific variants — the specific events carry richer payload (actual command / file path / MCP server name), the generic ones backfill anything without a dedicated hook. Platform dedupes server-side.Coverage: 20 of 20 events.
Test plan
go build ./... && go vet ./... && go test ./...cleanpromptconduit install claude-codeagainst a fake$HOMEwrites 28 hook entries to~/.claude/settings.json(every documented event exceptWorktreeCreate)promptconduit install cursoragainst a fake$HOMEwrites 20 hook entries to~/.cursor/hooks.jsonWorktreeCreateentry pointing at our binary + a user-ownedUserCustomHookin settings.json, re-raninstall claude-code. Result: staleWorktreeCreateremoved,UserCustomHookpreserved.uninstall cursorremoves all 20 (reportedSuccessfully removed 20 PromptConduit hook(s))https://claude.ai/code/session_019CWBC2E8pQuShejfsKYrvp