跳到正文
FunCoding

搜索

搜索文档、智能体、博客、Skill 和 MCP

会话与提示事件

SessionStart、Setup、InstructionsLoaded、UserPromptSubmit、UserPromptExpansion、MessageDisplay 六个事件的触发时机、输入字段和输出控制。

下面每个事件都会收到通用输入字段,这里只列该事件额外的字段。「决策控制」说明输出里哪些字段有效;多数事件之外的通用 JSON 字段(continue、stopReason、systemMessage、terminalSequence)是否被采纳也在各事件里注明。

SessionStart

新会话开始或恢复已有会话时运行,适合加载开发上下文(现有 issue、近期改动)或设置环境变量;不需要脚本的静态上下文改用 CLAUDE.md。每个会话都会运行,保持 Hook 很快。只支持 command 和 mcp_tool 类型的 Hook。matcher 取会话来源:

matcher触发
startup新会话
resume--resume、--continue 或 /resume
clear/clear
compact自动或手动压缩
fork从已有会话分叉出的新会话(--fork-session、/fork、/branch、移到后台的对话)

交互式启动、用 --continue/--resume 恢复或 /clear 时,SessionStart Hook 在后台运行,你可以立刻输入;在会话内用 /resume 切换对话则要等 Hook 结束;启动时等待期间发送的提示要等 Hook 完成才会到达 Claude(等待期间按 Esc 可取回提示)。输入字段:source;可选的 model(/clear 之后或会话经对话恢复时可能缺失,读取前先检查)、agent_type(用 claude --agent 启动时)、session_title(设置了自定义标题时)。source 为 resume 或 fork 且转录里至少有一次 Claude 回复时,还会收到 seconds_since_last_response、context_tokens(恢复后第一次请求重新发送的 token 数)、prompt_cache_likely_expired、estimated_cache_write_usd,让 Hook 能在第一次请求之前告知恢复一个陈旧对话的成本。

决策控制:退出 0 时被当作纯文本的 stdout 会加到 Claude 的上下文,所以只加载上下文的 Hook 直接打印即可;需要组合其他字段时用 JSON:

字段说明
additionalContext加到对话开头、第一个提示之前的上下文字符串
initialUserMessage作为会话第一条用户消息;适用于 -p 非交互模式(即使没有提示它也成为第一轮,有提示则随后跟上)
sessionTitle设置会话标题,效果同 /rename;source 为 startup/resume/fork 时有效,clear 和 compact 时忽略
watchPaths本会话里供 FileChanged 监视的绝对路径数组
reloadSkills为 true 时 SessionStart Hook 完成后重新扫描 Skill 和命令目录,让 Hook 刚装好的 Skill 在同一会话从第一个提示起就可用

持久化环境变量:SessionStart、Setup、CwdChanged、FileChanged Hook 可以使用环境变量 CLAUDE_ENV_FILE,它提供一个文件路径,往里写 export 语句即可让变量对该会话后续的 Bash 命令持久生效(用追加 >> 以保留其他 Hook 设置的变量;也可以对比 setup 命令前后的环境导出整个变化)。其他类型的 Hook 没有这个变量。

Setup

只在你用 --init-only,或在非交互 -p 模式下用 --init/--maintenance 启动时触发,正常启动不触发;用于需要显式从 CI 或脚本触发的一次性依赖安装或定期清理,每个会话的初始化仍用 SessionStart。matcher 对应触发它的 CLI 标志:init(claude --init-only 或 claude -p --init)、maintenance(claude -p --maintenance)。--init-only 会先运行 Setup Hook 和 startup matcher 的 SessionStart Hook,然后不开始对话就退出,成功时终端不输出任何东西(想确认就用 --debug-file 看日志)。因为 Setup 并非每次启动都触发,需要依赖的插件不能只靠它,常见做法是首次使用时检查依赖、缺失时安装。输入:trigger("init" 或 "maintenance")。不能阻塞,任何退出码都继续,并丢弃 JSON 输出字段;只运行 type: "command" 的 Hook,可使用 CLAUDE_ENV_FILE。

InstructionsLoaded

CLAUDE.md 或 .claude/rules/*.md 被加载进上下文时触发:会话开始时对立即加载的文件触发,之后懒加载时再次触发(例如 Claude 访问含嵌套 CLAUDE.md 的子目录、或带 paths: 前置信息的条件规则命中)。异步运行,仅用于可观测性,不支持阻塞或决策控制。Claude 直接读取 AGENTS.md 时不触发;CLAUDE.md 导入 AGENTS.md 时会触发,load_reason 为 include。matcher 对 load_reason 生效(如 session_start,或 path_glob_match|nested_traversal 只匹配懒加载)。输入字段:file_path(加载的指令文件绝对路径)、memory_type(User/Project/Local/Managed)、load_reason(session_start、nested_traversal、path_glob_match、include、compact)、globs(paths: 前置信息里的 glob,仅 path_glob_match)、trigger_file_path(触发懒加载的文件)、parent_file_path(include 时的父指令文件)。适合做审计日志和合规追踪。

UserPromptSubmit

用户提交提示后、Claude 处理之前运行:可以基于提示或对话添加上下文、校验提示、阻止某些类型的提示。默认超时 30 秒(command、http、mcp_tool),比多数事件的 600 秒短,因为它在每个提示前运行并阻塞模型处理,卡住的 Hook 会让会话停摆;超时的(非 async: true)Hook 被取消,其输出(含 additionalContext)被丢弃,提示照常继续。Agent SDK 的回调 Hook 超时则会阻塞该提示,因为回调可能充当不能「失败放行」的策略门。输入:prompt(用户提交的文本;折叠成 [Pasted text #N] 占位符的粘贴内容会就地展开),以及有自定义标题时的 session_title。决策控制:退出 0 时有两种添加上下文的方式——纯文本 stdout,或 JSON 的 additionalContext;二者都被注入为以 Hook 名开头的系统提醒,不产生可见的转录条目。阻止提示:

字段说明
decision"block" 在提示到达 Claude 之前阻止;省略则放行
reasondecision 为 block 时显示给用户,不加入上下文
additionalContext与提交的提示一起加入 Claude 上下文的字符串
sessionTitle设置会话标题,可据提示内容自动命名
suppressOriginalPrompt为 true 且 Hook 阻止提示时,阻止消息里不再附带原始提示文本

退出 2 阻止时,stderr 文本同样显示给用户而不进入上下文。被阻止的提示不会彻底消失:默认阻止消息以 Original prompt: 结尾并附上提交的文本,且 Claude Code 把该消息写进会话转录文件;suppressOriginalPrompt 只改变阻止消息,提交的文本仍可能出现在本地转录和提示历史里,所以阻止型 Hook 不是把秘密挡在磁盘之外的办法。

UserPromptExpansion

用户输入的命令展开成提示、到达 Claude 之前触发:可以阻止特定命令被直接调用、为某个 Skill 注入上下文、记录用户调用了哪些命令(例如匹配 deploy 的 Hook 可在没有审批文件时阻止 /deploy,匹配评审 Skill 的 Hook 可附上团队的评审清单作为 additionalContext)。它覆盖 PreToolUse 覆盖不到的路径:匹配 Skill 工具的 PreToolUse 只在 Claude 调用该工具时触发,而你直接键入 /skillname 会绕过它,UserPromptExpansion 正是触发于这条直接路径。matcher 匹配 command_name,留空则对每个提示型命令触发。输入:expansion_type、command_name、command_args、command_source 和原始 prompt。决策控制:decision: "block"(阻止展开,reason 显示给用户)和 additionalContext;退出 2 同样阻止,stderr 显示给用户。

MessageDisplay

助手消息流式显示到屏幕时运行:每当一批新完成的行准备渲染,Hook 就针对这批行运行一次,Claude Code 用 Hook 的替换文本取代它们。用途:去掉 Markdown 做极简显示;转换 Agent SDK 应用展示给用户的文本;脱敏 Claude 回复里的 API Key 或内部主机名。Claude Code 会等每批的 Hook 返回,所以要保持快速;Hook 失败或超时则显示原文;默认超时 10 秒。它只影响显示:转录和 Claude 看到的仍是原文,Claude 永远看不到替换文本,详细模式也显示原文。不支持 matcher,对每条流式输出文本的助手消息触发(纯工具调用的消息不触发)。非交互运行(含 Agent SDK 查询和 claude -p)里,它每条助手消息只运行一次,在消息完成后收到完整消息。输入:turn_id、message_id(该条消息所有批次里稳定,不是 API 的 msg_… id)、index(批次序号,从 0 开始)、final(是否最后一批)、delta(自上一批以来新完成的行,含换行;总是整行,最后一批可能在行中间结束)。输出:hookSpecificOutput.displayContent 替换屏幕上的 delta,省略则显示原文;无决策控制,systemMessage 等被丢弃。示例(去掉粗体与行内代码标记):

#!/bin/bash
jq '{hookSpecificOutput: {hookEventName: "MessageDisplay", displayContent: (.delta | gsub("\\*\\*"; "") | gsub("`"; ""))}}'

脚本失败(如缺少 jq)时显示原文,失败只记录在调试输出里。