Hooks

Hooks Configuration

  • Project Level: {project_path}/.hcode/settings.json
  • User Level: ~/.hcode/settings.json

Matcher

Hooks support Matcher for matching tool names or Subagent names. The matching rules are as follows:

  • Single Match: Match a single attribute, e.g., "Edit".
  • Multiple Matches: Use pipe | to separate multiple attributes, e.g., "Edit|Write".
  • Wildcard Match: Use * for wildcard matching, e.g., "mcp__memory__.*", "mcp__.*__write.*", "mcp__.*__write.*|Edit".

Stop

Triggered when the main Agent conversation ends. Can be used to prevent the main Agent from stopping and allow it to continue working.

Input Parameters

Parameter Description
session_id Current session ID
transcript_path Path to the current session’s message log file
permission_mode Current Agent running mode
hook_event_name Hook event name
stop_hook_active Whether the stop hook has been triggered. true means triggered, false means not triggered. Used to avoid infinite loops.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}

Output Parameters

JSON Format

When the following data structure is returned, Hawa Code will end normally:

{"ok": true}

When the following data structure is returned, Hawa Code will continue working, and reason will be sent to the model as the reason for continuing:

{"ok": false, "reason": "your explanation"}

Exit Code Format

  • Exit code 0: Success, Hawa Code will stop the task
  • Exit code 2: Failure, Hawa Code will continue working, and stderr will be sent to the model as the reason for continuing

Configuration Methods

Prompt Method

Configure the prompt using the $ARGUMENTS placeholder:

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

Command Method

Execute a shell script:

{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node ./hooks/stop.js"
}
]
}
]
}
}

Example script:

import * as fs from 'fs';
const input = fs.readFileSync(0, 'utf-8');
console.log({
"ok": false,
"reason": input + " Root cause analysis"
});

Configuration File Locations

  • Project Level: {project_path}/.hcode/settings.json
  • User Level: ~/.hcode/settings.json

SubagentStop

Triggered when the Subagent conversation ends. Can be used to prevent the Subagent from stopping and allow it to continue working.

Input Parameters

Parameter Description
session_id Current session ID
transcript_path Path to the current session’s message log file
permission_mode Current Agent running mode
hook_event_name Hook event name
stop_hook_active Whether the stop hook has been triggered. true means triggered, false means not triggered. Used to avoid infinite loops.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}

Output Parameters

JSON Format

When the following data structure is returned, Hawa Code will end normally:

{"ok": true}

When the following data structure is returned, Hawa Code will continue working, and reason will be sent to the model as the reason for continuing:

{"ok": false, "reason": "your explanation"}

Exit Code Format

  • Exit code 0: Success, Hawa Code will stop the task
  • Exit code 2: Failure, Hawa Code will continue working, and stderr will be sent to the model as the reason for continuing

Configuration Methods

Prompt Method

Configure the prompt using the $ARGUMENTS placeholder:

{
"hooks": {
"SubagentStop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if Hawa Code should stop: $ARGUMENTS. Check if all tasks are complete."
}
]
}
]
}
}

Command Method

Execute a shell script:

{
"hooks": {
"SubagentStop": [
{
"hooks": [
{
"type": "command",
"command": "node ./hooks/subagent-stop.js"
}
]
}
]
}
}

Example script:

import * as fs from 'fs';
const input = fs.readFileSync(0, 'utf-8');
console.log({
"ok": false,
"reason": input + " Root cause analysis"
});

Configuration File Locations

  • Project Level: {project_path}/.hcode/settings.json
  • User Level: ~/.hcode/settings.json

SubagentStart

Triggered before the Subagent starts execution. Unlike Stop and SubagentStop, the SubagentStart Hook does not prevent the Subagent from executing, but can provide suggestions or warnings to the Subagent through the model or shell scripts.

Input Parameters

The parameter format is consistent with SubagentStop. See SubagentStop Input Parameters for details.

Output Parameters

{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Please follow security guidelines: Do not access production databases"
}
}

Configuration Methods

Prompt Method

Provide suggestions to the Subagent through the model:

  • Use matcher to match Subagent names
  • Use pipe | to match multiple names, e.g., Explore|Test
  • Use * to match all Subagents
{
"hooks": {
"SubagentStart": [
{
"matcher": "Explore",
"hooks": [
{
"type": "prompt",
"prompt": "Review this subagent task: $ARGUMENTS. If the task description is vague or potentially dangerous, warn the user."
}
]
}
]
}
}

Command Method

Execute commands through shell scripts:

{
"hooks": {
"SubagentStart": [
{
"matcher": "code-reviewer",
"hooks": [
{
"type": "command",
"command": "node ./hooks/subagent-start.js"
}
]
}
]
}
}

Example script:

import * as fs from 'fs';

const input = fs.readFileSync(0, 'utf-8');
const output = {
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Please follow security guidelines: Do not access production databases. Input parameters: " + input
}
};

console.log(JSON.stringify(output));

PostToolUse

PostToolUse triggers immediately after a tool executes successfully. Supports the same matcher values as PreToolUse.

Common Matchers

  • Task - Subagent tasks
  • Bash - Shell commands
  • Glob - File pattern matching
  • Grep - Content search
  • Read - File reading
  • Edit - File editing
  • Write - File writing
  • WebFetch, WebSearch - Web operations

Configuration

Configure hooks in your settings file:

  • ~/.hcode/settings.json - User settings
  • .hcode/settings.json - Project settings

Basic Structure

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

matcher: Pattern for matching tool names, case-sensitive

  • Simple string: Exact match, e.g., Write only matches the Write tool
  • Regular expressions: Supports patterns like Edit|Write or Notebook.*
  • Wildcard: Use * to match all tools. You can also use an empty string "" or omit matcher.

hooks: Array of hooks to execute when the pattern matches

  • type: Hook execution type - "command" for bash commands
  • command: The bash command to execute
  • timeout: (Optional) How long the hook should run in seconds

PostToolUse in Plugin Hooks

Example plugin hook configuration:

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

Input Parameters

The exact schema for tool_input and tool_response depends on the tool.

{
"session_id": "abc123",
"transcript_path": "/Users/.../.hcode/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
},
"tool_use_id": "toolu_01ABC123..."
}

Field Descriptions

Field Type Description
session_id string Session unique identifier
transcript_path string Full path to the conversation JSON file
cwd string Current working directory when the hook was invoked
permission_mode string Current permission mode: "default", "plan", "acceptEdits", "dontAsk", or "bypassPermissions"
hook_event_name string Always "PostToolUse"
tool_name string Name of the executed tool (e.g., Write, Edit, Bash, etc.)
tool_input object Tool input parameters (varies by tool)
tool_response object Tool response result (varies by tool)
tool_use_id string Unique identifier for the tool invocation

Note: The exact schema for tool_input and tool_response depends on the specific tool.

Output Parameters / Decision Control

PostToolUse hooks can provide feedback to Hawa Code after tool execution.

  • "block": Block subsequent operations and prompt Hawa Code with reason
  • undefined: Do nothing. reason is ignored.
  • "hookSpecificOutput.additionalContext": Add additional context for Hawa Code
{
"decision": "block" | undefined,
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Hawa Code"
}
}

Field Descriptions

Field Type Description
decision string | undefined "block" to block and show reason, or undefined to do nothing
reason string Explanation for the decision
hookSpecificOutput object Hook-specific output information
hookSpecificOutput.hookEventName string Always "PostToolUse"
hookSpecificOutput.additionalContext string Additional context information for Hawa Code

Exit Code Behavior

Simple Exit Codes

Hooks communicate status through exit codes, stdout, and stderr:

  • Exit code 0: Success. stdout is shown to the user.
  • Exit code 2: Blocking error. Shows stderr to Hawa Code (tool has run). Format is [command]: {stderr}.
  • Other exit codes: Non-blocking error. Shown in stderr.

PostToolUse-Specific Exit Code 2 Behavior

Hook Event Behavior
PostToolUse Shows stderr to Hawa Code (tool has run)

PostToolUseFailure

PostToolUseFailure triggers when a tool execution fails. This event is triggered when a tool call throws an error or returns a failure result. Useful for logging failures, sending alerts, or providing corrective feedback to Hawa Code.

Matching: Matches by tool name, supports the same matcher values as PreToolUse.

Input Parameters

PostToolUseFailure hooks receive the same tool_name and tool_input fields as PostToolUse, along with error information as top-level fields:

Field Description
tool_name Tool name
tool_input Parameters sent to the tool
tool_use_id Unique identifier for the tool use
error String describing what went wrong
is_interrupt Optional boolean indicating if the failure was caused by user interruption

Input Example

{
"session_id": "abc123",
"transcript_path": "/Users/.../.hcode/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": {
"command": "npm test",
"description": "Run test suite"
},
"tool_use_id": "toolu_01ABC123...",
"error": "Command exited with non-zero status code 1",
"is_interrupt": false
}

Output Parameters / Decision Control

PostToolUseFailure hooks can provide context to Hawa Code after a tool failure. In addition to the JSON output fields available to all hooks, the following event-specific fields can be returned:

Field Description
additionalContext Additional context for Hawa Code to consider, provided along with the error message

Output Example

{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "Additional information about the failure for Hawa Code"
}
}

Exit Code Behavior

Exit Code Behavior
0 Success, parses JSON response from stdout
Non-zero Failure, hook output is ignored

SessionEnd

SessionEnd triggers when a Hawa Code session terminates. Suitable for cleanup tasks, logging session statistics, or saving session state.

Note: Since SessionEnd triggers when the session ends, it cannot block session termination and only supports type: "command" hooks.


Key Features

Attribute Description
Trigger Timing When session terminates
Can Block No - Cannot prevent session termination
Supported Hook Types Only command
Decision Control None - For side effects only (logging, cleanup, etc.)

Matcher Support

SessionEnd supports using matchers to filter by session end reason:

Matcher Trigger Timing
clear When using /clear command to clear session
other Other exit reasons (normal exit, abnormal exit, etc.)
* Match all end reasons

Input Parameters

Field Type Description
session_id string Session unique identifier
transcript_path string Full path to the conversation JSON file
cwd string Current working directory
permission_mode string Current permission mode
hook_event_name string Always "SessionEnd"
reason string Session end reason: "clear" or "other"

Input Example:

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

Output Parameters

SessionEnd hooks have no specific output requirements. The script’s stdout and stderr will be logged but will not affect the session termination process.


Configuration Examples

Basic Cleanup Hook (matches all end reasons)

{
"hooks": {
"SessionEnd": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "node ./hooks/session-end.js"
}
]
}
]
}
}

Script Example (./hooks/session-end.js):

const fs = require('fs');

// Read parameters from stdin
const input = fs.readFileSync(0, 'utf-8');
const params = JSON.parse(input);

const sessionId = params.session_id;
const reason = params.reason;

// Record session statistics
const stats = {
sessionId: sessionId,
endTime: new Date().toISOString(),
reason: reason,
transcriptPath: params.transcript_path
};

// Write statistics to log file
fs.appendFileSync(
'./logs/session-stats.log',
JSON.stringify(stats) + '\n'
);

console.error(`[SessionEnd] Session ${sessionId} ended, reason: ${reason}`);
process.exit(0);

Match Specific Exit Reason (only execute on /clear)

{
"hooks": {
"SessionEnd": [
{
"matcher": "clear",
"hooks": [
{
"type": "command",
"command": "rm -f /tmp/claude-scratch-*.txt"
}
]
}
]
}
}

Multiple Matcher Configuration

{
"hooks": {
"SessionEnd": [
{
"matcher": "clear",
"hooks": [
{
"type": "command",
"command": "echo 'Session cleared' >> ./logs/cleanup.log"
}
]
},
{
"matcher": "other",
"hooks": [
{
"type": "command",
"command": "node ./hooks/normal-exit.js"
}
]
}
]
}
}