claude-mem Worker Service 指南:本地 HTTP 运行时、路由体系与观察生成背后的中枢
claude-mem 是一款为 Claude Code、Codex、Cursor 等 Agent 提供跨会话持久记忆的开源工具:它在会话中记录 Agent 的工具调用与产出,用 AI 压缩成观察与摘要,并在后续会话开头把相关上下文重新注入。这套流程之所以能跨进程协作,核心依赖一个常驻的本地 Worker Service。本文以仓库内 src/services/worker/README.md 为骨架,深入 Worker 的进程形态、监听端口推导规则、请求流、完整 HTTP 路由面以及源码目录的分层约定,帮助你理解“记忆从被采集到被检索”的运行时路径,并掌握扩展内部 API 时应遵循的代码组织原则。
Worker 是什么:为 Hooks、Viewer 与 MCP 共用的本地 HTTP 运行时
根据 src/services/worker/README.md 的定位,worker 是一个本机常驻的 HTTP 运行时,服务于四类调用方:
- Hooks:Claude Code / Cursor / Codex / Antigravity CLI 等平台在会话关键节点触发的回调(SessionStart、UserPromptSubmit、PostToolUse、Stop 等)通过 HTTP 请求 worker,完成上下文注入、观察记录与摘要请求;
- Viewer:浏览器端“实时观察记忆生成”的 UI 数据源;
- MCP Search:MCP 服务器向模型暴露的记忆检索工具,底层同样路由到 worker;
- 后台观察生成(background observation generation):由 worker 内常驻的生成器进程负责把积累的工具调用压缩为结构化记忆。
它被打包进 plugin/scripts/worker-service.cjs,并由 Bun 运行时管理。之所以要求 Bun,是因为 worker 依赖 bun:sqlite 提供本地 SQLite 存取(构建产物 bundle 中可以看到 openConfiguredSqliteDatabase 通过 bun:sqlite 打开数据库并统一施加 busy_timeout、WAL 等 pragma)。因此,若环境缺少 Bun,worker 将无法启动。
从进程模型看,worker 通常以分离的后台守护进程运行:入口以 --daemon 参数启动(见 src/shared/worker-utils.ts 的懒启动调用 spawnHidden(runtimePath, [scriptPath, '--daemon'], ...)),调用方通过“健康检查 → 就绪检查”确认其可用后才真正发业务请求。
监听地址与端口:37700 + (uid % 100) 的推导逻辑
worker 的监听配置全部来自环境变量,缺省时回退到内置默认值(源码见 src/shared/SettingsDefaultsManager.ts):
| 配置项 | 默认值 | 说明 |
|---|---|---|
CLAUDE_MEM_WORKER_HOST |
127.0.0.1 |
仅监听回环地址,保证本地安全性 |
CLAUDE_MEM_WORKER_PORT |
String(37700 + ((process.getuid?.() ?? 77) % 100)) |
无 uid(如 Windows)时按 77 参与取模 |
也就是说,端口在 37700(uid mod 100 == 0)到 37799(uid mod 100 == 99)区间内。若未设置 CLAUDE_MEM_WORKER_PORT,则默认取 37700 + (uid % 100);host 默认 127.0.0.1。
读取逻辑集中在 src/shared/worker-utils.ts:getWorkerPort() 与 getWorkerHost() 会先从 settings.json(位于 CLAUDE_MEM_DATA_DIR,默认 ~/.claude-mem)读取对应键,再做一次进程内缓存,避免每次调用都重新解析 JSON。buildWorkerUrl / workerHttpRequest 进一步封装了 http://{host}:{port}{path} 的拼装与超时控制,所有 hook 与 CLI 对 worker 的调用都经由这一层。
注意:环境变量/设置中的超时值并非随意读取——CLAUDE_MEM_API_TIMEOUT_MS、CLAUDE_MEM_HEALTH_TIMEOUT_MS、CLAUDE_MEM_HOOK_READINESS_TIMEOUT_MS 等都会先经过边界校验(如 API 超时限制在 500ms~300000ms 之间),非法值会被丢弃并回退到默认值(src/shared/worker-utils.ts)。
请求流:从 Hook / MCP 到路由处理器
README 给出了简洁的三段式请求流:
Hook or MCP client
-> HTTP request to worker on configured host/port
-> route handler in src/services/worker/http/routes/
-> service layer, SQLite, Chroma, or MCP search logic
实际调用面可以在 src/services/worker-service.ts 的 registerRoutes() 与 initializeBackground() 中验证:
- 构造函数阶段先注册不需要数据库初始化即可应答的路由:
ChromaRoutes、上下文注入的前置守卫、以及一组“初始化门控”中间件; initializeBackground()中,DatabaseManager初始化完成后才注册依赖数据层的SearchRoutes(含/api/search*、/api/context/*)、CorpusRoutes(知识库语料)与CloudSyncRoutes(云同步状态);/api/context/inject在initializationCompleteFlag未置位时会返回空文本而非报错,避免 hook 在冷启动竞态中被阻塞。
这意味着请求在到达各路由处理器前,会经过一个统一的可达性与就绪门控:当数据库仍在初始化时,除 /api/chroma/status、/api/health、/api/readiness、/api/version、/api/settings/dependency-health 外的业务请求会收到 503 Service initializing 响应,并提示重试(同上文件 L328-L351)。这也解释了为何 README 强调 /health 用于“健康与版本状态”,而真正表示“可以处理业务”的信号是就绪检查。
主路由面:README 清单 + 源码中的实际端点
README 列出的主路由均可从源码逐一对应,且比清单更细。以下把“文档声明”与“源码实现”对照呈现:
| 文档声明的路由 | 实际处理器(源码) |
|---|---|
GET /health — worker 健康与版本状态 |
ViewerRoutes.ts 的 handleHealth |
GET / — viewer UI |
ViewerRoutes.ts 的 handleViewerUI |
GET /stream — 用于实时 viewer 更新的 SSE |
ViewerRoutes.ts 的 handleSSEStream,并由 SSEBroadcaster 向订阅连接广播处理状态 |
/api/settings 及依赖健康 |
SettingsRoutes.ts:GET/POST /api/settings、GET /api/settings/dependency-health、GET /api/mcp/status、POST /api/mcp/toggle |
/api/mcp/* — MCP 开关状态 |
同上 SettingsRoutes(MCP 状态与切换归入设置域) |
/api/observations、/api/summaries、/api/prompts、/api/projects — 存储数据 |
DataRoutes.ts:含按 id 读取、按文件查询 GET /api/observations/by-file、批量读取 POST /api/observations/batch、删除、GET /api/stats、GET /api/processing-status、POST /api/import |
/api/search、/api/timeline、/api/context/* — 搜索与上下文 |
SearchRoutes.ts:GET /api/search(统一搜索)、GET /api/timeline、/api/search/observations、/api/search/by-file、GET /api/context/recent、GET /api/context/preview、GET /api/context/inject、POST /api/context/semantic、GET /api/timeline/by-query 及 /api/onboarding/explainer |
/api/corpus/* — 知识 Agent 语料 |
CorpusRoutes.ts:建语料、列出、读取、删除、重建、预热、查询、再预热 |
/api/logs — 本地 worker 日志 |
LogsRoutes.ts:GET /api/logs、POST /api/logs/clear |
/api/chroma/status — Chroma 集成状态 |
ChromaRoutes.ts 的 handleGetStatus |
需要补充的是,上述路由并未覆盖全部实际端点,只是 README 面向常规使用的“主清单”。会话采集这条主线还要经过 SessionRoutes:会话初始化、工具观察入队(含隐私校验与 tag 剥离)、总结请求等由 SessionRoutes.ts 承接;记忆写入端点 POST /api/memory/save 定义在 MemoryRoutes.ts;云端同步状态 GET /api/sync/status 则在 CloudSyncRoutes.ts。这些都是 Worker HTTP 面的一部分。
/api/health 的响应体远比“健康与版本”丰富:在 Server 中,它聚合返回 status、runtime、version、workerPath、uptime、managed、platform、pid、initialized、mcpReady、ai(当前选中的 provider 与认证方式)、dependencies(依赖健康快照)、rateLimits 与队列健康快照。hook 侧的版本一致性检查正是读取该响应中的 version 字段,与插件自身版本比对——不一致时 kill 掉旧 worker 并懒启动新版,这是 CLAUDE_MEM_WORKER_SCRIPT_PATH 之后最复杂的“单一版本 oracle”逻辑(见 src/shared/worker-utils.ts 的候选脚本解析与 L470-L547 的版本回环回收)。
路由布局:把新端点放进“最近的类”
README 强调:路由处理器统一放在 src/services/worker/http/routes/,并列举了 9 个文件。结合当前仓库目录(该目录下实际已扩展到 10 个文件,新增 CloudSyncRoutes.ts),各文件的职责可以归纳为:
ViewerRoutes.ts— 浏览器 UI、SSE 流、健康/重启页;SessionRoutes.ts— 会话生命周期与观察/摘要采集(最“重”的入口,依赖多个 provider 与事件广播器);DataRoutes.ts— 存储数据的查询、批量读取、删除、导入与统计;SearchRoutes.ts— 搜索、时间线与上下文注入/预览(含 5 秒 TTL 的设置缓存,降低每个 hook 回调的磁盘读取);SettingsRoutes.ts— 设置读取/更新、MCP 开关、依赖健康;CorpusRoutes.ts— 知识 Agent 的语料构建与查询;MemoryRoutes.ts— 手动记忆写入;LogsRoutes.ts— 日志读取与清空;ChromaRoutes.ts— 向量数据库集成状态;CloudSyncRoutes.ts— 云同步配置状态。
README 给出的工程原则值得作为扩展准则强调:若新端点属于某个既有 API 领域,应放进最近的既有路由类,只有行为构成全新顶层 API 时才新建路由类。这样可以避免 /api/search、/api/settings 等路由被零散散落到不同文件,也方便在 WorkerService.registerRoutes() 里按“是否依赖已初始化数据库”分组注册。
对端点体做校验时,仓库遵循 zod schema 前置校验:例如 DataRoutes 用 integerArrayLike/stringArrayLike 预处理支持 JSON 数组或逗号分隔串的批量查询,SearchRoutes 的语义上下文 schema 允许同时接受 platformSource 与 platform_source 两种命名,兼容不同平台 hook 的字段约定。
Worker 之上的服务化:server 命令与 API Key
值得区分的是:本地 worker 与可选的 server 模式不是一回事。WorkerService 的 CLI 入口解析(src/services/worker-service.ts)同时支持 worker start|stop|restart|status 与 server <command> 两类命令。server 模式会把 server-service.cjs 作为独立子进程拉起,并使用更好的认证体系(better-auth)与 API Key 管理(api-key create|list|revoke)。也就是说,worker 是面向单机 Agent 会话的轻量记忆运行时,而 server 提供了可承载团队项目、带鉴权的服务化面。二者的数据层在 worker 侧始终基于本地 SQLite,并可按需接入 Chroma 向量库做语义检索。
记忆采集的幕后链路(Worker 如何驱动观察生成)
把路由面串起来看,一条“工具调用 → 记忆”的典型链路是:
- Agent 平台触发
PostToolUse等 hook,hook 进程把规范化后的载荷 POST 到/api/sessions/observations(SessionRoutes内部经SessionManager.queueObservation入队); - 入队前会做隐私校验与
<private>标签剥离(PrivacyCheckValidator、stripMemoryTags),并跳过被排除项目或CLAUDE_MEM_SKIP_TOOLS列出的工具; - worker 常驻的生成器(由
ClaudeProvider/GeminiProvider/OpenRouterProvider之一承载,按provider-dispatch.ts选择)定期把缓冲的工具调用压缩为“观察”(observation); - 会话结束触发 Stop hook,向
/api/sessions/summarize请求摘要; - 下次会话开始,SessionStart hook 调用
/api/context/inject,worker 从 SQLite/Chroma 检索相关历史并拼装成注入文本返回。
这条链路解释了为何 /api/context/inject 在未初始化时返回空串、为何搜索类路由要等数据库就绪后才注册——hook 的容错优先于报错,任何一环 worker 不可用,hook 都会返回“继续但不阻塞”的回退结果,而不是中断用户会话。
没有 git 分支相关的 HTTP 端点
README 特别提醒:worker HTTP 面上不存在任何用于切换 git 分支的端点。非稳定发布线(non-stable release lines)应当直接从源码运行,而不是依赖 worker 动态切分支——相关分支说明见仓库文档 docs/public/branches.mdx。这意味着 worker 是一个“纯记忆运行时”,其职责边界刻意排除了源码管理类操作,设计上避免把代码拉取/切换逻辑暴露进常驻服务。
结束语
Worker Service 是 claude-mem 三层架构中的“本地中枢”:hooks 负责把 Agent 行为送进来,MCP/上下文注入负责把记忆送回去,Viewer 提供可视化,而 worker 在中间完成落库、压缩、检索与状态广播。理解它的端口推导(37700 + uid % 100)、就绪门控、路由分层与“端点放进最近路由类”的组织约定,既能帮你排障(比如 hook 报 worker 不可达时检查 CLAUDE_MEM_WORKER_PORT/CLAUDE_MEM_WORKER_HOST 与 /api/health、/api/readiness),也能为向内部 API 添加新能力提供一致的落点。深入代码时可从 src/services/worker-service.ts(注册编排)与 src/services/worker/http/routes/(端点实现)两条主线继续追读。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00