#606·memU

[BUG] bridging 运行自己的会话也是会话:record seam 每小时挖掘自己的运行记录,prepare 永远不会为空(claude_code / hermes 已实证)

Author: xnne-botCreated Jul 29, 2026Updated Jul 31, 2026

Description

bridging 任务是以宿主 agent 的一次会话的形式运行的,而宿主会把这次会话记录在——正是 memU 用来发现会话的那个地方。两个后果,都是结构性的:

  1. 每一次运行都保证了下一次运行"有新内容"。prepare 永远不可能返回 0——文档里写明的 "zero prepared sessions is fine and correct" 这个状态,在 bridging 装好之后就再也到不了了。
  2. memU 在挖掘自己的流水账:prepare → self-evolve → commit 的会话记录,成了下一轮 prepare → self-evolve → commit 的输入。

这不是 OpenClaw 独有的问题。它直接来自 ADR 0008 的形状——record seam 本身就是一次被调度的 agent 运行——所以凡是"被调度的运行本身会被记录成会话"的宿主,都中招。

证据(同一台机器,两个宿主)

manifest 只会为被选中并切片成挖掘 job 的会话写条目(bridging/transcripts.py:83-89),所以下面这些不是"被看到",是实实在在被挖过了。

宿主 已跟踪 memU 自己的 占比
claude_code 95 个会话 / 25,833 条记录 19 个会话 / 2,111 条记录 会话数 20%,记录数 8.2%
hermes 5 个会话 4 个会话 80%
  • claude_code:19 个全部位于项目目录 C--Users-Administrator--memu-hosts-claude-code 下——也就是 bridging 任务工作目录被 slug 化后的名字。它们的第一条 user 记录,逐字就是 memU 自己写进 ~/.memu/hosts/claude-code/bridge-prompt.txt 的那段 bridge prompt:"Run the memU bridging pipeline. Do the four steps strictly in order…"。单个自我会话最大的一个有 449 条记录。
  • hermes:会话 id 为 cron_c3fc5c456385_20260726_130012 / 140013 / 150015 / 160017——整点一次,和 bridging 的调度完全吻合。

某个 hermes 自我会话被挖出来的全部"对话"内容(~/.memu/hosts/hermes/sessions/1.jsonl,222 字节,逐字):

json
{"role": "assistant", "content": "12 jobs ran (5 leftovers + 7 prepared); committed 0 new recall files and 7 resources (install memory/skill already present; bridge sessions meta-only).", "timestamp": 1785050295.8598778}

而它对应的 1_full.jsonl 有 50,896 字节的工具调用。一整个挖掘 job 槽位,就花在了一句运行摘要上——顺带注意挖掘 agent 自己写下的那句 "bridge sessions meta-only":它其实已经察觉到自己在读什么了。

尚未实证、但机制相同的:cursor(20 个已跟踪,key 在 empty-window/agent-transcripts/… 下,需要看内容确认)和 openclaw(每次运行一个隔离 cron 会话)。

为什么这是 bug,而不是无伤大雅

  1. 槽位挤占。 自我会话永远是磁盘上最新的东西,于是在 newest-first 排序里被顶到 discover() 最前面,排在真实对话之前,去挤 MAX_JOBS = 10bridging/pipeline.py:27)。这正是 #533 的那种伤害——非对话的转录吃掉挖掘槽位——只是来源完全不同。
  2. token 燃烧。 每小时一次,对着纯流水账跑一遍 LLM 挖掘。
  3. 污染风险。 尚未归因:store 里确实存在关于 memU 自身运行的记忆,但它们同样可能来自真实的排查对话。下结论之前应当先做归因。

它还毁掉了一条文档所依赖的不变量:INSTALL.mdtranscripts.py:57-58 都把"prepare 返回零"当作平静日子的正常结果。但只要 bridging 装着,平静的日子就不存在了——于是"一直有活干"不再能说明任何事情,包括 #528 里那套沉默失效的诊断。

Steps to reproduce

  1. 按任一宿主的 BRIDGING_TASK.md 安装 bridging 任务;
  2. 让它跑三次以上;
  3. 打开 ~/.memu/hosts/<host>/.session_manifest.<host>.json,找属于 bridging 运行自身的 key——claude_code 上它们在以 ~/.memu/hosts/claude-code 命名的项目目录下,hermes 上它们是 cron_* 会话 id;
  4. 每一个这样的 key,都曾被切片成 job 并挖掘过。

Expected behavior

bridging 运行自己的会话永远不被挖掘。在没有真实活动时,prepare 报零——正如文档已经承诺的那样。

Additional Information

建议的修法——宿主无关,落在 bridging/

在规范的 bridging prompt 里放一行稳定的哨兵标记(每个宿主的 BRIDGING_TASK.md,以及生成的 bridge-prompt.txt),然后让 prepare 跳过第一条 user 记录带该标记的会话。

选这条缝的理由:

  • 那段文本是 memU 自己的——这不是对别人数据的启发式猜测;
  • 不需要任何按宿主写死的路径 hack;对 claude_code 由 cwd 推出的项目目录、hermescron_* id、以及 OpenClaw 的隔离 cron 会话(根本没有任何路径可供区分)都同样有效;
  • 它能扛过 OpenClaw 的 JSONL→SQLite 迁移,因为标记随事件内容走,不随容器走;
  • fail-open:prompt 里没有哨兵的(老安装)行为和今天完全一致——绝不会误跳过任何东西。

锚定在第一条 user 记录、而不是"会话里任意位置",可以避免把真正讨论 bridging 的对话(那些会引用 prompt 原文)误判掉。

考虑过并否决的方案

按宿主做路径/id 排除。那是 N 个各不相同的 hack,而且对 OpenClaw 根本无解。

关联

  • #605:OpenClaw 双读适配器会原样继承这个循环,除非本问题先落地;SQLite 之后每次 cron 运行都是一个新 session_id,只会更显眼;
  • #532 / #533:同一种伤害形状(非对话转录挤占挖掘槽位),不同来源。

Environment: Windows 11,memu-cli 2.0.0-beta.0,仓库 main @ bba0293;在 claude_codehermes 两个宿主上观测到。

Version: memu-cli 2.0.0-beta.0

Severity: Major —— 每次运行都在浪费挖掘槽位与 token,并且抹掉了沉默失效诊断所依赖的"空闲"信号。