Claude Subconscious如何实现"永不阻塞"?异步Hook模式完整深度分析
【免费下载链接】claude-subconsciousGive Claude Code a subconscious项目地址: https://gitcode.com/GitHub_Trending/cl/claude-subconscious
Claude Subconscious是一款为 Claude Code 打造的后台记忆代理插件:它在后台默默观察你的每一次会话、读取你的代码库、构建跨会话的长期记忆,并在你下次提问前"低语"回有用的上下文。它最打动人的设计承诺是——永不阻塞(Never Blocks):无论后台代理做多重的"记忆整理",你敲下的每一个命令、每一次工具调用都零等待。本文将带你完整拆解它背后的异步 Hook 模式,看懂"主 Hook 秒退 + 后台 Worker 独立干活"这套经典双进程架构。
🧠 先搞懂问题:为什么 Hook 会"卡住"你
Claude Code 的插件可以在四个关键时机挂接钩子(Hook):会话开始、提交提示词前、调用工具前、响应结束(Stop)。如果钩子里直接执行"读取完整对话记录 → 调 API → 等待代理返回"这种重活,你的每次收尾都会干等几十秒甚至更久。
Claude Subconscious 的解法是把它注册在hooks/hooks.json中的 Stop 钩子标记为"async": true——告诉 Claude Code"这个钩子不用等它跑完",再配合一套"文件交接 + 独立进程"的机制,把真正耗时的 SDK 会话彻底甩到后台。
四个钩子的职责与耗时预算一目了然:
| Hook | 脚本 | 超时 | 作用 |
|---|---|---|---|
| SessionStart | session_start.ts | 5s | 通知代理新会话、清理遗留状态 |
| UserPromptSubmit | sync_letta_memory.ts | 10s | 把记忆块与低语消息注入上下文 |
| PreToolUse | pretool_sync.ts | 5s | 工具调用前同步最新提示 |
| Stop | send_messages_to_letta.ts | 120s(async) | 异步派发:把对话记录交给后台 Worker |
💡 前三个钩子都是"轻查询、快注入",只有 Stop 钩子涉及繁重的记忆处理,也正是异步模式的主战场。
🏗️ 核心架构:Stop 钩子的"两级流水线"
整个异步链路可以概括为一句话:主进程只负责打包和发车,后台 Worker 负责长途运输。
第一级:Stop 钩子——只做"秒级"准备
当 Claude 完成一次响应,send_messages_to_letta.ts 被触发,它依次完成五件快速的事:
- 解析对话记录:读取会话的 JSONL 转录文件,提取用户消息、助手回复、思考块与工具调用;
- 增量判断:依据上次处理到的索引(
lastProcessedIndex),只挑出新增消息,避免重复发送; - 绑定会话:获取或创建该 Claude Code 会话对应的 Letta 对话(conversation);
- 打包载荷:把待发送内容写入临时 payload 文件(如
payload-{sessionId}-{时间戳}.json); - 点火即走:调用
spawnSilentWorker启动后台 Worker,随即退出。
关键就在第 5 步。Worker 以detached: true(脱离父进程)+stdio: 'ignore'方式启动,再对子进程句柄执行child.unref()——这意味着主 Hook 不持有对 Worker 的任何等待,Node 事件循环不会因它而停留,主进程毫秒级退出。
第二级:后台 Worker——独立进程慢慢干
send_worker_sdk.ts 被独立进程拉起后,才真正执行"重活":
- 通过 Letta Code SDK 的
resumeSession恢复已有对话(见 send_worker_sdk.ts),把打包好的转录内容发给 Subconscious 代理; - 代理在后台可以使用 Read / Grep / Glob 工具真实地读你的代码库、更新 8 个记忆块(用户偏好、项目上下文、待办事项等);
- 流式接收代理响应后,把
lastProcessedIndex回写到状态文件,并删除临时 payload 文件完成收尾。
三级交接:为什么用"文件"而不是直接传参?
两个进程之间的交接全靠一个payload 文件(写入逻辑),这个设计有三个妙处:
- 解耦启动与执行:主进程只写文件、传路径,Worker 崩溃也不会拖累已退出的主进程;
- 天然可恢复:状态文件先于 Worker 持久化(L181-L182),即使 Worker 失败,下次 Stop 时增量索引也不会错乱;
- 跨平台统一:不依赖管道或共享内存,Windows、macOS、Linux 行为一致。
🐧 Windows 用户特别关心:静默执行
后台进程在 Windows 上有个经典麻烦——命令行窗口一闪一闪。这个项目给出了完整的工程化答案:
- 所有钩子统一经由 silent-npx.cjs 启动,它是一个跨平台静默启动器;
- Windows 下它调用 silent-launcher.exe(由 SilentLauncher.cs 编译),利用PseudoConsole(ConPTY)+ CREATE_NO_WINDOW标志彻底消除窗口闪现;
- Worker 还获得了独立的伪控制台,即使主启动器的控制台被关闭,后台任务依然存活。
📊 状态与可观测性:出问题了去哪找
所有状态分两层存放,方便你排障:
- 持久状态(项目目录
.letta/claude/):conversations.json记录"会话 ID → 对话 ID"映射,session-{id}.json记录每个会话的处理进度——这是记账本,不是独立代理,所有项目共享同一个 Subconscious 大脑; - 临时日志(
$TMPDIR/letta-claude-sync-$UID/):send_messages.log对应主 Hook,send_worker_sdk.log对应后台 Worker。
排查钩子是否正常运行,盯住这两份日志即可:
tail -f /tmp/letta-claude-sync-$(id -u)/send_messages.log tail -f /tmp/letta-claude-sync-$(id -u)/send_worker_sdk.log🚀 快速上手:三步启用你的"潜意识"
1️⃣ 安装插件(在 Claude Code 内执行):
/plugin marketplace add letta-ai/claude-subconscious /plugin install claude-subconscious@claude-subconscious2️⃣ 配置 API Key(从 app.letta.com 获取):
export LETTA_API_KEY="your-api-key"3️⃣ 按需调整行为:
LETTA_MODE:whisper(默认,只注入消息)/full(注入记忆块+消息)/off(关闭)LETTA_SDK_TOOLS:read-only(默认)/full(后台可改代码)/off(纯聆听)
首次使用时插件会自动导入内置的 Subconscious.af 代理,零额外配置。想从源码安装?git clone仓库后执行npm install,再/plugin enable .即可。
✅ 总结:这套"永不阻塞"设计学到了什么
Claude Subconscious 的异步 Hook 模式,本质是把三个工程原则组合成了一拳:
| 原则 | 实现 |
|---|---|
| 主路径永远快 | Stop 钩子只做解析、打包、发车,毫秒级退出 +async: true声明 |
| 重活交给独立进程 | detached启动 +unref(),Worker 生灭与主进程完全解耦 |
| 用文件做安全交接 | payload 文件传参、状态文件先行持久化,崩溃不丢进度 |
这套"秒退主进程 + 持久化载荷 + 静默后台 Worker"的组合拳,是任何需要在交互工具里挂载耗时后台任务的插件开发者的教科书级参考。而它带来的用户体验就是那句承诺:Sub 在后台越用越聪明,你却永远感觉不到它的存在。
【免费下载链接】claude-subconsciousGive Claude Code a subconscious项目地址: https://gitcode.com/GitHub_Trending/cl/claude-subconscious
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考