Hooks

Hooks 配置

  • 项目级别{项目路径}/.hcode/settings.json
  • 用户级别~/.hcode/settings.json

Matcher

当前 Hook 支持 Matcher,用于匹配工具名称或 Subagent 名称。匹配规则如下:

  • 单一匹配:匹配单个属性,例如 "Edit"
  • 多个匹配:使用竖线 | 分隔多个属性,例如 "Edit|Write"
  • 通配符匹配:使用 * 进行通配匹配,例如 "mcp__memory__.*""mcp__.*__write.*""mcp__.*__write.*|Edit"

Stop

在主 Agent 对话结束时触发,可用于阻止主 Agent 结束并让其继续工作。

入参

参数名 说明
session_id 当前会话 ID
transcript_path 当前会话的消息记录文件路径
permission_mode 当前 Agent 运行模式
hook_event_name Hook 事件名称
stop_hook_active 是否已触发过停止 Hook,true 表示已触发,false 表示未触发,用于避免无限循环
{
"session_id": "abc123",
"transcript_path": "~/.Hawa Code/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}

出参

JSON 格式

返回以下数据结构时,Hawa Code 将正常结束:

{"ok": true}

返回以下数据结构时,Hawa Code 将继续工作,并将 reason 作为继续工作的原因发送给模型:

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

返回码格式

  • 退出代码 0:成功,Hawa Code 将停止任务
  • 退出代码 2:失败,Hawa Code 将继续工作,并将 stderr 作为继续工作的原因发送给模型

配置方式

Prompt 方式

通过 $ARGUMENTS 占位符配置 Prompt:

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

Command 方式

执行 Shell 脚本:

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

示例脚本:

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

SubagentStop

在 Subagent 对话结束时触发,可用于阻止 Subagent 结束并让其继续工作。

入参

参数名 说明
session_id 当前会话 ID
transcript_path 当前会话的消息记录文件路径
permission_mode 当前 Agent 运行模式
hook_event_name Hook 事件名称
stop_hook_active 是否已触发过停止 Hook,true 表示已触发,false 表示未触发,用于避免无限循环
{
"session_id": "abc123",
"transcript_path": "~/.Hawa Code/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}

出参

JSON 格式

返回以下数据结构时,Hawa Code 将正常结束:

{"ok": true}

返回以下数据结构时,Hawa Code 将继续工作,并将 reason 作为继续工作的原因发送给模型:

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

返回码格式

  • 退出代码 0:成功,Hawa Code 将停止任务
  • 退出代码 2:失败,Hawa Code 将继续工作,并将 stderr 作为继续工作的原因发送给模型

配置方式

Prompt 方式

通过 $ARGUMENTS 占位符配置 Prompt:

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

Command 方式

执行 Shell 脚本:

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

示例脚本:

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

SubagentStart

在 Subagent 开始执行前触发。与 Stop 和 SubagentStop 不同,SubagentStart Hook 不会阻止 Subagent 执行,但可以通过模型或 Shell 脚本向 Subagent 提供建议或警告。

入参

参数格式与 SubagentStop 一致,详见 SubagentStop 入参

出参

{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "请遵循安全规范:禁止访问生产环境数据库"
}
}

配置方式

Prompt 方式

通过模型向 Subagent 提供建议:

  • 使用 matcher 匹配 Subagent 名称
  • 使用竖线 | 匹配多个名称,如 Explore|Test
  • 使用 * 匹配所有 Subagent
{
"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 方式

通过 Shell 脚本执行命令:

{
"hooks": {
"SubagentStart": [
{
"matcher": "Explore",
"hooks": [
{
"type": "command",
"command": "node D:/Javaworks/hawa-code/hooks/SubagentStart.js"
}
]
}
]
}
}

示例脚本:

import * as fs from 'fs';

const input = fs.readFileSync(0, 'utf-8');
const output = {
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "请遵循安全规范:禁止访问生产环境数据库。输入参数: " + input
}
};

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

PostToolUse

PostToolUse 在工具成功执行后立即触发,支持使用与 PreToolUse 相同的匹配器值。

常见匹配器

  • Task - Subagent 任务
  • Bash - Shell 命令
  • Glob - 文件模式匹配
  • Grep - 内容搜索
  • Read - 文件读取
  • Edit - 文件编辑
  • Write - 文件写入
  • WebFetchWebSearch - Web 操作

配置方式

在设置文件中配置 Hooks:

  • ~/.hcode/settings.json - 用户级设置
  • .hcode/settings.json - 项目级设置

基本结构

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

matcher:用于匹配工具名称的模式,区分大小写

  • 简单字符串:精确匹配,如 Write 仅匹配 Write 工具
  • 正则表达式:支持 Edit|WriteNotebook.* 等模式
  • 通配符:使用 * 匹配所有工具,也可使用空字符串 "" 或省略 matcher

hooks:模式匹配时执行的 hooks 数组

  • type:Hook 执行类型,"command" 表示执行 bash 命令
  • command:要执行的 bash 命令
  • timeout:(可选)hook 执行超时时间(秒)

插件 Hooks 中的 PostToolUse

示例插件 hook 配置

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

输入参数

tool_inputtool_response 的具体格式取决于工具类型。

{
"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..."
}

字段说明

字段 类型 说明
session_id string 会话唯一标识符
transcript_path string 对话 JSON 文件的完整路径
cwd string 调用 hook 时的当前工作目录
permission_mode string 当前权限模式:"default""plan""acceptEdits""dontAsk""bypassPermissions"
hook_event_name string 固定为 "PostToolUse"
tool_name string 被执行的工具名称(如 WriteEditBash 等)
tool_input object 工具的输入参数(因工具而异)
tool_response object 工具的响应结果(因工具而异)
tool_use_id string 工具调用的唯一标识符

注意tool_inputtool_response 的具体格式取决于工具类型。

输出参数 / 决策控制

PostToolUse hooks 可在工具执行后向 Hawa Code 提供反馈。

  • "block":阻止后续操作,并使用 reason 提示 Hawa Code
  • undefined:不执行任何操作,reason 被忽略
  • "hookSpecificOutput.additionalContext":为 Hawa Code 添加额外上下文
{
"decision": "block" | undefined,
"reason": "决策说明",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "提供给 Hawa Code 的额外信息"
}
}

字段说明

字段 类型 说明
decision string | undefined "block" 表示阻止并提示原因,undefined 表示不执行任何操作
reason string 决策的解释说明
hookSpecificOutput object hook 特定的输出信息
hookSpecificOutput.hookEventName string 固定为 "PostToolUse"
hookSpecificOutput.additionalContext string 为 Hawa Code 添加的额外上下文信息

退出码行为

简单退出码

Hooks 通过退出码、stdout 和 stderr 传达状态:

  • 退出码 0:成功,stdout 显示给用户
  • 退出码 2:阻止错误,向 Hawa Code 显示 stderr(工具已执行),格式为 [command]: {stderr}
  • 其他退出码:非阻止错误,stderr 中显示

PostToolUse 特定的退出码 2 行为

Hook 事件 行为
PostToolUse 向 Hawa Code 显示 stderr(工具已执行)

PostToolUseFailure

PostToolUseFailure 在工具执行失败时触发。当工具调用抛出错误或返回失败结果时,此事件会被触发。可用于记录失败日志、发送警报或向 Hawa Code 提供纠正性反馈。

匹配方式:按工具名称匹配,支持使用与 PreToolUse 相同的匹配器值。

输入参数

PostToolUseFailure hooks 接收与 PostToolUse 相同的 tool_nametool_input 字段,以及作为顶层字段的错误信息:

字段 说明
tool_name 工具名称
tool_input 发送给工具的参数
tool_use_id 工具使用的唯一标识符
error 描述出错原因的字符串
is_interrupt 可选布尔值,指示失败是否由用户中断引起

输入示例

{
"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
}

输出参数 / 决策控制

PostToolUseFailure hooks 可在工具失败后向 Hawa Code 提供上下文。除所有 hooks 共有的 JSON 输出字段外,还可返回以下事件特定字段:

字段 说明
additionalContext 供 Hawa Code 考虑的额外上下文,与错误信息一并提供

输出示例

{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "关于失败的其他信息"
}
}

退出码行为

退出码 行为
0 成功,解析 stdout 中的 JSON 响应
非零 失败,忽略 hook 输出

SessionStartHook

SessionStart 在 Hawa Code 启动新会话或恢复现有会话时触发。适用于加载开发上下文(如待处理的问题或代码库的最近更改),或设置环境变量。

注意:对于不需要脚本的静态上下文,建议使用 HAWA.md。由于 SessionStart 在每个会话都会运行,请确保 hooks 执行快速高效。


Matcher 支持

SessionStart 支持 matcher,用于匹配不同的会话启动方式:

Matcher 触发时机
startup 新会话启动时
resume 使用 --resume--continue/resume 恢复会话时
clear 执行 /clear
compact 自动或手动压缩对话后

输入参数

除通用输入字段外,SessionStart hooks 还接收以下字段:

字段 说明
source 会话启动方式:"startup"(新会话)、"resume"(恢复会话)、"clear"/clear 后)、"compact"(压缩后)
model 当前使用的模型标识符
agent_type 可选,Agent 类型

输入示例:

{
"session_id": "abc123",
"transcript_path": "/Users/.../.hcode/projects/.../dakabxi.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"source": "startup",
"model": "kimi-k2.5"
}

输出参数

Hook 脚本输出到 stdout 的内容将作为上下文添加到 Claude。除通用 JSON 输出字段外,还可返回以下专用字段:

字段 说明
additionalContext 要添加到 Claude 上下文的字符串,多个 hooks 的值会拼接在一起

JSON 输出示例:

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

配置

Hook 处理器字段

通用字段(所有 hook 类型)

字段 必需 说明
type Hook 类型:"command""prompt""agent"
timeout 超时时间(秒)。默认值:command 为 600,prompt 为 30,agent 为 60
statusMessage Hook 运行时显示的自定义 spinner 消息

Command Hook 专用字段

字段 必需 说明
command 要执行的 shell 命令
async 设为 true 时在后台运行,不阻塞会话启动

Prompt Hook 专用字段

字段 必需 说明
prompt 发送给模型的提示文本,使用 $ARGUMENTS 作为 hook 输入 JSON 的占位符
model 用于评估的模型,默认为快速模型

配置示例

1. Command Hook(命令类型)

{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "node ./scripts/test.js",
"timeout": 600
}
]
}
]
}
}

脚本示例./scripts/test.js):

function testAddContext() {
const result = {
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "会话已启动,当前项目使用 Node.js 技术栈,主要目录包括 src、tests 和 docs。"
}
};
console.log(JSON.stringify(result));
}
testAddContext();

2. Prompt Hook(提示类型)

Prompt Hook 将提示发送给模型进行单轮评估,模型返回的 JSON 可作为决策依据,适用于需要 LLM 判断的场景。

{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "prompt",
"prompt": "Analyze the current project structure and provide a brief summary of the main technologies used. Input: $ARGUMENTS",
"timeout": 30
}
]
}
]
}
}

后台运行 Hooks

Command Hook 支持 async 字段,设为 true 时 hook 将在后台运行,不会阻塞会话启动。

{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "./scripts/background-task.sh",
"async": true
}
]
}
]
}
}

SessionEnd

SessionEnd 在 Hawa Code 会话终止时触发。适用于执行清理任务、记录会话统计信息或保存会话状态。

注意:由于 SessionEnd 在会话终止时触发,它无法阻塞会话结束,仅支持 type: "command" 类型的 hook。


关键特性

属性 说明
触发时机 会话终止时
能否阻塞 - 无法阻止会话终止
支持的 Hook 类型 仅支持 command
决策控制 无 - 仅用于副作用(日志记录、清理等)

Matcher 支持

SessionEnd 支持使用 matcher 按会话结束原因进行过滤:

Matcher 触发时机
clear 使用 /clear 命令清除会话时
other 其他退出原因(正常退出、异常退出等)
* 匹配所有结束原因

输入参数

字段 类型 说明
session_id string 会话唯一标识符
transcript_path string 对话 JSON 文件的完整路径
cwd string 当前工作目录
permission_mode string 当前权限模式
hook_event_name string 固定为 "SessionEnd"
reason string 会话结束原因:"clear""other"

输入示例:

{
"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"
}

输出参数

SessionEnd hook 无特定输出要求。脚本的标准输出和错误输出将被记录,但不会影响会话终止流程。


配置示例

基础清理 Hook(匹配所有结束原因)

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

脚本示例./hooks/session-end.js):

const fs = require('fs');

// 从标准输入读取参数
const input = fs.readFileSync(0, 'utf-8');
const params = JSON.parse(input);

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

// 记录会话统计信息
const stats = {
sessionId: sessionId,
endTime: new Date().toISOString(),
reason: reason,
transcriptPath: params.transcript_path
};

// 将统计信息写入日志文件
fs.appendFileSync(
'./logs/session-stats.log',
JSON.stringify(stats) + '\n'
);

console.error(`[SessionEnd] 会话 ${sessionId} 已结束,原因: ${reason}`);
process.exit(0);

匹配特定退出原因(仅在 /clear 时执行)

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

多 Matcher 配置

{
"hooks": {
"SessionEnd": [
{
"matcher": "clear",
"hooks": [
{
"type": "command",
"command": "echo '会话被清除' >> ./logs/cleanup.log"
}
]
},
{
"matcher": "other",
"hooks": [
{
"type": "command",
"command": "node ./hooks/normal-exit.js"
}
]
}
]
}
}