description: "Run your existing Claude Code hooks.json or settings hook config during agent runs — block prompts and tools, attach context, or force continuation — for users and maintainers of the bridge."
English | 中文
dsh-hooks-claude-code runs command hooks from your existing Claude Code hooks.json or settings file during agent runs, without requiring a rewrite. Supported hooks can run when sessions, prompts, tools, stops, or subagents reach matching moments. They can block prompts or tool calls with model-visible reasons, add conversation context, or force another model turn. Choose this package to reuse Claude Code command hooks in the harness; use a native plugin for behavior that has no Claude Code equivalent.
Mount this package, point configPath at your hook config, and the hooks you already have start firing at the corresponding moments in agent runs. There is nothing else to set up before the first hook works.
Use it when you own a Claude Code hooks.json (or a settings file whose hooks key holds the config) and its command hooks should gate prompts, tools, and turns. Skip it for behavior with no Claude Code equivalent: a native plugin has the full harness API, while this bridge runs only the reference tool's command-hook subset.
- name: '@deepseek-ai/dsh-hooks-claude-code'
config:
configPath: ./.claude/hooks.json
pluginRoot: ./.claude/plugins/my-plugin
projectDir: .
| Field | Default | Meaning |
|---|---|---|
configPath |
required | Path to a hooks.json or a settings file whose hooks key holds the config |
pluginRoot |
— | Replaces ${CLAUDE_PLUGIN_ROOT} in command strings |
projectDir |
session workspace | Replaces ${CLAUDE_PROJECT_DIR} and sets the CLAUDE_PROJECT_DIR env var |
defaultTimeoutMs |
600,000 |
Per-hook timeout when a hook sets none (the Claude Code default) |
stderrSummaryMaxChars |
500 |
Character cap on the persisted hook/result stderr summary |
The generated configuration catalog is the exhaustive source for every accepted field.
| Your hook | When it runs | What it can do |
|---|---|---|
SessionStart |
when a session starts | attach context the model sees in that session |
UserPromptSubmit |
when the agent receives a prompt | block the prompt, or attach extra context |
PreToolUse |
before a tool runs | block the tool, or ask for approval before it runs |
PostToolUse |
after a tool runs | block the result with feedback, or attach extra context |
Stop |
when the run is about to stop | force another step with a reason |
SubagentStart |
when a subagent starts | attach context to a still-running subagent (in-process only) |
SubagentStop |
when a subagent ends | observe only — cannot block or add context |
pwd and relative paths in your hooks refer to your project, not the server's launch directory.${CLAUDE_PLUGIN_ROOT} and ${CLAUDE_PROJECT_DIR} in command strings are replaced from your config, and CLAUDE_PROJECT_DIR is set for every hook process.configPath resolves from the directory that launched the process.Read these pages when the package-level contract is not enough. They move from the shared protocol to the bridge design and the extension points it programs against.
SessionStart, accepted prompt, post-tool, and live in-process subagent-start hooks can add source-attributed context messages; a blocking Stop hook adds its reason as next-step steering. Remote-child injection has no local target.
No cost when hooks return no context. Hook text is data-dependent, logged, and resent in later conversation requests until compaction.
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
Provider-supplied reasons pass through verbatim. When absent, a denied tool becomes Error: blocked by PreToolUse hook, blocked post-tool feedback is exactly blocked by PostToolUse hook, and a blocking stop adds steering exactly continue: blocked by Stop hook; a blocked prompt is discarded with no model-visible message, ending the turn as blocked. systemMessage and updatedInput are logged or warned but are not model-visible in this implementation.
Blocking a prompt removes that prompt's request tokens; denial or feedback adds the retained fallback or provider text; forced continuation pays another full request.
A blocked prompt sends no request and invalidates nothing. Denial, feedback, and forced-continuation context append after the reusable prefix without rewriting it.
These limits describe what your Claude Code hooks cannot do through this bridge yet, and where behavior differs from the reference tool. They are current package constraints, not a task backlog.
Setup, InstructionsLoaded, UserPromptExpansion, MessageDisplay, PermissionRequest, PostToolUseFailure, PostToolBatch, PermissionDenied, Notification, TaskCreated, TaskCompleted, StopFailure, TeammateIdle, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, PreCompact, PostCompact, SessionEnd, Elicitation, and ElicitationResult. Config for these events is ignored before group parsing, so an unsupported event cannot invalidate or register hooks. The comparison baseline is Claude Code's official hook-event reference.SessionStart is partial — JSON additionalContext is consumed, but plain stdout context, initialUserMessage, sessionTitle, watchPaths, reloadSkills, and CLAUDE_ENV_FILE are unsupported. The hook runs detached, so context can miss the first request, and the payload omits optional fields such as model, agent_type, and session_title.UserPromptSubmit is partial — blocking and JSON additionalContext work, but plain stdout context, sessionTitle, and suppressOriginalPrompt are unsupported. Unless overridden, the bridge also uses its 600-second default instead of Claude Code's event-specific 30-second command timeout.PreToolUse is partial — deny and ask decisions work; allow does not pre-approve, defer is unsupported, additionalContext is ignored, and updatedInput is logged + warned but not honored (the pre-tool-input-rewrite Agent Note).PostToolUse is partial — blocking feedback and JSON additionalContext work, but updatedToolOutput and updatedMCPToolOutput are unsupported and tool_response is flattened to text.SubagentStart and SubagentStop are partial — both report a constant agent_type of general-purpose and use the child session id where Claude Code reports the parent session. Start context is best-effort and can only reach a live in-process child; stop is observe-only and cannot block the subagent or feed it context. Stop omits agent_transcript_path, last_assistant_message, background_tasks, and session_crons and always reports stop_hook_active: false.Stop is partial — blocking forces another model turn, but stop_hook_active is always false, last_assistant_message, background_tasks, and session_crons are omitted, and the consecutive-block cap is not implemented. An unconditionally blocking hook therefore force-continues every step unless it self-limits.prompt_id, permission_mode, and effort where Claude Code would provide them, and transcript_path is never populated: it is always the empty string, because the persistence seam exposes no artifact paths and the default-zstd session log is not readable by hook scripts. systemMessage is logged + warned but not surfaced; {"continue": false} is recorded but does not halt the run; suppressOutput, stopReason, and terminalSequence are not applied.http, mcp_tool, prompt, and agent handlers are skipped; command-handler options such as args, async, asyncRewake, shell, if, once, and statusMessage are not honored. Matching handlers run serially and are not deduplicated, whereas Claude Code runs them in parallel and deduplicates identical handlers. One process-level configPath is parsed once at load; Claude Code's layered project, user, plugin, and policy discovery and live reload are not implemented.