Memknow · Feishu × Claude Code × Long Memory

你的 bot,是一套长期运行的工作区。

Memknow 把飞书消息、Claude Code CLI、本地 workspace 和记忆检索层接成了一条稳定运行链路。 这页不是安装说明,而是一堂系统解剖课:从一条消息开始,看它如何穿过会话队列、上下文增强、Claude 执行器,再回到飞书卡片。

1 个 app = 1 个 workspace 应用级隔离,模板、记忆、session、技能全部独立
按 channel_key 串行 同一聊天上下文不并发抢写,不同聊天并发运行
不是云 Agent 托管 前提是本机已经安装并登录 Claude Code
端到端运行快照 single machine / sqlite wal / claude cli
1. 飞书用户发消息 text / post / image / file 进入 WebSocket 事件流
2. Receiver 标准化 解析消息、下载附件、构造 IncomingMessage
3. Session Worker 串行执行 基于 channel_key 路由到稳定队列,组装 prompt 与上下文
4. Claude Executor 调用 CLI 在目标 workspace 中 resume 并流式消费 stream-json
5. Feishu Sender 回写卡片 Thinking、结果、错误、重试状态都会回传到聊天界面
这一页回答 3 个关键问题
消息是怎么被可靠地串起来的? 从飞书事件,到 `session.Manager`,再到每个 `Worker` 的串行队列模型。
为什么它能有“长期记忆”? 不是把所有历史一股脑塞进 prompt,而是靠 session 归档、摘要与检索注入。
为什么它能主动执行? 因为 `heartbeat` 和 `schedule` 是框架内建机制,不是让 agent 自己写 YAML 假装调度。
先抓住核心判断
Memknow 是编排层 Claude Code 是执行内核 workspace 是 bot 的长期住处 SQLite 是会话与调度账本 Feishu 是输入输出界面
不要误解成“另一个 LLM 平台”

Memknow 不替代 Claude Code。它负责把飞书、会话管理、调度、记忆和本地工作区接起来,让 Claude Code 在一个可持续运行的系统里工作。

01

先跑一遍完整主链路

如果你只能记住一段内容,就记住这一章。Memknow 的价值首先不在“功能点”,而在它把一次飞书消息可靠地推进到了一个真实的本地 Agent 工作流里。

从 Feishu 到 Claude CLI,再回到卡片响应
消息进入系统后的 6 个动作
Receiver 接住 WebSocket 事件 解析 `text`、`post`、`image`、`file`,欢迎事件直接回复,不进入 Claude 执行链路。
标准化为 IncomingMessage 判断来源 chat、thread、mentions、reply 关系,并在需要时把附件先下载到临时目录。
Session Manager 用 channel_key 分发 `p2p`、`group`、`thread` 形成稳定键。相同键进入同一 Worker 队列,不同键并发执行。
Worker 组装可执行上下文 取当前 session、移动附件、记录用户消息、做历史摘要检索、构造 prompt。
Executor 调 `claude --resume` 真实进入目标 workspace 目录,流式接收 Claude Code 的输出和工具调用结果。
Sender 持续回传状态 Thinking 卡片、结果文本、失败信息、重试表现都会回写到飞书消息。
主链路背后的组件边界
F `internal/feishu`

输入输出边界。接 WS,发卡片,不关心记忆细节。

S `internal/session`

对话编排核心。管理 Worker、session 生命周期、上下文注入。

C `internal/claude`

把 prompt 和工作目录真正送给 Claude Code CLI。

D `internal/db` + model

存会话、消息、摘要、schedule 和日志。

W `internal/workspace`

负责 bot 住的地方:模板初始化、skills、memory、sessions。

关键设计取舍

Memknow 没有把所有职责堆进一个“智能 Agent 服务”里,而是把输入输出、会话编排、Claude 执行、工作区初始化拆清楚。这样调试和演进都更稳。

Feishu User -> WebSocket Event -> feishu.Receiver -> session.Manager.Dispatch() -> session.Worker -> claude.Executor -> feishu.Sender -> Feishu Card / Text Reply
为什么这条链路重要

很多“聊天机器人”只是在回调里拼一段 prompt 然后调用模型 API。Memknow 做得更深一层:它把每次消息都导向一个真实可持续的本地工作区,让 bot 具备编辑文件、执行命令、积累记忆和被系统定时唤醒的条件。

02

为什么每个 bot 都有独立 workspace

在 Memknow 里,bot 不是一组数据库字段,而是一个真正的目录树。你可以把它理解成“AI 的长期住处”:人格、记忆、技能和会话现场都放在这里。

app 级隔离,而不是 prompt 级临时拼装
workspaces/<app-id>/ ├── SOUL.md bot 的长期行为设定 ├── IDENTITY.md 身份描述 ├── USER.md 用户关系与约束 ├── MEMORY.md 记忆使用规则 ├── HEARTBEAT.md 心跳检查清单 ├── skills/ 按需读取的能力说明 ├── memory/ 长期知识沉淀 ├── sessions/ 运行期会话现场 ├── bin/web-search 本地统一搜索入口 └── .search.json 运行期搜索配置
这个目录结构解决了什么问题
1. 多应用隔离 不同飞书 app 用不同 workspace,不共享记忆、不共享 session 目录、不串 prompt。
2. 让 Claude Code 有“落脚点” Claude 执行时不是在空目录里想象自己有文件,而是真的进入这个工作区。
3. 记忆与行为可以被演化 `HEARTBEAT.md`、memory 文件、skills 内容都可以在长期运行中被调整。
模板不是摆设,而是启动时的默认人格包

`internal/workspace/template/` 里的中英文模板会被嵌入到二进制里。新 workspace 初始化时,如果缺文件,就从模板生成默认内容。这意味着项目层面对“一个 bot 初始长什么样”有统一、可版本化的控制。

一个容易忽略的点

`HEARTBEAT.md` 是心跳运行器读取的工作清单,不是任务 YAML 模板。Memknow 明确把 heartbeat 设计成系统内建调度,而不是依赖 agent 自己写配置文件来伪造主动性。

03

一次对话如何被串行处理

这部分决定系统稳不稳。Memknow 没有让同一聊天上下文里的消息并发地撞进同一个 Claude session,而是用 `channel_key` 维持稳定的串行执行面。

稳定的会话键,比“谁先抢到 goroutine”更重要
channel_key 的意义
p2p:{chat_id}:{app_id}
单聊 同一个人与同一个 app 的私聊,会稳定地落到一个 Worker 队列里。
group:{chat_id}:{app_id}
群聊 群整体共享上下文,适合群内共同协作场景。
thread:{chat_id}:{thread_id}:{app_id}
话题群 把 thread 作为更细粒度上下文边界,避免群内多个话题互相污染。
Worker 在执行时实际做的账本动作
getOrCreateSession()
获取当前活跃 session,或在需要时创建新的 `session_id` 与 Claude resume 关系。
moveAttachments()
把 Receiver 下载到临时目录的附件,移入当前 session 的 `attachments/`。
DB record
先记 user message,再写 assistant/tool 结果和 token 统计,保证会话能回放。
Retrieve()
根据 channel_key 和当前输入做历史摘要检索,构造 ContextPayload 注入 prompt。
Execute()
进入 Claude CLI 执行。若空文本返回,会尝试归档、摘要、重试一次。
为什么串行是必要的

Claude session 本身就有上下文状态。如果同一会话边界里的消息并发进来,文件修改、上下文注入、回传卡片顺序都可能乱掉。Memknow 把并发留给不同 `channel_key`,把顺序保证留给同一个 `channel_key`。

channel_key -> dedicated worker queue -> active Memknow session_id -> claude_session_id (--resume) same channel_key: serial different channel_key: concurrent
04

长期记忆不是堆历史,而是检索归档

“长期记忆”最容易被说虚。Memknow 这里做得相对务实:保留 Claude `--resume` 的连续上下文能力,同时在 session 维度做摘要归档和后续检索,把跨 session 的连续性补上。

resume 保留短中期上下文,summary + retrieve 补长期连续性
记忆链路分两层
会话内连续性
依赖 Claude CLI 自己的 `--resume`。只要你还在同一个 session 里,Claude 会延续之前的内部上下文。
跨会话连续性
由 Memknow 自己负责。归档旧 session,生成 `session_summaries`,在新消息到来时按 channel_key 与当前 prompt 做检索,再把相关摘要注入。
这比“把历史都塞进去”更可持续

直接把所有历史消息拼进 prompt,短期内看似简单,长期一定爆。Memknow 选择的是更像信息检索系统的做法:哪些历史值得带回来,由摘要与检索层决定,而不是由上下文窗口硬撑。

归档发生在什么时候
用户长时间不继续对话 空闲超时后,当前 session 可以被归档。
需要切换到新 session 例如 `/new` 之类的显式操作,会结束当前上下文并启动新会话。
执行异常触发补救 某些空响应场景下,Worker 会尝试先摘要归档,再带摘要重试。
archived session -> summarize -> store in session_summaries -> next user message arrives -> retrieve relevant summaries -> build ContextPayload -> inject into prompt -> execute in new or current session
这里的“长期”是工程上的长期,不是魔法上的长期

它依赖的是持续积累文件、结构化摘要和可检索历史,而不是假设模型自己永远记得一切。也正因为如此,它更接近一个真实可维护的 Agent 记忆层。

05

主动能力从哪里来:Heartbeat 与 Schedule

Memknow 不只支持“收到消息再回复”。它内建了两种主动触发机制,但两者职责完全不同:`heartbeat` 是系统维护循环,`schedule` 是业务提醒与计划执行。

主动性来自框架内建调度,不来自 prompt 里的自我幻想
Heartbeat

这是系统级自检和维护循环,由 `internal/heartbeat` 按 `config.yaml` 配置周期触发。它会读取 workspace 里的 `HEARTBEAT.md`,让 bot 定期检查自己该整理什么、更新什么、反思什么。

内建服务 系统维护 读取 HEARTBEAT.md 不写 YAML 任务
Schedule

这是业务侧的自然语言调度能力,由 `internal/schedule` 负责。用户可以通过“每小时提醒我喝水”“明天 10 点提醒我回顾 PR”这类语言创建、查看、修改、删除定时任务。任务实体存数据库,由调度器直接执行。

用户可管理 DB 持久化 gocron 执行 不是 tasks/*.yaml
heartbeat: config.yaml -> heartbeat service -> open workspace HEARTBEAT.md -> run maintenance turn schedule: user natural language -> schedule intent parser -> schedules table -> scheduler executes at trigger time
项目里专门强调的一条规则

不要把 heartbeat 实现成生成任务 YAML,也不要把 schedule 的创建依赖于 agent 去写 YAML 文件。主动执行必须是框架层确定的能力,而不是 prompt 层约定俗成的“假功能”。

06

这套系统的边界与适用场景

理解 Memknow,不只要知道它能做什么,也要知道它刻意没有做什么。它是一个偏单机、偏本地、偏工作区编排的 Agent 平台,而不是一个大一统云原生控制平面。

边界讲清楚,场景判断才不会跑偏
它适合什么

适合把一个飞书 bot 变成真正有 workspace、有文件系统、有长期记忆沉淀能力的数字同事。尤其适合私有部署、企业内网、工具链已经围绕 Claude Code 展开的场景。

它不打算解决什么

它不是多租户云平台,不是无状态函数调用框架,也不是“接一下大模型 API 就自动拥有长期记忆”。它依赖本机 Claude Code、文件系统和本地持久化。

为什么单机设计反而有优势

部署简单、状态清晰、调试路径短。SQLite WAL、workspace 目录、Claude CLI 都在一台机器上,很多复杂度被直接压平了。

你需要接受的约束

前提是机器已经安装并登录 Claude Code;某些能力天然绑定本地环境;横向扩展、多机共享状态、统一集中调度不是当前设计重点。

一句话重新总结 Memknow

它是一个把飞书接入、会话调度、本地工作区、Claude Code CLI、长期记忆和系统级主动执行接到一起的编排层。它让 bot 从“会回复消息的接口”升级成“在一个持续存在的目录里工作和成长的 agent”。

如果你要继续往下读

建议顺序是:先读 `README.md` 了解整体能力,再读 `docs/design.md` 看实现结构,最后回到代码中的 `internal/session`、`internal/claude`、`internal/workspace` 三个目录,把这页里的心智模型和实际实现一一对照起来。