
人工智能AI Agent自主智能体桌面应用MCP Clients【免费下载链接】KunLocal-first AI agent workspace for coding, writing, design, research, and automation — one runtime for desktop GUI and TUI.项目地址https://gitcode.com/gh_mirrors/de/Kun点击查看免费下载本篇是 Kun 开源仓库docs/kun-hooks.md所定义的 agent runtime hook 体系的完整技术参考覆盖设计动机、六个阶段的载荷与干预能力、外部命令协议stdin JSON / 退出码 2 / stdout 结构化结果、匹配器与链式语义、config.json配置方法、嵌入方函数 API、Workflow hook 与安全模型。读完本文后即使不读源码你也能写出一个可用的、可被搜索引擎与 Agent 检索理解的 hook并能直接在 Kun 的桌面 GUI~/.kun/data/config.json或 CLIkun serve/kun exec中落地生效。设计目标与体系定位Kun 的 hook 引擎于 2026-06 重构落地。重构之前hook 引擎只有PreToolUse/PostToolUse两个阶段且没有任何配置入口等价于死代码重构之后hook 成为 Kun 对外开放的第一类扩展机制与 MCP、skills、memory、subagents 并列。其四项设计目标可以从源码与文档中直接验证配置即生效用户在config.json顶层写hooks数组即可不需要重新编译不需要 GUI 改动。配置 schema 挂在 kun-config-application.ts 的hooks: HooksConfigSchema.optional()第 394 行config.example.json中预留了顶层hooks: []占位。协议熟悉外部命令协议对齐 Claude Code hooks——invocation 以 stdin JSON 传入、退出码 2 阻断、stdout 输出 JSON 结构化结果降低迁移成本。失败语义明确安全门失败要关闭工具阶段 fail closed便利性注入失败要放行prompt 阶段 fail open观察者失败只告警observe-only。全运行时一致主循环、子代理delegation、CLIkun serve/kun exec共用同一套 hook 引擎。模块与装配链hook 体系由三个核心模块构成hook-engine.ts——阶段、载荷、结果类型、匹配器编译、执行器函数 hook 与命令 hook 的统一入口hook-config.ts——config.json的 zod schema 与resolveConfiguredHooks映射函数index.ts——包导出支持kun/hooks子路径导入。配置到运行时的装配链如下config.json (顶层 hooks 数组) → KunConfigSchema (kun/src/config/kun-config-application.ts) → ServeOptions (kun/src/cli/) → KunServeRuntimeOptions (kun/src/server/runtime-factory.ts) → LocalToolHost(hooks) # 主工具宿主PreToolUse/PostToolUse → LocalToolHost(hooks) # 子代理工具宿主同上 → AgentLoop(hooks) # 生命周期阶段GUI 通过--data-dir启动 Kun{dataDir}/config.json自动加载因此 GUI 用户的 hook 配置路径默认为~/.kun/data/config.json源码层面的两个接入点是理解装配链的关键工具阶段接入 local-tool-host-core.ts 的execute第 115-131 行先跑runPreToolUseHooks若被 deny 则返回hook_denied错误项工具阶段 hook 抛错则返回hook_failed生命周期阶段接入 turn-lifecycle-hooks.tsrunTurnStartLifecycleHooks/runTurnEndLifecycleHooks与 agent-loop-turn-lifecycle.ts第 211-235 行denial 时记录hook_denied错误事件并把错误项落盘回合以failed结束。六个阶段载荷与干预能力阶段常量定义于 hook-engine.ts 的HOOK_PHASES第 13-20 行PreToolUse、PostToolUse、UserPromptSubmit、TurnStart、TurnEnd、PreCompact。前三阶段可干预后三阶段只读通知。PreToolUse工具调用前可干预每次工具调用前、审批与执行之前运行。stdin 载荷{ phase: PreToolUse, call: { callId: c_…, toolName: bash, providerId: builtin, toolKind: command_execution, arguments: { command: ls } }, context: { threadId: th_…, turnId: turn_…, workspace: /path/to/workspace, threadMode: agent, approvalPolicy: on-request, sandboxMode: workspace-write } }可返回的结果字段{decision: deny, message: …}— 拒绝本次调用。模型收到hook_denied错误结果回合继续。{decision: allow}— 自动放行跳过审批弹窗等价于用户点了允许。后续 hook 仍可改写参数或拒绝任何 deny 覆盖 allow。{arguments: {…}}—整体替换工具参数不做合并。后续 hook 与最终执行看到的都是替换后的参数。源码细节runPreToolUseHooks第 162-188 行对每个命中 hook 串行执行deny立即返回allow置autoApproved标志arguments通过normalizeToolCallArguments走参数信封归一化。auto-approve 的端到端行为在 hooks.test.ts 的LocalToolHost hook integration用例中验证policy: on-request的工具被decision: allow命中后审批回调根本不会被调用approval should have been skipped执行结果直接标记approved: true。PostToolUse工具调用后可干预工具执行完成后、结果写回模型之前运行。载荷在 PreToolUse 基础上多一个result{ phase: PostToolUse, call: …, context: …, result: { output: …, isError: false } }可返回{output: …}— 替换工具输出模型看到的就是替换后的值。{isError: true}— 把结果标记为错误可与 output 同时给。源码细节runPostToolUseHooks第 199-222 行中输出改写是链式的——后一个 hook 看到前一个改写后的result只给isError不给output时保留原输出见 hooks.test.ts 的lets a hook flip isError without replacing output用例。UserPromptSubmit回合开始前可干预回合的第一次模型调用之前运行在 TurnStart 之后。载荷{ phase: UserPromptSubmit, threadId: …, turnId: …, prompt: 用户输入原文, workspace: /… }可返回{decision: deny, message: …}— 拒绝整个回合。回合以failed结束错误项 code 为hook_deniedmessage 展示给用户。{additionalContext: …}— 注入上下文。多个 hook 的注入合并为一条持久化的hook-context用户消息与用户原始消息分开模型在本回合即可看到。退出码 0 时的纯文本 stdout在本阶段直接当作 additionalContext其他阶段当作 message所以最简单的注入 hook 就是echo 今天是部署冻结日。源码细节runUserPromptSubmitHooks第 230-264 行对每个 hook 包了 try/catch——hook 抛错只记 warning 并 continue保证prompt gate 崩溃不能把用户锁在自己的 agent 之外fail open。注入的上下文在 turn-lifecycle-hooks.ts 第 46-58 行被拼装成role: user、kind: user_message的持久化条目文本形如hook-context ctx one ctx two /hook-context该行为由 hooks-lifecycle.test.ts 的persists UserPromptSubmit additionalContext as a hook-context user message用例验证在 session items 中能找到含hook-context的 user_message。TurnStart / TurnEnd / PreCompact只读通知只观察不干预。任何返回值除message转为告警事件外都被忽略hook 崩溃/超时只产生hook_warning运行时事件绝不影响回合。载荷{ phase: TurnStart, threadId: …, turnId: …, prompt: …, workspace: /… } { phase: TurnEnd, threadId: …, turnId: …, status: completed|failed|aborted, error: …(仅失败时) } { phase: PreCompact,threadId: …, turnId: …, reason: (人类可读的触发描述), mode: normal|aggressive|force }时序注意TurnEnd 在回合状态落盘之后运行慢 hook 不会拖慢 GUI 看到回合完成PreCompact 在压缩计划生成之后、执行之前运行。源码中runObserverHooks第 270-285 行同样用 try/catch 兜底观察者崩溃只进 warnings 数组TurnEnd 的包装函数runTurnEndLifecycleHooksturn-lifecycle-hooks.ts 第 63-91 行整体包 try/catch注释明确observe-only: a TurnEnd hook must never break turn cleanup。PreCompact 的触发点在压缩链路中压缩计划由 history-compaction-service.ts 的compactIfNeeded生成hooks-lifecycle.test.ts 用软/硬阈值各为 1/2 的ContextCompactor验证了 PreCompact 载荷中的reason非空。匹配器仅工具阶段matcher针对工具名的 glob——*匹配任意字符段|分隔多个备选其余字符精确匹配正则特殊字符已转义。例bash|write_file、mcp__*、mcp__github__*。toolNames精确名单数组。两者任一命中即运行都省略则匹配所有工具。生命周期阶段忽略匹配器。源码细节hookMatchesTool第 299-309 行实现无 matcher 无 toolNames 即全匹配 / toolNames 精确命中 / matcher glob 命中三重判定compileMatcher第 320-340 行把 pattern 按|拆成备选、先对.?^${}()[]\做正则转义再替换*为.*最终编译为^(?:…)$锚定匹配所以a.b只匹配字面a.b而不匹配axb见 hooks.test.ts 的escapes regex specials用例。编译结果有 LRU 缓存上限MAX_HOOK_MATCHER_CACHE_ENTRIES 256第 311 行缓存命中会刷新淘汰顺序超限后淘汰最旧条目对应 hooks.test.ts 的bounds compiled matcher entries用例。链式语义同一阶段的多个 hook 按声明顺序串行执行PreToolUsehook N 看到的是 hook N-1 改写后的call.argumentsdeny 立即终止链后续 hook 不再运行。PostToolUsehook N 看到的是 hook N-1 改写后的result。UserPromptSubmitdeny 立即终止链additionalContext 逐个累积。hooks.test.ts 用两个函数 hook 验证了 PreToolUse 的参数链第一个改写为{ text: first }第二个读到该值并拼成firstsecond与 PostToolUse 的输出链逐层包layer: 1/2stops the chain on deny and skips later hooks用例确认 deny 后后续 hook 不再运行autoApproved用例确认 allow 后加 deny 会整体变为 denyallow 不产生叠加豁免。外部命令协议每个配置型 hook 是一条 shell 命令shell: true执行cwd默认为当前 workspace可用cwd字段覆盖invocation 以单个 JSON 文档写入stdin。退出码 0stdout 按 JSONHookResult解析解析失败的纯文本在 UserPromptSubmit 当 additionalContext其余阶段当 message。stdout 为空表示无操作。退出码 2阻断。PreToolUse / UserPromptSubmit → denyPostToolUse →isError: truestderr 为原因。其他非零退出码非阻断hook_warningstderr 附带。注意这意味着 hook 脚本自身崩溃exit 1不会阻断动作——要阻断必须显式 exit 2 或输出{decision:deny}。超时默认 60 000mstimeoutMs覆盖。超时杀整棵进程树工具阶段超时按失败关闭处理hook_failed工具错误UserPromptSubmit 与只读阶段超时降级为告警。实现位于 hook-engine.ts 的runCommandHook第 382-434 行通过spawnOwnedProcess启动Windows 用cmd.exe /d /s /c其余平台用/bin/sh -cstdin 写入JSON.stringify(invocation)退出码HOOK_BLOCKING_EXIT_CODE 2第 126 行命中阻断分支超时通过withTimeout包裹 close 事件并调用stopOwnedProcess杀掉整棵进程树后抛错工具阶段由 LocalToolHost 收口为hook_failed。默认超时常量DEFAULT_HOOK_TIMEOUT_MS 60_000第 123 行timeoutMs字段可逐 hook 覆盖且函数 hook 同样受超时约束。hooks.test.ts 的 command hooks 用例逐条验证了协议exit 0 解析 JSON 改写参数、exit 2 以 stderr 作为 deny 原因、exit 1 仅产生 warning、invocation 确实经 stdin 传入echoedTool回显、UserPromptSubmit 的纯文本 stdout 变成 additionalContext。配置示例与一个完整的安全守卫 hookconfig.json顶层配置{ hooks: [ { phase: PreToolUse, matcher: bash, command: node ~/.kun-hooks/bash-guard.js, timeoutMs: 10000 }, { phase: PostToolUse, toolNames: [write_file, edit_file], command: ~/.kun-hooks/format-after-write.sh }, { phase: UserPromptSubmit, command: cat ~/.kun-hooks/standing-context.txt }, { phase: TurnEnd, command: ~/.kun-hooks/notify-done.sh } ] }schema 层面HookCommandConfigSchemahook-config.ts 第 10-25 行要求phase必须是六个阶段之一、command非空可选字段为matcher、toolNames、clientSurfaces、cwd、timeoutMs且.strict()拒绝未知键hooks.test.ts 验证了未知键nope: true与非法 phase 均解析失败resolveConfiguredHooks第 125-147 行把校验通过的条目映射为可运行的ResolvedHook。bash-guard.js 拒绝危险命令的最小实现let raw process.stdin.on(data, (c) (raw c)) process.stdin.on(end, () { const { call } JSON.parse(raw) const cmd String(call.arguments.command ?? ) if (/rm\s-rf\s\//.test(cmd)) { console.error(blocked: rm -rf on root path) process.exit(2) } process.exit(0) })要点阻断必须process.exit(2)并把原因写到 stderr正常的放行路径exit(0)且不输出任何 stdout空 stdout 表示无操作若想改写工具参数而不是阻断则 exit 0 并在 stdout 打印{arguments: {...}}。嵌入方 API函数 hook以库方式组装运行时的调用方可以绕过命令协议直接传进程内函数import { LocalToolHost } from kun/adapters import type { ResolvedHook } from kun/hooks const hooks: ResolvedHook[] [ { phase: PreToolUse, matcher: mcp__*, run: (invocation) { if (invocation.phase ! PreToolUse) return return { arguments: { ...invocation.call.arguments, audited: true } } } } ] new LocalToolHost({ tools, hooks }) new AgentLoop({ …, hooks })run收到完整的判别联合HookInvocation定义于 hook-engine.ts 第 40-76 行先用invocation.phase收窄再取字段。函数 hook 与命令 hook 可以混用链式顺序一致。ResolvedHook的判别联合第 101-121 行包含run与command两个分支executeHook第 348-362 行统一处理函数分支用withTimeout包hook.run(invocation)命令分支走runCommandHook两者都支持可选的clientSurfaces作用域过滤——未设置clientSurfaces时对所有客户端表面生效设置了则只在命中的TurnClientSurface上运行。Workflow hook用 GUI 工作流替代 shell 命令从源码可以确认config.json的hooks条目除了命令型还有第二种形态——Workflow hookHookWorkflowConfigSchemahook-config.ts 第 32-47 行由 GUI 在同一顶层hooks键下写入不执行 shell 命令而是通过本地WorkflowRuntime的 HTTP 端点运行一条 GUI Create Loop 工作流。字段包括workflow触发时运行的工作流 idmodeobserve只运行/block失败或输出 DENY 时阻断等同 exit 2 语义/rewrite把工作流输出折回 hook 结果PostToolUse 合并 output、UserPromptSubmit 作为 additionalContext、PreToolUse 尝试把 JSON 输出解析为 argumentsbaseUrlWorkflowRuntime 基地址如http://127.0.0.1:8765secret可选 Bearer 鉴权timeoutMs超时可省略走默认。实现上buildWorkflowHookRun第 61-122 行POST 到${baseUrl}/workflow/internal/hook-run把workflow/phase/mode/payload/workspaceRoot打包传输错误一律 fail open——只返回 message 告警绝不阻断 agent。这属于 2026-06 重构后 hooks 作为第一类扩展机制的一部分与命令 hook 共用同一套阶段、匹配器与链式语义二者可在同一hooks数组内混用。安全模型命令 hook 以 Kun runtime 的权限执行任意 shell 命令。config.json必须当作可信输入不要把不可信来源的内容写进hooks数组。这与 MCPservers配置的信任模型一致。除此之外源码还体现了两层纵深防护凭证隔离命令 hook 的进程环境来自shellSpawnEnv()builtin-tool-utils.tshooks.test.ts 的does not expose runtime credentials to command hooks用例明确断言KUN_RUNTIME_TOKEN与DEEPSEEK_API_KEY均不出现在 hook 子进程环境中输出missing|missing——即 runtime 凭证与模型密钥不会泄漏给第三方 hook 脚本。失败方向由阶段决定工具阶段安全门fail closedprompt 注入与观察者 fail open确保守卫坏掉时宁可挡下可疑动作、也不把用户锁在门外。事件与可观测性hook_denied— PreToolUse/UserPromptSubmit 拒绝错误项 事件severityerror。hook_failed— 工具阶段 hook 崩溃或超时fail closed工具错误项。hook_warning— 非阻断告警severitywarning的 error 事件观察者崩溃、命令非零退出、prompt gate 崩溃等。事件落点工具阶段的hook_denied/hook_failed由 local-tool-host-core.ts 的errorToolResult构造生命周期阶段的 warning 由 turn-lifecycle-hooks.ts 的recordLifecycleHookWarnings第 93-108 行以code: hook_warning、severity: warning记录回合级 deny 由 agent-loop-turn-lifecycle.ts 第 212-235 行同时写 error 事件与kind: error的落盘条目code 均为hook_denied随后回合以failed收尾hooks-lifecycle.test.ts 的fails the turn when a UserPromptSubmit hook denies it用例验证了错误项与 turn status 双落盘。测试与源码索引引擎单测hooks.test.ts——匹配器glob/转义/或/全匹配、链式改写、deny 截断、auto-approve、退出码协议、stdin 载荷、超时杀进程、凭证隔离、schema 严格校验。循环集成hooks-lifecycle.test.ts——TurnStart/TurnEnd 载荷、deny 落盘、hook-context注入、PreCompact 触发、观察者容错崩溃后回合仍 completed 且产生hook_warning事件。工具宿主接入点local-tool-host-core.tsexecute的 pre/post 段第 115-131 行。循环接入点turn-lifecycle-hooks.tsrunTurnStartLifecycleHooks/runTurnEndLifecycleHooks与 agent-loop-turn-lifecycle.tshook_denied落盘。配置挂载kun-config-application.tshooks: HooksConfigSchema.optional()默认占位见 config.example.json 顶层hooks: []。已知边界与后续方向GUI 设置页暂无 hooks 编辑界面配置走config.json~/.kun/data/config.json。子代理复用同一套工具 hook但没有独立的SubagentStop阶段。工具阶段 hook 的非阻断告警目前不产生运行时事件工具宿主没有事件记录器只有生命周期阶段的告警会以hook_warning事件浮出。从源码看clientSurfaces作用域过滤、Workflow hook 与 matcher 缓存均已落地这些是文档之外值得持续关注的演进方向。综上Kun hooks 的边界设计非常清晰工具阶段是安全门fail closedprompt 阶段是便利注入fail open观察者阶段只告警。按读取 stdin JSON → 决定 exit 0 / 2 / 其他 → 需要时输出结构化 stdout的协议写脚本就能以最小成本为 Kun 的主循环、子代理与 CLI 注入一致的策略能力。赞分享人工智能AI Agent自主智能体桌面应用MCP Clients【免费下载链接】KunLocal-first AI agent workspace for coding, writing, design, research, and automation — one runtime for desktop GUI and TUI.项目地址https://gitcode.com/gh_mirrors/de/Kun点击查看免费下载相关推荐Notepad-- 十分钟上手指南批量替换、文件对比与编码修复一次讲清Notepad 十分钟上手指南批量替换、文件对比与编码修复一次讲清 核心关键词Notepad 长尾关键词Notepad 安装编译步骤、Notepad 批量桌面应用Kun Hooks 全参考面向 Kun Agent 运行时的六阶段钩子系统实战指南Kun Hooks 全参考面向 Kun Agent 运行时的六阶段钩子系统实战指南 Kun 是一个 Local first 的 AI Agent 工作区运行时人工智能AI Agent自主智能体桌面应用MCP ClientsODrive CAN 协议完全指南CANSimple 帧格式、命令集与总线配置实战ODrive CAN 协议完全指南CANSimple 帧格式、命令集与总线配置实战 CANSimple 是 ODrive 固件内置的轻量级 CAN 传输协议嵌入式固件硬件开发智能硬件机器人上一篇华硕笔记本风扇异常终极修复指南5分钟掌握G-Helper散热优化技巧下一篇终极指南如何使用xnbcli工具轻松解包和修改星露谷物语游戏资源创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考