mcpField
M
memory-pulse

memory-pulse

本地服务
github.com/t-crew记忆与知识06 天前更新

关于 memory-pulse

memory-pulse 为需要跨会话保留项目经验的 Agent 提供本地事件账本、记忆检索和编辑防护。它优先呈现修正记录,并可阻止写入已撤回的旧值;记录保存在仓库文件中。

主要功能

  1. 01记录原因与结果事件
  2. 02按相关性生成会话简报
  3. 03查询事件因果关系
  4. 04沙盒中执行 JavaScript
  5. 05阻止重新写入已撤回值
  6. 06哈希链检测记录变更

适用场景

  1. 01让 Agent 在新会话延续项目上下文
  2. 02记录并强制执行已确认的修正
  3. 03在代码编辑前拦截过时值回写
  4. 04在 CI 中检查记忆相关问题

MCP 相关

通过 stdio 提供 MCP 服务,向客户端开放 remember、pulse、recall 和 execute 四种工具。记忆事件保存在项目仓库的本地文件中。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"t-crew-memory-pulse": {
"command": "npx",
"args": [
"-y",
"memory-pulse"
],
"env": {
"MEMORY_PULSE_KEY": "<MEMORY_PULSE_KEY>",
"MEMORY_PULSE_LEDGER": "<MEMORY_PULSE_LEDGER>",
"MEMORY_PULSE_BOARD": "<MEMORY_PULSE_BOARD>"
}
}
}
}
启动命令npx -y memory-pulse
需要配置的环境变量
MEMORY_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmmemory-pulse0.16.1

工具

4

收录的工具列表 · 更新于 5 天前

参数类型必填说明
rootstring否作为因果前沿中心的实体。
tierenum否index(最小)→ full。默认为 brief;与 `budget` 同时使用时省略此参数,以获取适合预算的最丰富层级。index | brief | notes | full
budgetnumber否可用于简报的令牌数。简报会调整到适合该额度;更正始终完整地置于最前。

详细介绍

memory-pulse

npm license MCP

网站: 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-hookinstall-hook --cursor其他 MCP 客户端
四个工具是是使用 claude mcp add 或 codex mcp add使用 .cursor/mcp.json是
会话开始时提供简报是在信任 /hooks 后是是否
编辑前检查Edit|Write|MultiEdit|apply_patch|Bashapply_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 从来不需要联网。MCP pulse 工具则会返回错误,因此引擎不可用且客户端未安装 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客户端版本
hostclaude、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_APIhttps://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.jsonlAgent 账本路径
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_TIERbrief未提供预算时 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-pulseinstall-hook 和 mode 存放固定副本的位置;钩子会通过 node 运行该副本(每个版本一个文件夹);通过 npx 运行的钩子每次调用约需一秒
MEMORY_PULSE_LOCK_TIMEOUT_MS5000写入者在放弃前等待账本锁的时长;如果锁的持有者已退出,会立即解除该锁
NO_COLOR、TERM未设置仅当输出位于 TTY 上、NO_COLOR 未设置且 TERM 不为 dumb 时,防护模块的阻止消息才会显示颜色
HOMEshell 的值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 都会报错;版本不一致时,发布工作流也会拒绝发布。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。