Skip to content

Hooks Reference ​

Version requirement: This guide targets the Claude Code Hooks–compatible implementation shipped with CodeBuddy Code v1.16.0 and later. Feature status: Hooks are currently in Beta; APIs and runtime behavior may evolve.

Hooks let you inject custom scripts or commands into every stage of a CodeBuddy Code session so you can automate validation, bootstrap environments, run compliance checks, and more. Our implementation is fully compatible with the Claude Code Hooks specification, including event names, payload schemas, and safety guarantees.


Table of Contents ​


Feature Overview ​

  • Full support for all nine Claude Code hook events: PreToolUse, PostToolUse, Notification, UserPromptSubmit, Stop, SubagentStop, PreCompact, SessionStart, SessionEnd.
  • Regex-based matchers to route execution by tool name or event context.
  • Automatic injection of session_id, transcript paths, working directory, and other context.
  • Dual signaling via exit codes and JSON payloads to mirror Claude Code semantics.
  • /hooks CLI panel for reviewing and approving any configuration changes before they take effect.
  • Individual hook processes time out after 60 seconds so one slow script will not block the rest.

Configuration ​

CodeBuddy Code stores hook configuration inside your settings files:

ScopePathNotes
User~/.codebuddy/settings.jsonApplies to every project
Project<project-root>/.codebuddy/settings.jsonShared with the whole repo
Project local<project-root>/.codebuddy/settings.local.jsonLocal-only overrides (not committed)
Enterprise policyDistributed policy bundleManaged centrally by your org

Structure ​

Hooks are grouped by matcher, and each matcher may contain multiple hook definitions:

json
{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}

Key fields:

  • matcher – Case-sensitive pattern for tool names (only for PreToolUse and PostToolUse).
    • Plain string for exact matches: Write matches only the Write tool.
    • Regex patterns allowed: Edit|Write, Web.*, etc.
    • Use *, an empty string (""), or omit matcher to match everything.
  • hooks – Array executed when the matcher hits.
    • type – Execution mode. Use "command" for shell commands. ("prompt" for LLM-based evaluation is defined but not yet available.)
    • command – (type = command) Shell command to run. $CODEBUDDY_PROJECT_DIR is available.
    • prompt – (type = prompt) Prompt text sent to the LLM (not yet supported).
    • timeout – Optional timeout in seconds for the specific hook.

For events that do not use matchers (UserPromptSubmit, Stop, SubagentStop, etc.) you can omit the field entirely:

json
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/prompt-validator.py"
          }
        ]
      }
    ]
  }
}

Project-Scoped Hook Scripts ​

Use the CODEBUDDY_PROJECT_DIR environment variable (available while CodeBuddy builds the hook command) to reference scripts stored in the repo:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CODEBUDDY_PROJECT_DIR\"/.codebuddy/hooks/check-style.sh"
          }
        ]
      }
    ]
  }
}

Plugin Hooks ​

Plugins can ship hooks that merge seamlessly with user or project settings. When you enable a plugin, its hooks are merged automatically.

How plugin hooks work:

  • Defined inside hooks/hooks.json within the plugin bundle, or via a custom path referenced from the hooks field.
  • Activated hooks merge with user and project hooks.
  • Multiple hook sources can all respond to the same event.
  • ${CODEBUDDY_PLUGIN_ROOT} points to the plugin directory for script references.

Example:

json
{
  "description": "Automatic code formatting",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CODEBUDDY_PLUGIN_ROOT}/scripts/format.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Prompt-Based Hooks ​

Status: Not yet supported.

Besides shell commands (type: "command"), CodeBuddy Code defines prompt-based hooks (type: "prompt") that rely on an LLM to decide whether to allow or deny an action.

How Prompt Hooks Work ​

Instead of running a bash command, the hook:

  1. Sends the hook input plus your prompt to a fast LLM.
  2. Receives a structured JSON decision.
  3. Lets CodeBuddy Code enforce that decision.

Configuration ​

json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Evaluate if CodeBuddy should stop: $ARGUMENTS. Check if all tasks are complete."
          }
        ]
      }
    ]
  }
}

Fields:

  • type – Must be "prompt".
  • prompt – Text sent to the LLM. Use $ARGUMENTS as a placeholder; when omitted, the hook input JSON is appended after the prompt.
  • timeout – Optional timeout in seconds (default 30s).

Response Schema ​

The LLM must return JSON:

jsonc
{
  "decision": "approve" | "block",
  "reason": "Explanation for the decision",
  "continue": false,  // Optional: stop CodeBuddy entirely
  "stopReason": "Message shown to user",  // Optional custom stop message
  "systemMessage": "Warning or context"  // Optional message shown to user
}

Hook Events ​

Event Matrix ​

EventTriggerMatcher supportTypical use cases
PreToolUseBefore a tool executesYes (tool name)Command validation, approvals, logging
PostToolUseAfter a tool succeedsYesAuto-formatting, context enrichment
NotificationPermission prompts or 60s idle remindersPartialDesktop alerts, IM pings
UserPromptSubmitUser message submitted
(internal commands excluded)
NoContent review, context injection
StopMain agent reply finishesNoForce continuation, add reminders
SubagentStopSub-agent (Task tool) completesNoExtend or annotate sub-tasks
PreCompactBefore context compactionYes (manual / auto)Preserve key info, avoid lossy compression
SessionStartSession creation or resumeYes (startup / resume / clear / compact)Env bootstrap, variable injection
SessionEndSession terminatedYes (clear / logout / prompt_input_exit / other)Cleanup, log persistence

PreToolUse ​

Runs after CodeBuddy builds tool arguments but before executing the tool.

Common matchers:

  • Task – Sub-agent tasks
  • Bash – Shell commands
  • Glob – File globbing
  • Grep – Content search
  • Read – File reads
  • Edit – File edits
  • Write – File writes
  • WebFetch, WebSearch – Web operations

PostToolUse ​

Runs immediately after a tool succeeds. Uses the same matcher values as PreToolUse.

Notification ​

Runs when CodeBuddy emits a notification. Matchers filter by notification type.

Supported matchers (partial):

  • permission_prompt – Permission dialogs
  • idle_prompt – Idle > 60 seconds
  • auth_success – Auth success (not yet supported)
  • elicitation_dialog – MCP tool elicitation dialogs (not yet supported)

Example:

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/permission-alert.sh"
          }
        ]
      },
      {
        "matcher": "idle_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/idle-notification.sh"
          }
        ]
      }
    ]
  }
}

UserPromptSubmit ​

Runs after the user submits a prompt but before CodeBuddy processes it. Useful for injecting context, validating, or blocking certain prompts.

Stop ​

Runs when the primary CodeBuddy agent finishes responding (skipped if the user manually interrupts).

SubagentStop ​

Runs when a CodeBuddy sub-agent (Task tool) finishes.

PreCompact ​

Runs before CodeBuddy compacts conversation context.

Matchers:

  • manual – Triggered via /compact
  • auto – Triggered automatically when the context window fills up

SessionStart ​

Runs when CodeBuddy starts a new session or resumes an existing one.

Matchers:

  • startup – Fresh start
  • resume – Triggered by --resume, --continue, or /resume
  • clear – Triggered by /clear
  • compact – Triggered by auto/manual compaction

SessionEnd ​

Runs when a session closesβ€”use it to free resources or persist logs.

reason field values:

  • clear – Session cleared via /clear
  • logout – User signed out
  • prompt_input_exit – User exited while the prompt input box was visible
  • other – Any other exit reason

Hook Input ​

Each hook receives JSON over stdin containing session metadata plus event-specific fields:

jsonc
{
  "session_id": "string",
  "transcript_path": "string",  // Path to the conversation JSON
  "cwd": "string",              // Working directory when the hook runs
  "permission_mode": "string",  // "default", "plan", "acceptEdits", or "bypassPermissions"

  // Event-specific properties
  "hook_event_name": "string"
  // ...
}

PreToolUse Input ​

json
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

PostToolUse Input ​

json
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Notification Input ​

json
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Notification",
  "message": "CodeBuddy needs your permission to use Bash",
  "notification_type": "permission_prompt"
}

UserPromptSubmit Input ​

json
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Stop & SubagentStop Input ​

stop_hook_active becomes true when a stop hook has already resumed execution.

json
{
  "session_id": "abc123",
  "transcript_path": "~/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

PreCompact Input ​

For manual triggers, custom_instructions comes from the /compact command. Auto triggers leave it empty.

json
{
  "session_id": "abc123",
  "transcript_path": "~/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

SessionStart Input ​

json
{
  "session_id": "abc123",
  "transcript_path": "~/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

SessionEnd Input ​

json
{
  "session_id": "abc123",
  "transcript_path": "~/.codebuddy/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "SessionEnd",
  "reason": "exit"
}

Hook Output ​

Hooks communicate back to CodeBuddy Code in two ways.

Basic Mode: Exit Codes ​

Use exit status, stdout, and stderr to convey results:

  • Exit code 0 – Success. Stdout appears in transcript mode (Ctrl+R), except for UserPromptSubmit and SessionStart, where stdout is appended to the context.
  • Exit code 2 – Blocking error. Stderr is handled automatically based on the event.
  • Other exit codes – Non-blocking errors. Stderr is shown to the user and execution proceeds.

Exit Code 2 Behavior ​

EventEffect
PreToolUseBlocks the tool call and surfaces stderr
PostToolUseSurfaces stderr (tool already ran)
NotificationN/A – stderr shown to the user
UserPromptSubmitBlocks the prompt, clears it, surfaces stderr
StopBlocks the stop action, surfaces stderr
SubagentStopBlocks the sub-agent stop, surfaces stderr to the sub-agent
PreCompactN/A – stderr shown to the user
SessionStartN/A – stderr shown to the user
SessionEndN/A – stderr shown to the user

Advanced Mode: JSON Output ​

Write structured JSON to stdout for granular control.

Common JSON Fields ​

jsonc
{
  "continue": true,        // Whether CodeBuddy proceeds after the hook (default true)
  "stopReason": "string",  // Message shown when continue is false

  "suppressOutput": true,  // Hide stdout in transcript mode (default false)
  "systemMessage": "string" // Optional warning shown to the user
}

PreToolUse Decision Control ​

jsonc
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow" | "deny" | "ask",
    "permissionDecisionReason": "My reason here",
    "updatedInput": {
      "field_to_modify": "new value"
    }
  }
}
  • allow – Skip the built-in permission dialog.
  • deny – Block the tool call.
  • ask – Force the UI to prompt the user.
  • updatedInput – Mutate tool arguments before execution.

PostToolUse Decision Control ​

jsonc
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Additional information for CodeBuddy"
  }
}

UserPromptSubmit Decision Control ​

jsonc
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here"
  }
}

Stop / SubagentStop Decision Control ​

jsonc
{
  "decision": "block" | undefined,
  "reason": "Must be provided when CodeBuddy is blocked from stopping"
}

SessionStart Decision Control ​

jsonc
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "My additional context here"
  }
}

Using MCP Tools ​

Hooks integrate seamlessly with MCP (Model Context Protocol) tools.

MCP Tool Naming ​

MCP tool names follow the pattern mcp__<server>__<tool>, for example:

  • mcp__memory__create_entities – create_entities on the Memory server
  • mcp__filesystem__read_file – read_file on the Filesystem server
  • mcp__github__search_repositories – GitHub search tool

Configuring Hooks for MCP Tools ​

Target an individual tool or an entire MCP server:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

Security Notes ​

Disclaimer ​

Use at your own risk. Hooks run arbitrary shell commands on your machine. By enabling them you acknowledge:

  • You are solely responsible for the commands you configure.
  • Hooks can read, modify, or delete anything your user can access.
  • Malicious or buggy hooks can cause data loss or system damage.
  • Tencent Cloud offers no warranty and is not liable for any damages.
  • Always test hooks in a safe environment before rolling them into production.

Best Practices ​

  1. Validate and sanitize input – Never trust incoming data blindly.
  2. Quote shell variables – Use "$VAR", not $VAR.
  3. Prevent path traversal – Guard against .. in file paths.
  4. Use absolute paths – Especially for scripts (or "$CODEBUDDY_PROJECT_DIR").
  5. Skip sensitive files – Avoid touching .env, .git/, secrets, etc.

Configuration Safety ​

Editing the settings file does not hot-load hooks. CodeBuddy Code:

  1. Captures a snapshot at startup.
  2. Uses that snapshot for the whole session.
  3. Warns if the file changes externally.
  4. Requires review in the /hooks panel before changes apply.

Execution Details ​

  • Timeout – 60 seconds by default; override per hook.
  • Parallelism – All matching hooks run in parallel.
  • Deduplication – Identical commands are coalesced.
  • Environment – Runs inside the current working directory with CodeBuddy's environment.
    • CODEBUDDY_PROJECT_DIR exposes the absolute project root.
  • Input – JSON over stdin.
  • Output –
    • PreToolUse / PostToolUse / Stop / SubagentStop: progress visible in transcript mode (Ctrl+R).
    • Notification / SessionEnd: logged only when --debug is enabled.
    • UserPromptSubmit / SessionStart: stdout is appended to the conversation context.

Debugging ​

Basic Troubleshooting ​

If hooks are not firing:

  1. Check configuration – Run /hooks to confirm registration.
  2. Validate JSON – Ensure the settings file parses.
  3. Test commands – Execute the script manually first.
  4. Verify permissions – Scripts must be executable.
  5. Inspect logs – Launch codebuddy --debug for hook traces.

Common mistakes:

  • Unescaped quotes – Use \" inside JSON strings.
  • Incorrect matcher – Tool names are case-sensitive.
  • Command not found – Provide full paths.

Advanced Debugging ​

For tricky issues:

  1. Trace execution – codebuddy --debug shows hook scheduling and output.
  2. Validate schemas – Use external tools to simulate hook input/output.
  3. Check env vars – Confirm CodeBuddy exposes the expected environment.
  4. Test edge cases – Try unusual paths or payloads.
  5. Monitor resources – Ensure hooks are not exhausting CPU/RAM.
  6. Emit structured logs – Add logging inside your scripts.

Debug Output Example ​

Not yet supported for general availability.

codebuddy --debug prints hook execution like:

text
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>

Transcript mode (Ctrl+R) displays which hook is running, the command, success/failure, and any output.


With this guide you should have a complete understanding of how hooks work inside CodeBuddy Code and how to configure them safely. For a hands-on walkthrough, continue with the Hooks Getting Started Guide.