Skip to content
源码分析手册

InstructionsLoaded:角色与约束的动态注入

在 Claude Code 的启动或重置过程中,InstructionsLoaded 钩子扮演着“灵魂注入”的角色。它允许开发者根据当前项目、环境或任务,动态地为模型生成系统指令(System Instructions)。

先搞清楚这是什么

InstructionsLoaded 本质上是 系统 Prompt 的动态生成器(System Prompt Generator)

它解决了静态指令文件的局限性。虽然 CLAUDE.md 可以提供项目规范,但 InstructionsLoaded 可以提供更具时效性的约束。它不是对对话内容的拦截(那是 UserPromptSubmit 的职责),它专注于“你现在应该扮演什么角色”以及“你应该遵循哪些特殊的临时规则”。

例如:根据当前是星期几、当前所在的 Git 分支名、或者是当前服务器的负载状态,动态地向模型解释当前的执行上下文。

代码里的真实逻辑

该钩子的运行逻辑紧密结合了系统的初始化流程:

  1. 触发点:系统在每次会话开始、上下文压缩(Compact)完成或手动触发重载时,会重新加载所有指令源。在 CLAUDE.md 等静态文件读取完毕后,系统派发 InstructionsLoaded 事件。
  2. 输入上下文:钩子接收到 InstructionsLoadedHookInput,其中包含了目前已加载的所有静态指令内容。
  3. 动态增强(Augmentation): 钩子可以利用其 Shell 执行能力,实时获取外部信息(如调用 API、读取环境变量),然后通过 HookJSONOutput 回传:
    • 追加指令:向模型的 System Prompt 中添加一段自定义的文字。
    • 覆盖约束:通过更精确的提示词,微调模型在当前会话中的行为边界。
  4. 注入时机(Pre-inference): 注入的指令在首轮用户 Prompt 发送前就已经合并到了 System Prompt 视图中。这意味着模型在“睁眼”的第一时间,就已经被这些动态规则所约束。

踩坑指南

  • Token 成本:动态注入的每一行指令都会持续占据上下文窗口。应避免在钩子中注入大量冗余的文档内容。
  • 非实时性:一旦指令加载完成并开启了对话,后续的 InstructionsLoaded 只有在触发 /compact 或重启会话时才会再次运行。它不是针对每一轮对话都重新生成的。
  • 优先级:通常作为静态指令的补充。CLAUDE.md 存放长期不变的规范,InstructionsLoaded 存放随环境变化的上下文。
  • 与 SessionStart 的关系SessionStart 通常用于注入消息流,而 InstructionsLoaded 专门用于注入 System Instructions。

接下来看什么

源码锚点

  • claude-code-opensource/src/utils/claudemd.ts — 指令加载的主逻辑及其对 InstructionsLoaded 的集成。
📄 src/utils/claudemd.ts — 指令加载的主逻辑及其对 `InstructionsLoaded` 的集成。L70-75 of 1480
typescript
  executeInstructionsLoadedHooks,
  hasInstructionsLoadedHook,
  type InstructionsLoadReason,
  type InstructionsMemoryType,
} from './hooks.js'
import type { MemoryType } from './memory/types.js'
  • claude-code-opensource/src/types/hooks.tsInstructionsLoadedHookInput 结构定义。
📄 src/types/hooks.ts — `InstructionsLoadedHookInput` 结构定义。L22-24 of 291
typescript
export function isHookEvent(value: string): value is HookEvent {
  return HOOK_EVENTS.includes(value as HookEvent)
}

基于 Claude Code v2.1.88 开源快照的深度分析