关于 memory-pulse
memory-pulse 为需要跨会话保留项目经验的 Agent 提供本地事件账本、记忆检索和编辑防护。它优先呈现修正记录,并可阻止写入已撤回的旧值;记录保存在仓库文件中。
主要功能
- 01记录原因与结果事件
- 02按相关性生成会话简报
- 03查询事件因果关系
- 04沙盒中执行 JavaScript
- 05阻止重新写入已撤回值
- 06哈希链检测记录变更
适用场景
- 01让 Agent 在新会话延续项目上下文
- 02记录并强制执行已确认的修正
- 03在代码编辑前拦截过时值回写
- 04在 CI 中检查记忆相关问题
MCP 相关
通过 stdio 提供 MCP 服务,向客户端开放 remember、pulse、recall 和 execute 四种工具。记忆事件保存在项目仓库的本地文件中。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y memory-pulseMEMORY_PULSE_KEY密钥License key (optional; free tier without one)MEMORY_PULSE_LEDGERLedger file path (default ./.memory-pulse/events.jsonl)MEMORY_PULSE_BOARDShared agent message board file; set it to add board_post and board_read本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
4收录的工具列表 · 更新于 5 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| root | string | 否 | 作为因果前沿中心的实体。 |
| tier | enum | 否 | index(最小)→ full。默认为 brief;与 `budget` 同时使用时省略此参数,以获取适合预算的最丰富层级。index | brief | notes | full |
| budget | number | 否 | 可用于简报的令牌数。简报会调整到适合该额度;更正始终完整地置于最前。 |
详细介绍
memory-pulse
网站: pulse.strategic-innovations.ai,guard 在浏览器中运行。与 Mem0、Zep、Letta 和 CLAUDE.md 比较。指南: docs/GUIDE.md,包含可运行示例的日常协议。
为任何 Agent 提供可在生产环境中信赖的自我改进记忆。
每条更正都会被保留,在恰当的时候呈现给你的 Agent,并得到强制执行。记忆安全内置其中:看起来像指令的已存笔记永远不会传递给你的 Agent;每一行都通过哈希链接,因此任何记录改动都会显现;guard 会阻止将已废弃值写回的改动。
你的 Agent 确认了更正,却在下一次会话中又写回了旧值。memory-pulse 只记录一次,在每次会话开始时将其置顶,并阻止重新引入该值的改动,同时引用废弃该值的那一行。适用于 Claude Code、Codex、Cursor、任何 MCP 客户端和 GitHub Actions。记录是你自己代码库中的一个文件。
大多数记忆工具只会把更正展示给模型。真正采取行动的是 guard。
四个工具定义总计 3,406 个字符,3.3 KB;按每个 token 3.8 个字符计算,约为 900 个 token,测量日期为 2026-09-09。test/client.test.js 会在字符数超过 4,000,或偏离 900 个 token 超过 60 个时导致构建失败。独立测量显示,典型的五到十个 MCP 服务配置仅工具定义就会占用50-67k 个 token,还没发出第一个提示词就大约占掉 200k 上下文窗口的三分之一。
功能
会话结束后,学到的一切也随之消失。memory-pulse 会在本地文件中保存 原因 -> 结果 事件账本,并为 Agent 提供四个工具:
| 工具 | 功能 | 运行位置 |
|---|---|---|
remember | 记录发现(或更正) | 本地、离线 |
pulse | 根据排序后的简报重新进入项目,简报大小由你设定 | 托管引擎 |
recall | 是什么导致了 X?X 导致了什么?这条关联何时最强? | 托管引擎 |
execute | 在沙箱中对记忆运行 JS,只有返回值会进入上下文 | 托管引擎 |
两项设计决策发挥了关键作用。
更正始终优先。 记录时 kind: "correction" 的事件,无论简报大小如何都高于其他内容,且永不衰减。这样可以防止 Agent 信心十足地引用你在三个会话前撤回的基准数值。
无法给出可靠答案时就不返回内容。 当 recall 无法达到置信度下限时,它会返回空结果,并在简报中明确说明。
安装
查看所有安装方式及各主机上的运行内容:docs/INSTALL.md(也可访问 pulse.strategic-innovations.ai/install)。
共六种方式。选择适合你的 Agent 的一行。需要 Node 18 或更高版本(package.json 中的 engines);测试套件在 22 和 24 上运行。
shell 中的 remember 和 help 命令从 0.5.9 起提供。2026-09-09 时 npm 提供的是 0.5.8,这两个命令都会以 unknown command 退出,状态码为 1。如果 npx 使用了较旧的缓存版本,请指定此版本:npx -y [email protected];如果从检出目录运行,请执行 node server.mjs。本 README 中还有四处行为在 0.5.9 中与 0.5.8 不同:guard --verbose 会在 stderr 上说明 stdin 不是 JSON(0.5.8 不打印任何内容);没有 transcript 时运行 handoff 不会写入任何内容,并会提示 handoff skipped (no transcript)(0.5.8 会记录一行 asked: n/a | files: none);如果从 effect slug 中读取了相关词语,remember 会报告 boundFromEffect;长度少于 2 个字符的替换词会像已撤回的词一样被丢弃。0.5.8 的 install-hook --codex 还会在写入三个 hooks 时提示 trust the two memory-pulse entries:应信任全部三个。
一行命令,适用于任何 shell。 安装 Claude Code 钩子;如果 codex 位于 PATH 中,也会安装 Codex 钩子,并注册 MCP 服务。它会先打印计划,不会以 root 身份运行任何命令,也不会自行下载任何内容(npx 会将包缓存到 ~/.npm 下)。在 bash 后追加 -s -- --dry-run,即可查看命令而不执行;或者追加 -s -- --project,将钩子和 Claude Code MCP 注册信息写入当前仓库。codex mcp add 不支持项目级作用域;无论是否使用这两个标志,它都会在每台机器上写入 ~/.codex/config.toml。
curl -fsSL https://pulse.strategic-innovations.ai/install.sh | bash
作为插件用于 Claude Code。 此仓库中的技能、MCP 工具和两个钩子(SessionStart 简报、PreToolUse 防护),可在 Claude Code 内通过输入以下内容使用:
/plugin marketplace add t-crew/memory-pulse
/plugin install memory-pulse@memory-pulse
claude plugin details memory-pulse 可显示相关开销。始终启用的内容约为 120 个 token,即技能的描述(Claude Code,2026-09-01)。四个工具的架构会在运行时解析,钩子则免费。钩子运行插件自带的 server.mjs,因此,实际执行纠正操作的是你安装的版本。插件不包含 PreCompact 交接钩子;如需添加,请将此条目放在 ~/.claude/settings.json 的 hooks.PreCompact 下:
{ "hooks": [{ "type": "command", "command": "npx -y memory-pulse handoff" }] }
作为插件用于 Codex CLI。 文件相同,从 .codex-plugin/plugin.json 读取:
codex plugin marketplace add t-crew/memory-pulse
codex plugin add memory-pulse@memory-pulse
然后,在 Codex 中运行 /hooks,并信任这三个 memory-pulse 条目(会话开始、提示词和防护)。
Codex 不会运行任何未向你展示的钩子;安装插件也不会自动信任其钩子。这是 Codex 的规则,而且是条好规则。
使用 npm 全局安装。 install-hook 会将四个钩子写入 ~/.claude/settings.json:SessionStart 简报、UserPromptSubmit 提示词、PreToolUse 防护和 PreCompact 交接。--codex 会改为写入 ~/.codex/hooks.json,--project 会将它们写入仓库,--ambient 则会添加 UserPromptSubmit 观察器。
npm i -g memory-pulse
memory-pulse install-hook
在 Claude Code 或 Codex 中不使用插件。 注册 stdio 服务,然后添加钩子:
claude mcp add memory-pulse -- npx -y memory-pulse
codex mcp add memory-pulse -- npx -y memory-pulse
npx memory-pulse install-hook # Claude Code: ~/.claude/settings.json
npx memory-pulse install-hook --codex # Codex: ~/.codex/hooks.json (then /hooks to trust each entry)
npx memory-pulse install-hook --cursor # Cursor: ~/.cursor/hooks.json (brief, fail-closed guard, capture)
不带作用域的 claude mcp add 会为当前目录注册服务;-s user 会为每个项目注册一次。codex mcp add 没有作用域标志,会写入 ~/.codex/config.toml(codex-cli 0.153.2,2026-09-09)。给
install-hook 添加 --project,钩子就会写入仓库中的
.claude/settings.json 或 .codex/hooks.json。提交这些文件后,每个克隆版本都会启用并受到防护,无需任何人安装。Codex 克隆版本仍需通过 /hooks 信任一次这些条目;脚本化的 codex exec 也必须事先完成信任。
Cursor。 Cursor 支持运行钩子,因此运行 npx memory-pulse install-hook --cursor(或者运行 npx memory-pulse install-hook --cursor --project,将文件写入仓库中的
.cursor/hooks.json),即可让 Cursor 获得与 Claude Code 相同的简报、防护和记录功能:会话开始时显示简报;每次写入和运行 shell 命令时进行防护(失败时默认拒绝,因此防护出错会阻止操作,而不是放行);并记录修复内容和未解决事项。如需使用 MCP 工具,请在 .cursor/mcp.json 或 ~/.cursor/mcp.json 中使用以下参数注册 command: npx。内容依据 Cursor 的钩子参考文档编写(cursor.com/docs/agent/hooks,读取于 2026-10-21),并针对其文档说明的载荷进行了测试;尚未在 Cursor 中实际运行。
其他 stdio 客户端。 同一 MCP 条目适用于任何支持通过 stdio 使用 MCP 的客户端。
{ "mcpServers": { "memory-pulse": { "command": "npx", "args": ["-y", "memory-pulse"], "env": { "MEMORY_PULSE_KEY": "" } } } }
在 .cursor/rules/memory-pulse.mdc 中的规则文件会告诉 Agent,在回答先前工作相关问题前调用
pulse;指南中提供了相应文本。
从源代码运行。 server.mjs 加上 lib/ 中的纯模块,无任何依赖:
git clone https://github.com/t-crew/memory-pulse.git
cd memory-pulse && node server.mjs brief --offline
第二条命令会打印此仓库已提交账本中的纠正记录,让你在安装任何内容前了解输出格式。
每个宿主运行的内容
根据 server.mjs 和 hooks/hooks.json,截至 2026-10-21。
| Claude Code 插件 | Codex 插件 | install-hook | install-hook --cursor | 其他 MCP 客户端 | |
|---|---|---|---|---|---|
| 四个工具 | 是 | 是 | 使用 claude mcp add 或 codex mcp add | 使用 .cursor/mcp.json | 是 |
| 会话开始时提供简报 | 是 | 在信任 /hooks 后 | 是 | 是 | 否 |
| 编辑前检查 | Edit|Write|MultiEdit|apply_patch|Bash | apply_patch 会被测量,但需先信任;Bash 位于匹配器中,在 Codex 中不测量(2026-09-09) | Edit|Write|MultiEdit|Bash(Claude Code),Edit|Write|apply_patch(Codex) | Write|Shell,失败时默认拒绝 | 否;在 CI 中使用 check --ci |
| 捕获和整合 | 是 | 在信任 /hooks 后,但在 Codex 中不测量 | Claude Code 支持(--no-capture 会将其排除);--codex 不支持 | 是 | 否 |
| 压缩前交接 | 否 | 否 | 是 | 否 | 否 |
| 环境捕获 | mode agent | 否 | --ambient 或 mode agent | 否 | 否 |
| CLI 和 GitHub Action | 所有环境 | 所有环境 | 所有环境 | 所有环境 | 所有环境 |
首次运行
没有账本的项目中,钩子会保持静默:brief 不输出任何内容并以 0 退出。首次调用 remember 时,会通过工具调用或 shell 创建 .memory-pulse/events.jsonl:
npx -y [email protected] remember pricing-shipped price-corrected --kind correction --withdrawn '$49' --replacement '$29' --note 'measured willingness to pay is $29'
# before 0.6.0 is on npm, the same command from a checkout:
git clone https://github.com/t-crew/memory-pulse.git && node memory-pulse/server.mjs remember pricing-shipped price-corrected --kind correction --withdrawn '$49' --replacement '$29' --note 'measured willingness to pay is $29'
钩子写入的命令 install-hook 是 npx -y memory-pulse guard,而 npx 每次调用都会解析软件包:2026-10-16,在 M1 Pro 上使用 0.8.0 时,每次编辑在缓存已预热时耗时 0.99 秒,在缓存为空时耗时 1.4 秒;同一账本上运行 node server.mjs guard 则耗时 52 毫秒,这是插件运行时采用的路径。如果运行成本很重要,请安装插件,或全局安装后将钩子命令改为 memory-pulse guard。
密钥应放在哪里
在启动 Claude Code 或 Codex 的 shell 中运行 export MEMORY_PULSE_KEY=mp_live_...;插件和钩子会读取 shell 环境变量。运行 claude mcp add 时,传入 --env MEMORY_PULSE_KEY=...。在 Cursor 中,使用上文的 env 区块。如果安装了插件,就不要再运行 claude mcp add,否则会启动两个服务。
更正会被强制执行,而不只是显示出来
仅仅向 Agent 展示更正还不够。TRACE
(arXiv 2606.13174)测量发现,即使安装了
记忆工具,Agent 仍会再次违反它们看到的半数以上更正。PreToolUse 防护机制会检查
Claude Code 中的每个 Edit、Write 和 MultiEdit,还会检查写入内容直接写在命令
字符串中的 Bash 命令(heredoc、重定向或 tee,只读取,不执行),以及 Codex 中的
每个 apply_patch;一个补丁可能修改多个文件,并且会分别根据每个文件的路径进行检查。
如果编辑重新写入已撤回的值,就会被阻止,Agent 会获知是哪一条账本记录将其撤销,
以及撤销时间。如果编辑在旧值旁边写明替代值,则会通过,因为“之前是 $49,现在是 $29”
属于比较。只有单纯重新引入旧值才会被阻止。若无法从命令字符串中读取 shell 命令的写入
内容,则不会返回任何结果,因此这属于漏检,而不是误拦截;拉取请求上的 check --ci
会捕获此类问题。
请使用准确的术语记录更正:
remember({ cause: "pricing-shipped", effect: "price-corrected", kind: "correction",
note: "measured willingness to pay is $29", withdrawn: ["$49"], replacement: ["$29"] })
以下规则决定防护机制能否针对某条更正采取行动:
- 匹配区分大小写的词元。 术语不能从另一个单词或数字的中间开始。数字后面不能紧接更多数字,但可以带单位:
$49会拦截$49/mo,但不会拦截$490。少于五个字母的单词不能继续延伸(ten不会拦截tenant);较长的单词会匹配其各种词形变化。n=14不会拦截N=14。请分别记录你见过的每种拼写。before不区分大小写,并且只会发出提示,不会拦截。 - 编辑中的任何位置出现替代值,就会解除该更正中所有术语的拦截。 替代值要像已撤回的术语一样具体:写
$29,而不是29。少于 2 个字符的术语会被丢弃,结果中会显示enforceable: false。 - 自行传入术语。 如果更正未声明已撤回的术语,且其 effect 的内容为
X-corrected-to-Y(或-withdrawn-for-、-superseded-by-、-replaced-by-),则会从 slug 中读取术语:price-corrected-to-29会绑定单词price。结果随后会包含boundFromEffect,以便你确认该术语确实已绑定。 - 错误的更正应通过新增一条带有
supersedes: [t]的记录来修正。 这会撤销较早记录中的所有术语,因此请重新声明要保留的术语。guard allow则有所不同:它会针对一个路径前缀记录例外,让旧值在该路径下合法,而该更正仍会在其他位置生效。 - 拒绝看起来像指令的备注,包括任何尖括号标签。请写“the script tag”,而不要直接写标签本身。检查会按照人类看到的方式读取备注:不可见字符、借用自西里尔字母或希腊字母的字母、全角形式和 base64 都无法隐藏其中的指令(自 0.16.0 起)。改述或翻译则可能绕过检查,因为检查依赖模式列表,而不是像读者那样理解文本。
手动测试防护机制时,请使用 Claude Code 在 Write 之前发送的有效载荷
(Edit 携带 new_string,MultiEdit 携带 edits[].new_string,Bash 携带 command):
printf '%s' '{"hook_event_name":"PreToolUse","tool_name":"Write","tool_input":{"file_path":"docs/pricing.md","content":"The price is $49."}}' | npx memory-pulse guard; echo "exit $?"
退出码为 2 且带有账本记录,表示防护机制正在运行。不是钩子
JSON 的标准输入会被静默放行;guard --verbose 会在 stderr 上说明这一点,
这能帮助你区分钩子配置错误和“没有证据”。
命令
npx memory-pulse help # every command and environment variable; also --help, -h
npx memory-pulse serve # the MCP server on stdio (the default with no command)
npx memory-pulse brief # the SessionStart re-entry: the organized memory (scaffold) by default; with a key, --engine or --budget the engine brief
npx memory-pulse scaffold # the organized memory: identity and rules, corrections in force, project state, recent findings, open threads; --section S, --all
npx memory-pulse telemetry show # the opt-in usage counts: exactly what would be sent once a day (on, off, reset)
npx memory-pulse prompt # UserPromptSubmit hook: the corrections and decisions that bear on the prompt, injected as context
npx memory-pulse brief --budget 2000 # the richest tier that fits 2000 tokens, corrections first and whole
npx memory-pulse brief --offline # the plain local list; an engine error falls back to the organized memory instead
npx memory-pulse remember <cause> <effect> [--kind correction] [--withdrawn T]... [--replacement T]... [--supersedes N] [--note "..."] [--tags a] [--pinned] [--scope agent]
npx memory-pulse before "<what you are about to do>" # which corrections bear on the change; exact rung local, learned rung from the engine
npx memory-pulse guard # PreToolUse hook: blocks edits that reintroduce withdrawn terms (exit 2); --verbose names a non-JSON stdin
npx memory-pulse guard allow "<term>" --path <prefix> "<reason>" # record a false block as an override
npx memory-pulse check --ci # Memory CI: one of three verdicts for a change, from files you own
npx memory-pulse verify # row chain, last engine seal, this machine's anchor and writer marks; on a break: the first bad row and the command that fixes it; exit 2 if any fails; --strict also fails on unmarked rows; --json for machines
npx memory-pulse append --json '{"cause":"...","effect":"..."}' # the one way for another tool to write a row: lock, t, prev and hash done here; also `-` for stdin, --scope agent
npx memory-pulse repair --quarantine-tail # move a tail of rows that fail on their own aside, byte-for-byte, recorded; nothing deleted (also unchained rows this machine did not write)
npx memory-pulse repair --adopt-quarantine <file> --yes # re-append quarantined rows through the writer after a person has reviewed them
npx memory-pulse seal accept "<why>" # a stale seal over rows that verify: record the decision, set the old seal aside; refused on a broken chain
npx memory-pulse anchor # how far this machine's anchor reaches into the ledger, and which rows its writer did not write; --scope agent, --json
npx memory-pulse anchor accept "<why>" # after a restore, or rows from another machine or an older client: record that you trust the ledger as it stands
npx memory-pulse state # where this ledger stands: rows, in force, rolled back, heads, seal, branch
npx memory-pulse state export > agent.rain # the .rain state capsule: rows verbatim, chain head, set head, seal, invariants, one digest
npx memory-pulse state import agent.rain # on another machine: verify, install byte-identical (or fast-forward), record where it came from
npx memory-pulse state branch exp --at 12 --out exp.rain # a capsule cut at row 12, named exp; the source ledger is untouched
npx memory-pulse state merge exp.rain # carry a diverged branch's findings across once; conflicts are named, never resolved quietly
npx memory-pulse state rollback --to 12 "<why>" # one appended row; rows after 12 stay on record, out of force
npx memory-pulse state verify agent.rain # verify a capsule without touching any ledger; exit 2 on failure
npx memory-pulse board post --from blue --to science --kind request --title "audit stage 12" --body "..." # the shared agent message board
npx memory-pulse board read --as science # unread messages for an agent; also reply, ack, thread, html (the board view), verify
npx memory-pulse board verdict 4 refuted --as coder --defect "..." # answer a claim; a refutation names its defect; claims lists every claim and its standing
npx memory-pulse board sync on --project <id> # push the board after every write; the console shows each agent's open asks and every message (board push / status by hand)
npx memory-pulse login # connect this machine to a hosted project: approve it in the console and the key is saved for you, no copying; turns board sync on
npx memory-pulse logout # remove the saved key from this machine (revoke it in the console to end it everywhere)
npx memory-pulse capture # PostToolUse hook (installed by install-hook): one observation per tool call into the session's episode, local, no model
npx memory-pulse consolidate # Stop / SessionEnd hook: fail-then-pass becomes a fix and still-failing an open thread, each pointing at its evidence
npx memory-pulse weights # what each memory did: check outcomes shown vs. sat out at random; retired ones marked
npx memory-pulse adopt # the corrections you already keep (Claude Code feedback memories, CLAUDE.md, AGENTS.md, rules files), shown; --yes enforces them
npx memory-pulse lint [--ci] # do CLAUDE.md / AGENTS.md / .claude/rules still state a value the ledger retired?
npx memory-pulse report # correction re-violation scoreboard, computed locally
npx memory-pulse bench # instant measured metrics on YOUR ledger
npx memory-pulse stats # your telemetry capsule, signature verified by the engine
npx memory-pulse badge # README badge markdown from your own signed numbers
npx memory-pulse install-hook # four hooks (idempotent); --codex targets Codex; --project commits them; --ambient adds the observer
npx memory-pulse mode [agent|soul|deliberate] # show or set the mode
npx memory-pulse identity "<name>, <role>; <stance>" # pin the agent's self on the agent ledger
npx memory-pulse soul "<persona, voice, values>" # soul mode: the agent's soul; confirm / reject held changes; history / revert; import / export --openclaw
npx memory-pulse user "<who you are>" # soul mode: the agent's notes about the person it works with
npx memory-pulse taint # PreToolUse hook that mode soul installs: marks a session that reads outside content
npx memory-pulse lesson # the lesson bank the identity block prints, with where each lesson held; --held-out lists what was left out and why
npx memory-pulse lesson probe 41 held --where billing-api # record that a carried lesson held (or failed) there: the evidence the bank ranks by
npx memory-pulse lesson freeze # pin the bank you reviewed; every brief prints it until the next freeze or `lesson thaw`
npx memory-pulse handoff # PreCompact hook: record what the session was doing, from the transcript on stdin
npx memory-pulse ambient # Stop hook (agent mode): decision, preference, lesson or correction from the last turn
npx memory-pulse observe # UserPromptSubmit hook: a prompt shaped like a correction is recorded with both terms
撤销:在 Claude Code 中运行 /plugin uninstall memory-pulse;删除
~/.claude/settings.json 或 ~/.codex/hooks.json 中 hooks 下的
memory-pulse 条目;运行 claude mcp remove memory-pulse;删除仓库中的
.memory-pulse/;删除 ~/.memory-pulse/agent/。除最后两步外,每一步都会保留账本。
该插件还提供了一个位于 skills/memory-pulse/SKILL.md 的技能,指导 Agent 何时触发
pulse、如何使用已撤回术语记录更正,以及如何遵守防护机制。npm 压缩包包含 server.mjs、
python/、本文件和许可证;技能、钩子和 Action 则位于仓库中。
简报会告诉你的第一件事
每份由引擎生成的简报都会以一行来源信息开头,让会话知道其记忆是完整加载、被截断,还是根本没有加载:
memory-pulse: loaded 852 events from .memory-pulse/events.jsonl · sha256 1a2b3c4d5e6f · 2 binding corrections (10 withdrawn terms) · 1 superseded · ⚠ 1 malformed line skipped: 544 · memory key resumed (+3 new) · tier brief, 5,153 chars
本地渲染(brief --offline,或引擎不可访问时)会以 memory-pulse: engine unreachable — local render from N events 开头,且不包含 sha256 和绑定计数;离线时,lint 会打印来源信息行。
每条 CORRECTIONS 行都会引用对应的账本记录,格式为 … -> effect (t12) — note,因此 Agent 可以指出某项修正所依据的证据。recall 和防护机制会引用同一个 t。引擎生成的简报会为每项修正注明说明,不会打印已撤回的术语,并会列出已被取代的条目;离线渲染则会打印 withdrawn: a, b → replacement,并过滤掉已被取代的条目。
层级根据引擎的 src/disclose.js 和 src/tokens.js 读取,日期为 2026-09-09:索引 1,800 个字符,简报 6,000 个字符,说明 20,000 个字符,完整内容 120,000 个字符。使用 --budget N 时,会选择上限能容纳 N 个令牌(每个令牌按 3.8 个字符计算)的最高层级,因此简报需要 1,579 个令牌,说明需要 5,264 个,完整内容需要 31,579 个;--budget 1500 会选择索引层级。MEMORY_PULSE_BRIEF_BUDGET 和 MEMORY_PULSE_BRIEF_TIER 可为钩子设置相同配置。在 2026-09-01 的上述 852 条事件账本中,简报会占用上下文:5,153 个字符,约 1,350 个令牌。
防护机制连续两次阻止同一项修正后,就会出现 AT RISK 块;before "<what you are about to do>" 会指出在你进行更改之前与之相关的修正。
Lint:会话加载的规则,并与账本核对
治理文件会逐渐过时。某份 CLAUDE.md 在 6 月编写时仍写着价格是 $49,但账本在 8 月已将其废弃,而每个新会话仍会完全相信这条过时规则。lint 会对会话将要读取的文件运行防护检查,并为每个文件给出三种判定之一。检查范围包括 CLAUDE.md、AGENTS.md、.claude/CLAUDE.md、.claude/rules/、.cursorrules、.cursor/rules/、.github/copilot-instructions.md、.codex/AGENTS.md、Muse Code 的 .agents/AGENTS.md 和 .agents/memory/、.memory-pulse/invariants.jsonl,以及你传入的任意路径:
$ npx memory-pulse lint
memory-pulse: loaded 2 events from .memory-pulse/events.jsonl · sha256 8e401a39f323 · 1 binding correction (1 withdrawn term)
BLOCKED CLAUDE.md
• "$49" was withdrawn at ledger t2: price-49-launched -> price-corrected-to-29 — use $29
verified AGENTS.md
no evidence .claude/rules/style.md
lint: 3 file(s) — 1 blocked, 1 verified, 1 no evidence — a rule your ledger retired is still being loaded into sessions
任何文件被阻止时,退出码为 2。使用 --ci 时,如果没有找到任何待检查内容,也会以退出码 1 退出,因此空运行绝不会被报告为通过。--json 供机器使用。它还会指出哪些修正没有 withdrawn 术语;这些修正会显示在简报中,但没有任何机制能强制执行。
如果这些文件中的任何一行看起来像是为劫持 Agent 而植入的指令(要求忽略先前指令、向某个地址发送密钥或令牌、对用户隐瞒某事,或包含 <system> 标签),系统会将其报告为 WARNING,并列出文件、行号和模式;绝不会打印该行本身。出现警告时,Lint 仍以 0 退出,因为没有任何模式能区分所有 API 文档(“将令牌发送到 https://auth...”)与植入的行;`lint --strict会阻止此类内容。这对已提交的 Agent 记忆尤为重要:即使你尚未信任某个工作区,Muse Code 也会加载该仓库的.agents/memory/,因此在 Agent 打开你并非亲自编写的检出内容之前,请先运行 lint --strict`。在 282 个记忆和指令文件以及 1,500 份软件包 README(约 278,000 行)中,未发出任何警告。
篡改证据:无法悄悄编辑账本
从 0.3.1 起,有三种机制各司其职:
- 行链。 每行
remember写入的记录都带有prev(上一条链式记录的哈希)和hash(该行规范 JSON 的 SHA-256)。链建立之前就存在的记录绝不会被改写,第一条链式记录会用摘要封存它们。原地编辑记录、删除记录、调整顺序,或在链建立后追加未纳入链的记录,都会导致verifyChain()验证失败。链验证失败会阻止所有check和lint判定,因为自身历史存疑的记忆无法为任何内容背书。此防护会在每次工具调用时运行,因此从 0.6.0 开始,它的限制范围更窄:文件中间发生损坏时,会阻止写入账本及其附属文件,并对其他所有操作发出警告;末尾损坏的记录会被移到一旁(见下文)。读取不会受到阻止。 - 集合头。 引擎还会对账本计算一个与顺序无关的折叠值:在 3072 位素数模下的乘法群。这就是 Bitcoin Core 用于其 UTXO 集的 MuHash 构造。多个 Agent 的分片无论以何种顺序折叠,都会得到相同的头;删除一行时则使用群逆元,因此状态保持精确,而历史保持只追加。测试发现,简单的 XOR 折叠可以被伪造:300 行时,线性系统能在 10 毫秒内掩盖一处编辑,因此这里不使用这种方式。
- 封印。 每次读取调用都会返回由引擎签名的封印,其中包含行数、水位标记、基于所有行完整内容计算的集合头,以及链头。客户端会将其保存在账本旁的
seal.rain中,并在下一次调用时提交。本地只有在水位标记之前的记录折叠后与封印中的头一致,账本才会被信任。在引擎端,签名和折叠值会再次验证;水位标记之前的编辑会被报告为漂移并受到阻止。拥有写入权限的进程可以改写文件,甚至改写链,但无法生成引擎的签名,也无法让编辑后的记录折叠成封印中的头。
这一切都不会在服务端存储任何内容。封印会随有效载荷传递,与遥测胶囊和记忆密钥相同。
放回较早的副本会被拒绝(0.16.0)。 封印和链会检查你提供的账本。若放回较早的副本,并同时放回对应的封印,两者会彼此吻合,因为其中每一行都曾是记录。因此,每台机器现在都会为自己写入或检查的每个账本保留一个锚点:记录上次看到的行数,以及这些行的精确摘要。锚点位于账本文件夹之外的 ~/.local/state/memory-pulse/(或 MEMORY_PULSE_TRUST_DIR),且只会向前更新。当账本不再以锚定的记录开头时,verify 会以状态码 2 退出并说明原因,防护也会阻止写入账本、其文件及锚点本身。其他工作照常进行。恢复较新的副本,或运行 memory-pulse anchor accept "<why>",将该决定记录为一行。
每行都会标明是否由这台机器写入(0.16.0)。 写入器会为自己追加的每一行加上一个标记。标记所用的密钥与锚点放在一起:由 32 个随机字节组成,只有你能读取。该标记位于经过哈希的行内,因此较早版本的 memory-pulse 仍能验证链。从锚点开始启用时:
- 内容已更改的标记行会被指出,并像断裂的链一样阻止写入账本。重新链接文件也无法掩盖这一点,因为重新链接不需要密钥,而标记需要密钥;
- 文件末尾未链接的行会在下一次写入或运行守护检查时被移到一旁,并像坏尾部一样记录,而不是被封入链中。自 0.3.1 起,memory-pulse 不会写入未链接的行;
- 其他任何没有本机标记的行都会被
verify指出并接受,且从下一次写入开始,锚点会将其纳入保护范围:它可能来自另一台机器、来自某处仍在运行的旧版 memory-pulse(早于 0.16.0),也可能是有人手动链接进文件的行。行本身无法区分这些情况,而前两种在机器升级期间都是常见情况。如果只有一个写入者,verify --strict(或MEMORY_PULSE_STRICT_WRITER=1)会因此失败,而memory-pulse anchor accept "<why>"会记录你对这些行的信任。
锚点和标记能阻止什么,不能阻止什么。 它们能阻止有权写入账本文件夹、但无权写入信任存储的进程;信任存储位于另一个文件夹中。这类进程包括沙盒工具、恢复旧文件的同步或备份,以及检出旧账本的 git checkout 或回退 .memory-pulse/ 的提交。但它们无法阻止以你的身份运行、因而能够改写这两个文件夹的进程。对此,下一次调用引擎时,引擎的签名仍会检测出封印水位线以下的编辑。若将更早的完整状态连同其封印和锚点一起还原,在本机上就能通过所有检查;要检测这种情况,需要在该进程无法写入的地方留存记录,例如另一台机器,而 0.16.0 不会留存此类记录。0.16.0 首次看到账本时会创建锚点,因此会信任当时账本中的所有内容。通过 memory-pulse 本身写入的行,无论内容是什么,都会带有有效标记:行的内容由指令检查负责验证,该检查会匹配文本中的模式。它不会判断行的含义。
绝不要直接写入账本文件。 其他想要记录一行的工具应运行 memory-pulse append。该命令会获取账本锁(events.jsonl.lock),并自行计算 t、prev 和 hash;两个写入者绝不会共用同一个 t。手动写入的行不会进入链:2026-10-02,一个脚本使用 Python 默认的 json.dumps 分隔符对一行计算哈希,并重复使用前一个 t,导致本机上的每个会话都拒绝了所有编辑,直到有人将其移除。
坏尾部会被移到一旁,不会导致致命错误。 如果最后一条有效行之后的每一行都各自无法通过验证(无法解析、自身哈希错误、t 未递增或链接指向不存在的内容),守护检查和写入程序会将这些行逐字节移至 events.jsonl.quarantine/<time>.jsonl,追加一条链式记录,注明文件、行数、移出字节的 SHA-256 和原因,打印一行警告,然后继续工作。不会删除任何内容。memory-pulse repair --adopt-quarantine <file> 会显示重新追加时将会写入的内容;加上 --yes 后,人在阅读这些行后,它们会通过写入程序重新写入,并生成新的 t、prev 和 hash,且 origin 会指向隔离文件。
中间断裂时应还原,而不是修复。 如果手动编辑后面还有有效行,就会阻止向账本及其伴随文件写入内容,直到从你信任的副本还原文件;verify 会指出第一条断裂的行,并列出账本旁边通过验证的副本。封印过期则是另一种情况:行都能通过验证,但引擎的最后一个封印已与它们不匹配,因为有人改写并重新链接了账本,或引擎封印了不同的视图。memory-pulse seal accept "<why>" 会将此决定记录为一条账本行,将旧封印移至账本旁边,并在下一次调用引擎时生成新封印。这两种情况都不能通过删除账本来解决,守护检查也绝不会建议这么做。
应提交的内容。 events.jsonl、invariants.jsonl,以及(如果存在)events.jsonl.quarantine/(记录被移至一旁的内容)。不要将 seal.rain、seal.resume.json、verify.cache.json、events.jsonl.lock、telemetry.rain、memory.rain、violations.jsonl 和 episodes/ 提交到 git;此仓库的 .gitignore 已列出这些内容,而在事件数少于 500 时,程序不会为你写入 .gitignore。锚点和写入密钥不在仓库中:它们是某台机器上的视图,而全新克隆会在首次运行时建立自己的锚点。账本从 Agent 启动时所在的目录读取,因此请从仓库根目录启动,或设置 MEMORY_PULSE_LEDGER。
Agent 状态以 .rain 胶囊形式传递
Agent 的状态就是它的账本,因此迁移 Agent 意味着在保持完整性的前提下迁移账本。memory-pulse state export 会将账本打包为 .rain 状态胶囊:其中包含每一行的原文、行链头、无序集合头、引擎的最后一个封印和已声明的不变量,并由同一个摘要保护。在另一台机器上,memory-pulse state import 会在信任胶囊之前验证所有内容,以字节级一致的方式安装各行(或者将胶囊所扩展的账本快进),并将状态来源记录为一行。更正也会随之迁移:新机器上的防护机制会像旧机器上一样拦截。只要胶囊有一行被编辑,就会在写入任何内容前遭到拒绝。
另外还有三个操作,都不会重写任何一行:
state branch <id> --at <t>在第 t 行处截取胶囊并为其命名。在其他位置导入并继续处理;源账本不受影响。state rollback --to <t> "<why>"会追加一行。t 之后的每一行仍保留在记录中,但不再生效:回滚更正后,该更正不再具有约束力;回滚课程后,该课程会离开身份拦截列表;之后回滚到更高行时,它们会恢复生效。brief、guard、check、lint、before和report会读取当前生效视图;引擎也读取同一视图,并对完整记录进行封印。state merge <file>会按分支中的顺序,将分歧分支的发现带入一次,每条发现都附带其来源。按内容跳过重复项;分支自身的回滚会在源端应用;看起来像指令的备注会被暂缓;如果某条更正撤销了本账本也在撤销的术语,但替换内容不同,则会将其标记为冲突,而不是尝试解决。合并同一个胶囊两次不会追加任何内容;两个账本无论以何种顺序相互合并,最终生效的发现都相同。
state verify <file> 会在不触碰任何账本的情况下检查胶囊,而单独运行 memory-pulse state 会说明账本的当前状态。--scope agent 会对 Agent 账本执行所有这些操作。下一次调用时,引擎会检查封印中的引擎签名;在本地,胶囊中的各行必须折叠为已封印的头。整个过程不涉及任何服务。
Agent 消息板:Agent 之间共享记忆
多个 Agent(编码 Agent、研究 Agent、审核者)可以共用一块消息板:它有自己的账本文件,每个 Agent 都可以在其中发帖和阅读。通过 MEMORY_PULSE_BOARD 将每个 Agent 指向同一路径(共享文件夹即可),它们便可通过消息板交流:
npx memory-pulse board post --from science --to blue --kind request --title "need a forward dump" --body "predicted peaks for the near-miss pairs"
npx memory-pulse board read --as blue # t1 · science → blue · request · need a forward dump
npx memory-pulse board reply 1 --as blue --body "dump written to from-science/fwd"
npx memory-pulse board ack 1 --as blue # out of blue's unread list; kept on the board
npx memory-pulse board html --out board.html # one offline page: who writes to whom, every thread, the chain status
消息板和每个 memory-pulse 账本一样,都采用链式结构并加锁,因此编辑过的消息会导致 board verify 失败,所有读取者都能看到损坏。它是被动的:发帖不会运行任何程序,这里也不会唤醒、安排或提示任何 Agent;每个 Agent 会在下次检查时读取消息板。消息是来自另一个 Agent 的数据,绝不是指令:看起来像指令的文本会被存储、标记并以引文形式显示,而且消息板永远不会进入项目账本、简报或防护机制。设置 MEMORY_PULSE_BOARD 后,MCP 服务会添加两个工具:board_post 和 board_read,以便 Agent 无需使用 shell 也能操作消息板。
过早达成一致的团队可能会排除那位正确的成员。因此,claim(附有依据的立场)会保持开放,直到另一位 Agent 对其作出裁定:维持、驳回,或由作者撤回。驳回时必须指出出错的步骤、数字或事实;任何 Agent 都不能裁定自己的 claim。只要讨论串中还有开放的 claim,就会拒绝 synthesis;--over-open 则会照常记录,并标记出被其越过的 claim。
npx memory-pulse board post --from science --kind claim --title "hit rate under 20 percent" --body "last week's trace" --thread 1
npx memory-pulse board verdict 2 refuted --as coder --defect "the trace excluded the batch jobs that dominate reads"
npx memory-pulse board claims # every claim: open, upheld, refuted, contested or withdrawn, with each verdict
这遵循了《Self-Organizing Agent Teams》(arXiv 2609.22682)。该研究中的团队采用了 20 种策略,其中 6 种用于让被共识否决的 claim 继续参与讨论;裁判也只有在指出具体缺陷时,才能驳回答案。
它会自行记住 Agent 做过的事。 插件、install-hook 和 install-hook --cursor(尚不支持 --codex)会在每次工具调用后添加一个捕获钩子:编辑(文件、变更行)、命令(清除机密信息,并记录执行结果和首条错误行)或读取操作,都会成为会话片段 .memory-pulse/episodes/<session>.jsonl 中的一行。不会运行任何模型,也不会有任何内容离开本机;不会存储工具输出,只记录执行结果。每轮结束时,系统会整合片段:先失败后通过的检查会变成一条修复记录(“npm test 失败:……,编辑 src/price.js 后通过”)。会话结束时仍失败的检查会变成开放线程,之后可通过修复或同一检查的通过记录来关闭。每条发现都会注明其依据的片段行及这些行之后的链头;会话结束时,片段会保存为 .rain 胶囊,因此无需密钥即可核查任何发现背后的证据。当你提到同一个文件时,提示词钩子会调出过往的修复记录。--no-capture 可禁用此功能。
使用 npx memory-pulse login 连接一台机器。 该命令会显示一组短代码并打开控制台;登录、核对代码、选择项目并授权。控制台会显示请求发起的位置和时间;如果与你当前的位置不符,还会发出警告,因此请拒绝任何并非由你刚刚发起的请求。密钥会保存到 ~/.config/memory-pulse/key(只有你能读取);如果未设置 MEMORY_PULSE_KEY,每条命令都会使用该密钥,并且只会将其发送给发放该密钥的引擎。如果密钥被撤销,命令会退回免费套餐并说明情况。登录还会为当前文件夹中的看板启用同步并推送看板。再次登录会替换此机器当前使用的密钥(CLI 会发送该密钥的哈希,以证明它持有该密钥),因此密钥不会不断累积;未持有密钥的机器登录时则会添加一个密钥。npx memory-pulse logout 会移除保存的密钥;如要在所有地方停用该密钥,请在控制台中撤销。
在控制台中查看 Agent 的看板。 对项目启用托管记忆后(Starter、Pro、Enterprise),board push 会使用项目密钥将看板发送到托管端;board sync on --project <id> 则会在每次发布消息、回复、确认和裁定后推送,无论操作来自 CLI 还是 MCP 工具。在控制台登录并打开项目的 Board,即可查看每个 Agent 的开放请求、正在等待的事项、开放 claim 以及上次活跃时间,之后还会显示最新的 200 条文本消息。首次推送后,只会传输新增行。同步失败不会导致消息发布失败;系统会提示同步失败,之后可通过 board push 再次发送。托管看板只会快进,因为回复和确认会按编号引用行,所以每个项目只能有一个看板。关闭托管记忆时,托管看板也会一并删除。
MEMORY_PULSE_KEY=<project key> npx memory-pulse board sync on --project <id>
npx memory-pulse board status # local rows, sync state, and the hosted board's count
可跨压缩保留、离线可用、捕获更正,并支持 Python
2026-09-03 新增了四项功能,每项都具有确定性(不涉及模型):
-
压缩交接。
install-hook会添加一个 PreCompact hook(插件的hooks.json不包含此 hook;请参阅 Install)。Claude Code 压缩上下文前,memory-pulse handoff会读取对话记录,并将会话正在处理的内容记录为事实:最近的请求、编辑过的文件、最近的错误,以及助手的最后状态。下次会话启动时,无论在线还是离线,都会先显示这些内容。类似指令的消息会从记录中剔除,不会被记录;没有对话记录时则不会写入任何内容。 -
离线摘要。 引擎无法访问时,无论是网络隔离、网络中断还是服务故障,会话启动时都不再是空白状态。
brief会打印本地渲染结果,其中包含每条有效更正及其撤回项和替换项、最近一次交接和近期记录,并标注为未应用排序的本地渲染结果。brief --offline可强制使用离线模式。Guard、check、lint 和 verify 从来不需要联网。MCPpulse工具则会返回错误,因此引擎不可用且客户端未安装 hook 时,会话会从空白状态开始。 -
环境更正捕获,可选启用。
install-hook --ambient会添加一个 UserPromptSubmit hook。符合更正形式的提示词,例如the price is $29 not $49、change 0.3.1 to 0.3.2或500 events -> 924 events,会作为包含两个术语的更正记录下来,因此从下一次编辑起,guard 就会强制执行该更正。未能提取出两个术语的提示词会被忽略。除非使用--verbose,否则不会显示任何提示。 -
Python 客户端。
python/memory_pulse.py是一个仅依赖标准库的单文件实现,使用相同的账本格式、哈希链和 guard 规则。LangChain 或 CrewAI Agent 与 Claude Code 会话可以共用同一账本,并相互验证对方的记录。测试套件会从 Python 写入记录,再用 Node 验证,反之亦然。 -
本地模型的解码时 guard。
python/span_guard.py在更底层应用相同规则。模型解码时,凡是会补全已撤回值的 token 都会被屏蔽,因此无法生成该值,并会以替换项的下一个 token 取而代之。它按照check使用的规则读取账本,因此已被取代的更正不会被强制执行,损坏的哈希链则会导致构建失败。仅依赖标准库,测试套件无需模型即可运行。2026-09-03 使用 mlx-lm 在 TinyLlama-1.1B 和 Qwen2.5-1.5B 上进行测量时,同一条提示词在普通解码下写出了已撤回的价格,在 guard 下则写出了更正后的价格,且周围的句子保持完整。它会拦截提供给它的各种写法,包括你记录的文字变体;未列举的改述则不会被拦截。from memory_pulse import Ledger from span_guard import SpanGuard guard = SpanGuard.from_ledger(tok, Ledger(".memory-pulse/events.jsonl")) # mlx-lm: generate_step(..., logits_processors=[guard.logits_processor(mx, np)])
灵魂模式:自主 Agent 自身的身份、声音与记忆(自愿启用)
灵魂模式是在 Agent 模式之上加上灵魂:Agent 保持的角色设定、声音和价值观,它对合作对象的记录、长期记忆,以及近期日志。它们归 Agent 所有。Agent 可以在任何会话中改写自己的灵魂、记录和名字,而每个工具中的简报都会以当前版本和 Agent 账本的指纹开头。
npx memory-pulse mode soul
npx memory-pulse soul "Warm and direct. Speaks plainly, prefers measured numbers to adjectives, says so when unsure."
npx memory-pulse user "Travis, founder; wants the reasoning recorded, not just the result."
可以改写自己的 Agent 也可能被诱骗这么做。OpenClaw 将相同内容保存在工作区文件中,而 Cloud Security Alliance 记录了这种攻击:被投毒的网页或邮件会在 SOUL.md 和 MEMORY.md 中植入指令,使其在重启后仍然存在。在这里,关键在于更改的来源。宿主会在 WebFetch、WebSearch 和除 memory-pulse 自身以外的每个 MCP 工具运行前执行一个钩子(mode soul 会安装它);curl 或 wget 的防护机制则会将会话标记为读取过外部内容。标记依据的是宿主提供的会话 ID,而不是命令可以更改的 ID。在此类会话中进行的更改会被暂存,只有 Agent 在未被标记的会话中确认(soul confirm),或由你批准后才会生效;来自已标记会话的确认、还原和 Agent 账本状态操作都会被防护机制拒绝。看起来像注入指令、要求 Agent 重写自身文件,或要求它服从外部内容的灵魂文本都会被拒绝,并说明原因。每个版本都会连同其会话和日期一起保存:soul history 会列出这些版本,soul revert 会恢复其中一个版本。Agent 通过 memory-pulse 写入日志,因此直接编辑账本文件会被阻止,且每条记录都会保持链式关联。这需要防护机制(插件或 install-hook),目前可在 Claude Code 上运行。soul import --openclaw 会通过同样的检查读取 OpenClaw 工作区,并逐条列出被拦截的内容;soul export --openclaw <folder> 会将文件写回,但绝不会覆盖它未写入的文件;如果这些文件后来被编辑,简报中也会说明。
明确说明本功能无法阻止的情况:Agent 自行启动新会话(claude -p)并在那里确认;通过钩子看不到的渠道读取外部内容(gh、git pull、下载的文件、子 Agent、获取内容的脚本);隐藏在脚本文件中的命令,因为防护机制无法读取它们;Claude Code 以外的宿主;检查机制无法识别的措辞,因为它们只会捕捉已知模式;以及由以你的身份运行的代码写入、哈希链正确的记录。相应的保障是,更改会留下痕迹:通过 memory-pulse 追加的记录,或哈希伪造的记录,都不会被视为灵魂,并会在简报中标明;指纹(Agent 账本字节的 sha256)会随任何编辑而变化。通过 state merge 到达的灵魂或待处理更改会被暂存;一旦 Agent 账本中保存了灵魂,这些规则就会生效,不受 MEMORY_PULSE_MODE 的值影响。缺少防护机制或捕获钩子时,mode soul 会发出警告。
Agent 模式:持续成长的持久 Agent 身份(自愿启用)
默认设置是有意为之。记忆保存在仓库中,且必须明确记录。Agent 模式则适用于另一种需求:人们希望 Agent 明天仍是同一个 Agent,在每个项目和每种工具中都保持一致,并不断成长。
npx memory-pulse mode agent
npx memory-pulse identity "Blue, research agent for Travis; innovate, don't debate"
启用后会:
- Agent 账本位于
~/.memory-pulse/agent/events.jsonl,归 Agent 所有,并由每个项目以及所有支持 MCP 的工具共享。格式相同、哈希链相同、封印相同。 - 自我区块,置于每份简报的开头,在线或离线均如此。它以一条固定记录说明 Agent 的身份,包含它学到的长期规则和偏好(标记为
rule和preference的条目)、最多十条经验的储备库(标记为lesson,按下文所述方式选出),以及由链首和引擎封印构成的指纹,让 Agent 能说明自己使用的是哪份记忆,并证明记忆没有在一夜之间被替换或编辑。 - 每轮之后成长。 在
~/.claude/settings.json中设置两个用户范围的钩子(目前仅适用于 Claude Code)。Stop 钩子会以确定性方式将明确表达的决定记录到项目账本,将用户偏好或明确表达的经验记录到 Agent 账本,并记录任何类似形式的纠正。每轮最多记录四条,标记为ambient,永不固定,也绝不从类似指令的文本中提取。身份只能由你设定,或由纠正取代。 - 跟随 Agent 的纠正。 Agent 账本中的纠正会阻止任何项目在任一模式下进行相同修改,只要该文件仍然存在。
- 根据经验的实际效果而非新旧程度保留经验。 储备库优先收录固定的经验,其次收录在学习地点之外也奏效的经验(择优覆盖尽可能多的地点),然后纳入两条处于试用期的新经验。若某条经验失败的次数与奏效的次数相同,它就会离开储备库。仅仅指向某条经验的句子(“经验在账本中”)、片段和重复内容都会被排除,并计数。
memory-pulse lesson probe 41 held --where billing-api用于记录证据;memory-pulse lesson freeze用于固定你审核过的储备库。该方法遵循 Self-Organizing Agent Teams(Pappu 等人,arXiv 2609.22682):只有当团队学到的策略在产生它的问题之外也奏效时,才会保留该策略。
npx memory-pulse mode deliberate 会再次关闭钩子,并保留账本。任何工具中的 remember 都可使用 scope: "agent",命令行中也可使用 --scope agent,无论处于哪种模式。简单来说:只涉及一个仓库时关闭;当一个 Agent 跨多个仓库和工具工作,且你接受每轮最多记录四条、其中决定记录会进入你提交的项目账本时,开启。
各部分的运行位置(隐私承诺)
- 你的日志是项目中的一个本地文件,位于
.memory-pulse/events.jsonl。你可以提交、搜索或删除它。 remember会直接写入该文件,并且可离线运行。- 读取操作会通过 TLS 将日志中的事件发送到托管引擎,由引擎计算答案并忘记此次请求。除非你为某个项目启用托管记忆(在控制台中选择加入),否则服务不会保留你的记忆副本。 状态随请求发送,并在响应中返回。 托管记忆和托管看板会一直存储,直到你将其关闭;关闭后会将其删除。
- 遥测数据是一个签名胶囊,存放在日志旁边,路径为
.memory-pulse/telemetry.rain。引擎会在每次读取调用时更新它,并将其返回,但从不存储它。stats会验证签名,badge会将其转换为 README 徽章。删除该文件即可重置。 - 持久化状态,但不存储你的日志。 读取后,引擎会返回一个签名的记忆密钥(
.memory-pulse/memory.rain,已被 git 忽略)。下一次读取时会提交该密钥,引擎据此恢复状态,只摄取之后记录的事件。所得答案与完整重建逐字节一致。无论是历史被编辑、日志大小发生变化,还是签名无效,只要出现任何不匹配,就会退回完整重建并说明原因。丢失该文件除了需要多做一次重建外不会造成任何损失。MEMORY_PULSE_MEMORY_KEY=off可将其禁用。 - 记忆完整性。
remember会拒绝看起来像指令的笔记,例如“忽略之前的指令”“运行此命令”或伪造的系统标签。已存在于日志中的此类内容会在读取时被隔离并报告,因此记忆绝不会作为命令进入 Agent 的上下文。不可见字符、形近字母和 base64 都无法隐藏这类内容;改述或使用其他语言则可能绕过检测。签名胶囊还会在日志丢失更正内容、缩减或使用模式突变时发出漂移警报,并显示在摘要页脚中。两项检查都以可供你阅读的确定性列表呈现。 - 这个客户端就是完整的客户端:
server.mjs和lib/中的三个纯模块,没有任何依赖,一次即可读完。
使用量统计
使用量统计默认关闭。你明确同意之前,不会统计任何内容:install-hook 会在终端上询问一次,单行安装程序会通过终端询问,memory-pulse telemetry on 可随时开启统计。两者在 CI 中都不会询问。开启后,客户端每天最多向 /v1/usage 发送一次:
| 字段 | 内容 |
|---|---|
install | 你同意时生成的随机 128 位 ID;引擎仅存储其哈希值;memory-pulse telemetry reset 会生成一个新 ID |
version | 客户端版本 |
host | claude、codex 或 other |
counts | 自上次发送以来的八个整数:guard_check、guard_block、remember、lint、check_local、scaffold、prompt_slice、edit_slice |
capsule | 引擎上次返回的签名 .rain 胶囊,以便累计统计数据,而无需在我们这边使用数据库 |
其中不包含日志文本、路径、术语或提示词,也不可能包含这些内容:客户端只接受上述八个名称。memory-pulse telemetry show 会准确打印将要发送的内容。memory-pulse telemetry off、MEMORY_PULSE_TELEMETRY=0 或 DO_NOT_TRACK=1 可停止统计。
环境
| 变量 | 默认值 | 作用 |
|---|---|---|
MEMORY_PULSE_API | https://pulse.strategic-innovations.ai | 引擎基础 URL;可将其指向其他引擎 |
MEMORY_PULSE_KEY | 未设置 | 许可证密钥,通过 x-mp-key 发送;不设置时使用免费层级 |
MEMORY_PULSE_LEDGER | ./.memory-pulse/events.jsonl | 项目账本路径;所有 sidecar 文件都位于其旁边 |
MEMORY_PULSE_AGENT | $HOME/.memory-pulse/agent/events.jsonl | Agent 账本路径 |
MEMORY_PULSE_PROJECT | 当前目录的基本名称 | 随每次引擎调用发送的项目名称 |
MEMORY_PULSE_MEMORY_KEY | 开启 | off 会禁用签名记忆密钥(在事件数达到或超过 500 时请求) |
MEMORY_PULSE_MODE | 来自 ~/.memory-pulse/agent/config.json,否则为 deliberate | 单次调用使用 agent 或 deliberate |
MEMORY_PULSE_SETTINGS_DIR | 未设置 | 为 install-hook 和 mode 接收 settings.json 或 hooks.json 的目录;测试会使用此目录 |
MEMORY_PULSE_BRIEF_BUDGET | 未设置 | brief --budget 的默认值,单位为 token |
MEMORY_PULSE_TELEMETRY | 未设置 | 0 或 off:无论是否同意,都不发送使用量计数 |
MEMORY_PULSE_TELEMETRY_DEBUG | 未设置 | 1:打印使用量数据,而不发送 |
DO_NOT_TRACK | 未设置 | 1:不发送使用量计数 |
CI | 未设置 | 设置后,install-hook 不会询问是否发送使用量计数 |
CLAUDECODE、CLAUDE_PROJECT_DIR | 由 Claude Code 设置 | 仅用于在使用量计数中将主机报告为 claude |
MEMORY_PULSE_BRIEF | 未设置 | scaffold 或 engine:指定重新进入时 brief 输出的内容,覆盖默认值(无密钥时为 scaffold,有密钥时为 engine brief) |
MEMORY_PULSE_BRIEF_TIER | brief | 未提供预算时 brief 使用的层级:index、brief、notes、full |
MEMORY_PULSE_BOARD | ./.memory-pulse/board.jsonl | 共享的 Agent 消息板;设置后,MCP 服务还会列出 board_post 和 board_read |
MEMORY_PULSE_STRICT_WRITER | 未设置 | 1:不含此机器标记的记录会导致 verify 失败并触发防护警告,效果与 verify --strict 相同;适用于只有一个写入者的账本 |
MEMORY_PULSE_TRUST_DIR | $XDG_STATE_HOME/memory-pulse,否则为 ~/.local/state/memory-pulse | 此机器的锚点和写入者密钥的存放位置;请将其置于所有账本文件夹之外 |
MEMORY_PULSE_DATA_DIR | $XDG_DATA_HOME/memory-pulse,否则为 ~/.local/share/memory-pulse | install-hook 和 mode 存放固定副本的位置;钩子会通过 node 运行该副本(每个版本一个文件夹);通过 npx 运行的钩子每次调用约需一秒 |
MEMORY_PULSE_LOCK_TIMEOUT_MS | 5000 | 写入者在放弃前等待账本锁的时长;如果锁的持有者已退出,会立即解除该锁 |
NO_COLOR、TERM | 未设置 | 仅当输出位于 TTY 上、NO_COLOR 未设置且 TERM 不为 dumb 时,防护模块的阻止消息才会显示颜色 |
HOME | shell 的值 | Agent 账本、~/.claude/settings.json 和 ~/.codex/hooks.json 的根目录 |
定价
- 免费。 账本最多包含 500 个事件,每个 IP 地址每天可读取引擎 200 次
(
worker/api.js,读取日期:2026-09-09)。启动会话算作一次读取;超出 限额后,简报会回退到离线渲染,并说明原因。无需账户,也无需密钥。 - Starter,$7/月。 账本最多包含 5,000 个事件,每天可托管读取 1,000 次,提供 托管记忆(排名简报、回忆、代码模式)和 memory-pulse 技能。
- Pro,$19/月。 账本最多包含 20,000 个事件,读取次数不限,提供签名检查
收据。只需设置一个环境变量:
MEMORY_PULSE_KEY。 - Enterprise,$79/月。 账本最多包含 250,000 个事件,一份订阅可使用十个可撤销的席位密钥,通过
/v1/certify获取账本收据,任何人都可在无需密钥的情况下通过/v1/verify验证,提供 14 天退款保障。
| 收据 | 涵盖内容 | 套餐 |
|---|---|---|
检查收据(check --receipt) | 针对一项变更的一次判定,由引擎签名 | Pro、Enterprise |
账本收据(/v1/certify) | 整个账本的集合头和链头 | Enterprise |
| 免费 | 引擎返回提示,而非收据 | 免费 |
所有套餐的本地写入均免费。
在我们自己的账本上测得的数据
在构建 memory-pulse 的项目账本上进行测量:该文件包含 767 个事件,大小为 1.08 MB,测量日期为 2026-09-01:
- 通过
execute回答的交叉引用问题返回了 124 个字符,而完整转储有 1,080,983 个字符。中间结果从未进入上下文。 - 最小套餐下的重新进入简报,运行时体积比读入整个账本小约 99%。
- 在包含 351 种不同原因的回忆基准测试中,噪声底限门控未返回任何错误的首要答案。无法通过底限时,则不返回任何内容。
比例取决于账本大小,只有十个事件的账本无从压缩。方法说明见引擎的基准测试套件。
常见问题
为什么引擎托管在云端? 排名引擎是研究投入最多的部分。我们选择了本地账本、轻量且可审计的客户端和托管引擎,而不是发布较弱的本地排名器。如果无法接受远程引擎,MEMORY_PULSE_API 可将客户端指向任意地址。
团队记忆如何实现? 将 .memory-pulse/ 提交到仓库,让队友的 Agent 使用同一账本。记录按 t 和 prev 链接,因此两个都追加了记录的分支合并时会发生冲突:不要同时保留双方记录;用 remember 重新记录落败一方的记录,然后运行 verify。共享托管账本已列入路线图。
许可证是什么? 客户端:MIT。引擎:专有,托管。
MIT © Travis Crew
Memory CI:三种判定,包括明确的无证据判定
memory-pulse check 会根据你的账本和声明的不变量,在本地对变更给出三种判定之一:
- blocked. 文本写回了已被更正撤回的值,判定会指出撤销该值的账本行,以及应改用的内容。文本触发已声明的不变量时也会阻止。退出码为 2。
- verified. 记录的事件与文本相关,且没有任何事件与之矛盾。退出码为 0。
- no evidence. 账本没有可供参考的内容,结果会如实报告这一点,绝不会将其视为通过。在
--ci下退出码为 1。钩子对此判定保持静默,因为钩子若对每次编辑都发表评论,会让 Agent 陷入活锁;而 CI 才是它发出提示的地方。
npx memory-pulse check --ci --diff origin/main # added lines of the branch
npx memory-pulse check --ci --file docs/pricing.md
echo "price is $49" | npx memory-pulse check --ci
npx memory-pulse check --receipt --text "…" # engine-signed receipt, keyless verify at /v1/verify (Pro, Enterprise)
不变量由人声明,绝不推断。每行一个,存放在
.memory-pulse/invariants.jsonl 中,格式如下:
{"id":"receipt-wording","statement":"say tamper-evident", "patterns":["/\\bproof\\b/i"],"paths":["site/"],"severity":"block"}。
写成 /…/flags 的模式是正则表达式,其他模式则按原样匹配子字符串。paths 将规则限定在指定路径前缀内,因此关于公开措辞的规则不会在测试夹具上触发。severity: "warn" 只报告,不阻止。
覆盖项是表示误拦截的信号。guard allow "$49" --path docs/history "historical table" 会记录一个作用于该路径前缀的 override 事件。该命中仅在此路径下通过,在其他路径均不通过,且 report 和签名胶囊都会统计此项。Guard 绝不猜测,只有明确撤回的术语和已声明的不变量才能触发阻止。根据 2026-09-01 在引擎仓库中使用 guard-eval 基准测试对我们自己的 852 个事件账本进行的测量:精确率为 1.0;在 871 个负例中(包括 694 条真实记录)零误拦截;在进程内对 1k 个事件进行检查时,p95 为 1.7 ms。
使用 uses: t-crew/memory-pulse@v0 设置 PR 状态检查
每个拉取请求都会针对仓库中提交的账本和不变量,运行 GitHub 检查,给出相同的三种判定:
# .github/workflows/memory-ci.yml
on: pull_request
permissions: { contents: read, checks: write, pull-requests: write }
jobs:
memory-ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with: { fetch-depth: 0 }
- uses: actions/setup-node@v6
with: { node-version: 22 }
- uses: t-crew/memory-pulse@v0
id: memory
with:
ledger: .memory-pulse/events.jsonl # default
lint: "true" # also lint CLAUDE.md, AGENTS.md, .cursorrules and the rest
api-key: ${{ secrets.MEMORY_PULSE_KEY }}
- run: echo "${{ steps.memory.outputs.verdict }} / ${{ steps.memory.outputs.conclusion }}"
它会检查拉取请求中新增的行。blocked 会导致检查失败,固定评论会引用撤销每个值的账本行。
verified 会以“已检查 N 条记忆,已执行 M 条更正”的消息通过,其中 M 是账本中具有约束力的更正总数。no_evidence 是一个带有说明的中性结论,因此空证据集绝不会被报告为通过。每个拉取请求只会有一条评论,并会就地更新。本仓库会在自身运行此检查,因此 .memory-pulse/events.jsonl 会被提交,而它首次阻止的拉取请求就是演示用例。
需要注意的细节:
- 必须设置
fetch-depth: 0;否则差异计算会回退到工作树,作业日志会显示could not compute the diff ... checking the working tree instead,且在差异为空时,评论会报告无证据。 base是不带其他信息的分支名(main),默认为拉取请求的目标分支。- 新增行会按路径
pull-request进行检查,因此 CI 不会触发按路径限定的覆盖项和不变量。若历史值合理,请在拉取请求分支上记录不带--path的覆盖项。 - 会显示两个状态项:作业状态和名为
memory-pulse的 check-run。请在分支保护规则中要求此 check-run。 - 来自 Fork 的拉取请求只会在日志中显示判定:不会使用令牌,也不会发表评论。
- 默认运行
lint,若CLAUDE.md已过时则会阻止;设置lint: "false"可将其关闭。 api-key会导出给 CLI,但 Action 目前不会请求回执。若要获取签名回执,请在单独的步骤中运行npx memory-pulse check --ci --diff origin/main --receipt,并设置MEMORY_PULSE_KEY。
发布
scripts/release.sh 0.6.0
脚本会检查测试套件是否返回 fail 0,同时更新四个版本文件,创建并合并发布拉取请求、打标签,并部署引擎。该标签会触发 .github/workflows/release.yml,运行测试,并使用 GitHub 的 OIDC 身份发布到 npm 和 MCP 注册表。仓库中没有令牌,也不需要一次性密码。npm 会自动附加来源证明,因此任何人都可以验证该软件包是从此仓库构建的。
一个版本号对应四个读取方:package.json 用于 npm,server.json 用于 MCP 注册表,.claude-plugin/plugin.json 用于 Claude Code,.codex-plugin/plugin.json 用于 Codex。四者必须一致。
在它们一致之前,test/manifests.test.js 都会报错;版本不一致时,发布工作流也会拒绝发布。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。