news 2026/10/30 1:21:21

让Claude主动回调Emacs:claude-code.el的Hook事件系统与emacsclient深度集成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
让Claude主动回调Emacs:claude-code.el的Hook事件系统与emacsclient深度集成

【免费下载链接】claude-code.el

Claude Code Emacs integration

项目地址:https://gitcode.com/gh_mirrors/cl/claude-code.el
点击查看免费下载

claude-code.el是 Claude Code CLI 的 Emacs 集成包,而它的Hook 事件系统是整个项目最有"主动权"的设计:借助emacsclient回调机制,Claude Code 能在关键节点主动"敲醒"Emacs——通知你该回复了、在动用工具前请你审批、改完文件后自动同步 buffer。本文面向新手,用最少代码讲清这条回调链路,并给出可直接上手的配置步骤与实战场景。

为什么需要 Hook:从"被动提示"到"主动回调"

默认情况下,claude-code.el 靠检测终端响铃(bell)来判断"Claude 处理完了,等你输入",再弹出 minibuffer 消息并闪烁 modeline。这属于被动监测——你只能在 Emacs 这一侧"猜测"事件。

而 Hook 是双向的:

事件(settings.json 中的键)触发时机典型玩法
NotificationClaude 等待输入、有通知时桌面提醒、自动切回 Claude buffer
Stop一轮回复结束写日志、更新 org 任务状态
PreToolUseClaude 准备调用工具(编辑文件、执行命令等)在 minibuffer 里做 y/n/q 权限审批
PostToolUse工具执行完成后自动 revert / git 三方合并文件变更

事件发生时,CLI 会把事件数据以JSON 写入 stdin交给你在 settings.json 里登记的命令——这就是"主动回调"的起点。

一张流程看懂 emacsclient 回调链路

整条链路只有 5 步,理解它比背配置更重要:

  1. Claude Code CLI 触发事件,将 JSON 数据通过 stdin 传给claude-code-hook-wrapper <事件名>;
  2. bin/claude-code-hook-wrapper 读取 JSON,执行emacsclient --eval "(claude-code-handle-hook '<type> \"$CLAUDE_BUFFER_NAME\")" "$json";
  3. Emacs server 端执行 claude-code-handle-hook:它把 JSON 和额外参数装进一个 plist 消息;
  4. 该消息被依次投递给 claude-code-event-hook 上注册的每个监听函数(run-hook-with-args-until-success语义,第一个返回非 nil 结果的处理器生效);
  5. 处理器若返回 JSON(如权限决定),wrapper 会剥掉 emacsclient 自动加的外层引号,把干净 JSON 回传给 CLI,直接影响 Claude 的后续行为。

其中第 3 步依赖一个巧妙细节:claude-code.el 启动 Claude 实例时,会把当前 buffer 名写入子进程环境变量(见 claude-code.el 中 CLAUDE_BUFFER_NAME 注入),于是 shell 侧的 hook 总能通过$CLAUDE_BUFFER_NAME知道"这个事件属于哪个 Emacs buffer"。

仓库克隆方式(如尚未安装):git clone https://gitcode.com/gh_mirrors/cl/claude-code.el

四步完成 Hook 配置(最快配置方法)

第 1 步:把 bin 目录加入 PATH

wrapper 脚本需要能被 CLI 的 shell 环境找到:

export PATH="/path/to/claude-code.el/bin:$PATH"

写入~/.bashrc或~/.bash_profile。

第 2 步:启动 Emacs server

emacsclient要能连上你正在用的 Emacs:

;; init.el (start-server)

第 3 步:在~/.claude/settings.json注册 Hook

可直接参考模板 examples/hooks/example_settings.json,最小配置形如:

{ "hooks": { "Notification": [{ "matcher": "", "hooks": [{ "type": "command", "command": "claude-code-hook-wrapper notification" }] }], "PreToolUse": [{ "matcher": "", "hooks": [{ "type": "command", "command": "claude-code-hook-wrapper pre-tool-use" }] }] } }

四个事件(Notification/Stop/PreToolUse/PostToolUse)按需各加一条即可。

第 4 步:在 Emacs 端注册监听器

监听函数只需接收一个 plist 消息并做你想做的事:

(defun my-claude-hook-listener (message) (let ((type (plist-get message :type)) (buffer (plist-get message :buffer-name))) (when (eq type 'notification) (message "Claude 等待输入:%s" buffer) (ding)))) (add-hook 'claude-code-event-hook #'my-claude-hook-listener)

examples/hooks/目录里还有一份完整参考实现 claude-code-hook-examples.el,含通知、工具监控、日志、org 集成等多个现成监听器,配合 examples/hooks/README.md 说明使用。

Hook 消息的 4 个字段

每个监听函数拿到的 plist 消息结构固定(见 claude-code-handle-hook 源码):

键含义
:type事件类型,如'notification、'pre-tool-use
:buffer-name来源 Claude buffer(来自$CLAUDE_BUFFER_NAME)
:json-dataCLI 发来的 JSON 载荷(工具名、参数等)
:argssettings.json 命令里追加的额外参数列表

:args给了你一个"带外通道":在 settings.json 命令里追加 shell 表达式,比如claude-code-hook-wrapper notification "$PWD" "$(date -Iseconds)" "$$",监听器即可在:args里拿到工作目录、时间戳、进程号,适合做富上下文日志。

实战场景

场景一:把权限审批搬到 minibuffer(PreToolUse)

最出彩的用法。Claude 每次要用工具前,你会在 minibuffer 看到格式化的 JSON 参数并收到Allow? (y/n/q):提问:

  • y→ 返回"allow",放行
  • n→ 返回"deny",拒绝
  • q / ESC→ 返回"ask",交还给 Claude 自己的权限对话框

现成实现是 my-claude-pretooluse-handler:它会先读取~/.claude/settings.json的permissions.allow白名单自动放行已授权工具,只有陌生工具才弹窗,避免每次都被打断。执行setup-claude-pretooluse-control即可启用(以最高优先级挂入 hook 链)。

场景二:Claude 改完文件,buffer 自动同步(PostToolUse)

Claude 直接改磁盘文件,Emacs buffer 会"过期"。claude-code-auto-revert-hook.el 是一对精心设计的 Pre/Post 监听器:

  • Pre 阶段:在 Claude 动手前自动保存你的未存修改,并记录文件"原始内容"作为合并基线;
  • Post 阶段:用git merge-file做三方合并(基线 + 你的修改 + Claude 的修改),无冲突时 buffer 直接更新并保存;也可切换为简单:revert策略。

一行(setup-claude-auto-revert :git-merge t)完成注册(setup-claude-auto-revert),从此"Claude 在改、你在看"不再互相覆盖。

场景三:通知、日志与 org 任务

  • my-claude-notification-listener:Notification/Stop 事件触发(ding)+ 提示,并可自动显示 Claude buffer;
  • my-claude-session-listener:把所有事件带时间戳追加到~/claude-hooks.log,排障利器;
  • my-claude-org-listener:Claude 就绪时在 org 文件里自动生成带 buffer 名和 JSON 摘要的 TODO 条目。

三者分别对应 通知监听器、会话日志、org 集成,用setup-claude-hooks-advanced一键全部挂上。

JSON 响应机制:第一个非 nil 响应生效

claude-code-event-hook采用run-hook-with-args-until-success语义(源码):

  1. 多个监听器按注册顺序依次执行;
  2. 第一个返回非 nil 值的函数立即"赢下"本次事件,其返回值作为 JSON 经 emacsclient 回传给 CLI;
  3. 因此"审批类"处理器(要返回permissionDecision)应挂在前面的高优先级位置,"日志类"处理器返回 nil 则不影响链路。

这正是 Emacs 能"反向控制" Claude 的关键——不只是接收事件,还能决定Claude 能不能用某个工具。

常见排查清单

症状原因与解决
Emacs 完全收不到回调确认 Emacs 已执行(start-server);确认claude-code-hook-wrapper在 CLI 的 shell PATH 中(新开终端验证which claude-code-hook-wrapper)
CLI 收到带引号的奇怪输出说明事件没经过 wrapper,而是直接emacsclient --eval;换用 wrapper 即可自动清洗
已允许的工具仍弹窗已知限制:permissions.allow中的工具也会触发 PreToolUse;现成 handler 已内置白名单检查规避冗余弹窗
想查看所有已注册监听器运行交互式命令list-claude-hooks(实现)

关键文件导航

文件作用
claude-code.elclaude-code-handle-hook统一入口与事件消息构造
bin/claude-code-hook-wrappershell 侧 emacsclient 调用与 JSON 清洗
examples/hooks/example_settings.json四事件完整 settings.json 模板
examples/hooks/claude-code-hook-examples.el通知/日志/org/权限审批监听器合集
examples/hooks/claude-code-auto-revert-hook.elPre/Post 自动保存与 git 三方合并
examples/hooks/README.mdHook 示例快速上手指南

小结

claude-code.el 的 Hook 事件系统用一条极简链路(stdin JSON → wrapper → emacsclient → event-hook → JSON 回传)打通了 Claude Code 与 Emacs 的双向通信:Notification/Stop负责"叫你回来",PreToolUse把审批权交还给你,PostToolUse让 buffer 永远与磁盘同步。四步配置、零额外依赖,值得每个 Emacs + Claude Code 用户花十分钟体验一次这种"AI 主动敲门"的工作流 🚪

【免费下载链接】claude-code.el

Claude Code Emacs integration

项目地址:https://gitcode.com/gh_mirrors/cl/claude-code.el
点击查看免费下载

相关推荐

上一篇:nghttp2 项目教程
下一篇:骆驼大乱斗:文本生成在游戏内容创作中的创新应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 1:17:34

【JavaWeb】文件上传下载(213-221)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:15:43

Gin + Vue3 + ElementPlus 后台:固定窗口限流的实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:15:28

Gin + Vue3 + ElementPlus 后台前端:Vue3 + TypeScript + Vite 实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:15:12

Gin + Vue3 + ElementPlus 的接口自动注册:EasyGoAdmin 实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:14:54

python selenium启动常用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:14:53

android的两种启动service方式及混合方式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华