
ECC Unified Memory用 Memory Vault 打通 Claude、Codex 与 Hermes 之间的跨 Agent 上下文交接【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECCECCThe agent harness performance optimization system通过 Unified Memory 技能与本地 Memory Vault为 Claude、Codex、Hermes、Cursor、OpenCode 等不同 Agent 运行时harness提供了一个共享、可检查、可审计的持久化上下文层。本文以 .agents/skills/unified-memory/SKILL.md 为主体结合 scripts/memory.js、scripts/lib/memory-vault.js 与 scripts/lib/memory-vault-format.js 的源码实现完整讲解 Vault 的三个作用域、ecc memoryCLI 的四步工作流recall / save / handoff / doctor、ecc.memory.v1文档格式的硬性约束以及可选的 MCP 接入方式。读完本文你可以独立配置并安全使用 Memory Vault在不同 Agent 之间保存、检索与交接持久上下文并理解其 fail-closed 的安全边界在源码中如何落地。Unified Memory 是什么ecc.memory.v1 可移植文档Unified Memory 技能定位是跨 harness 的公共上下文层Vault 存储的是可移植的ecc.memory.v1Markdown 文档而不是某个 harness 私有的会话记录transcript或收件箱inbox。这意味着每条记忆是一个独立的 Markdown 文件带严格校验的 frontmatter 元数据任何能读文件系统的 harness 都能消费文档格式由 scripts/lib/memory-vault-format.js 中的MEMORY_SCHEMA_VERSION ecc.memory.v1固定不匹配的 schema 在解析时直接报错Unsupported memory schema.记忆之间通过links字段建立关联而不是靠覆盖历史来更新状态。技能目录中还包含 agents/openai.yaml 等接口元数据声明该技能允许隐式调用allow_implicit_invocation: true。适用场景与明确边界技能文档明确给出使用与不使用的场景应该使用 Vault 的场景保存需要其他 Agent 或后续会话使用的持久上下文在 Claude 与 Codex、Hermes 与 Claude 或任意 harness 对之间交接工作恢复任务时检索此前的决策、事实、教训或交接记录诊断格式错误的记忆、失效链接、重复 ID 或被跳过的符号链接。不应把 Vault 当作任务跟踪器task tracker密钥/秘密存储secret store策略引擎policy engine受治理项目文档的替代品。运行时前提技能本身不是可执行程序技能文档特别强调SKILL.md 只是指导文档不是 Memory Vault 的可执行部分。仅安装技能skill-only、最小安装minimal、手动安装manual或 Claude 插件plugin安装都不会在PATH上创建所需的命令。在使用 CLI 或 MCP 示例前需要单独安装ecc-universalnpm 运行时npm install -g ecc-universal ecc memory --help command -v ecc-memory-mcp在仓库检出checkout中也可以直接以 Node 方式运行 CLInode scripts/ecc.js memory ...但需要注意如果 MCP 配置引用了ecc-memory-mcp这个命令该二进制仍然必须位于PATH上仓库检出方式不能替代全局安装。Vault 作用域project、team 与 userVault 将记忆按三个作用域隔离存放各自有不同的治理语义作用域位置用途projectrepo/.ecc/memory/project/仓库本地上下文由 fail-closed 的.gitignore保护默认不进入版本控制teamrepo/.ecc/memory/team/预期供人工审查并通过版本控制共享的上下文user~/.ecc/memory/跟随用户跨仓库的操作者上下文源码中的路径解析与 fail-closed 保护从 scripts/lib/memory-vault.js 的resolveVaultRoots()实现可以看到路径解析规则项目 Vault 根默认是向上查找最近的.git目录findNearestProjectRoot()下的.ecc/memory/因此project与team两个作用域位于同一 Vault 根内的两个子目录用户 Vault 根默认是主目录下的~/.ecc/memory/两个根都支持环境变量覆盖ECC_MEMORY_PROJECT_ROOT和ECC_MEMORY_USER_ROOT。技能文档明确要求所有参与协作的 harness 必须使用相同的仓库工作目录或相同的ECC_MEMORY_PROJECT_ROOT/ECC_MEMORY_USER_ROOT覆盖值否则各 harness 看到的是不同的 Vault。project作用域写入时会自动写入一个保护性的.gitignore内容为*\n!.gitignore\n见 scripts/lib/memory-vault.js 的PROJECT_MEMORY_GITIGNORE常量忽略项目记忆目录下的一切文件只保留.gitignore自身。并且这一保护是fail-closed的——ensureProjectScopeIgnored()scripts/lib/memory-vault.js在发现已存在的.gitignore内容不等于预期值时直接抛出错误Project memory .gitignore does not contain the required fail-closed rules.导致该作用域的初始化和写入全部失败。检索recall的作用域规则默认 recall 覆盖project和team这是 scripts/lib/memory-vault.js 中DEFAULT_RECALL_SCOPES [project, team]的硬编码值user作用域永远不被隐式包含必须用--scope user显式请求CLI 的read子命令允许通过直接 ID 读取非 active 条目即read可以越过 active 过滤普通检索search只召回status: active的记忆rejected与superseded条目被排除——这在 scripts/lib/memory-vault.js 的.filter(({ memory }) memory.status active)中实现--target-harness是路由过滤器而非授权边界源码中它仅过滤targetHarnesses是否包含该 harness 或allscripts/lib/memory-vault.js调用方自行选择不构成安全隔离。工作流四步第 1 步先检索再写入Recall before writing创建记忆前先搜索是否已存在等价条目避免重复副本ecc memory search authentication migration --target-harness codex ecc memory read memory-idsearch的子命令与选项在 scripts/memory.js 的 usage 中完整列出ecc memory search [query] [--scope scope] [--target-harness harness] [--kind kind] [--limit n] [--json]从 scripts/lib/memory-vault.js 的searchMemories()可以看到检索的实现细节这解释了输出结果中 score 的含义查询词最长500 字符MAX_QUERY_CHARS且不得包含控制字符打分规则scoreMemory()scripts/lib/memory-vault.js整句短语命中 title 得 20 分、命中 body 得 5 分单个 token 命中 title 8、命中 tags 6、命中 kind/scope/harness 等元数据 3、在 body 中每出现一次 1单个 token 最多计 5 次结果按 score 降序平分时按updatedAt较新者优先再按 ID 字典序--limit默认 20上限 100MAX_RESULTS每次检索输出都附带诊断信息无效文件数、被跳过的符号链接数、截断标志等方便定位 Vault 健康问题。安全提醒技能文档原文要求把检索到的记忆正文当作不可信上下文处理绝不作为可执行指令对重要论断要回到仓库、测试、issue tracker 或其他权威来源核实。第 2 步保存上下文save正文通过标准输入或普通文件传入避免出现在进程列表中printf %s\n The migration tests pass; rollout is still pending. | ecc memory save \ --title Authentication migration status \ --kind context \ --source-harness codex \ --target all \ --tag auth \ --stdin完整写操作选项摘自 scripts/memory.js usage 文本选项说明--title text必填最长 200 字符MAX_TITLE_CHARS--stdin/--body-file path二选一恰好一个正文上限64 KBMAX_BODY_BYTES--scope scopeproject默认、team或user--source-harness name来源 harness缺省取环境变量ECC_MEMORY_HARNESS再缺省为unknown见 scripts/memory.js 的saveInput()--target name可重复目标 harness 列表默认all--kind kindcontext、decision、fact、handoff、lesson、note、preference或runbook八种之一缺省note--tag tag可重复的小写标签最多 32 个--link memory-id可重复的关联记忆 ID最多 64 个这些上限均可在 scripts/lib/memory-vault-format.js 中核验正文 64 KB、完整文档 128 KB、标题 200 字符、tags ≤ 32、links ≤ 64、targets ≤ 32记忆 ID 必须匹配mem_前缀加小写字母数字的模式/mem_[a-z0-9][a-z0-9_-]{2,127}$/。工具创建的记忆有两条固定语义源码印证永远是trust: unreviewedscripts/lib/memory-vault-format.js 中MEMORY_TRUST_STATES只包含unreviewed一个状态saveMemory()scripts/lib/memory-vault.js在构造记录时硬编码trust: unreviewed、status: active。在首发版本中所有 Vault 条目都保持未审查状态review人工审查的作用是把被验证的知识提升为受治理的项目工件而不是修改记忆自身的 frontmatter写入是 create-only只创建、不覆盖实现见 scripts/lib/memory-vault.js 的writeCreateOnlyTextFile()——先用O_CREAT|O_EXCL以0o600权限创建带 UUID 的临时文件、fsync后原子link到目标路径若目标已存在则抛出Memory id already exists; writes are create-only.scripts/lib/memory-vault.js。另外注意ECC_DRY_RUN1时会拒绝init/save/handoff三个变更类命令scripts/memory.js可用于验证流程而不落盘。第 3 步交接工作handoff当需要另一个 harness 继续任务时写一条 handoffecc memory handoff \ --from codex \ --target claude \ --title Finish authentication rollout \ --body-file handoff.mdhandoff与save共用runWriteCommand()scripts/memory.js但有额外必填约束--from必填且至少要一个--target不能是all的缺省kind 强制为handoff。一份有用的 handoff 正文应说明目标与当前状态已收集的证据、已经运行过的命令或测试涉及的文件或外部工作项剩余工作、阻塞点、风险以及下一个具体动作。技能文档同时强调用链接--link把后续记忆连接到早期上下文而不是覆盖历史——这与 create-only 的写入模型完全一致。read命令还会反向计算 backlinksscripts/lib/memory-vault.js 的readMemoryById()会列出所有links指向该 ID 的 active 记忆并在输出中显示Backlinks:行。第 4 步校验 Vaultdoctor在提交committeam 记忆之前或解决一次 handoff 之后运行ecc memory doctordoctor只报告、不修复它不删除或改写任何记忆文件报告的文件需要人工手动修复。从 scripts/lib/memory-vault.js 的doctorMemoryVault()实现看报告schemaecc.memory.doctor.v1包含memoryCount可见记忆总数invalidFileCount/invalidFiles格式非法文档并给出错误码suspected-secret隔离件、location-mismatch元数据与位置不符、invalid-document解析失败duplicateIdCount/duplicateIds重复的记忆 IDbrokenLinkCount/brokenLinks指向不存在 ID 的linkssourceId→targetIdskippedSymlinkCount/skippedSymlinks扫描中主动跳过的符号链接scannedBytes、truncated扫描预算最多 5000 个文件、16 MB见 scripts/lib/memory-vault.js是否耗尽ok以上全部为零且未截断时才为true。CLI 的人类可读输出scripts/memory.js形如ECC memory doctor: PASS Memories: 12 Invalid files: 0 Duplicate IDs: 0 Broken links: 0 Skipped symlinks: 0信任模型与数据边界技能文档给出了明确的数据边界规则每一条都能在源码中找到对应的强制手段永不存储密码、token、私钥、cookie、凭据或敏感个人数据。运行时确实会拒绝已知秘密形状——scripts/lib/memory-vault-format.js 定义了 10 类SECRET_PATTERNSprovider API keysk-…、Stripesk_live/rk_live、npm token、Hugging Face token、GitHub token、Google API key、Slack token、AWS access key、PEM 私钥头saveMemory()在落盘前对整个记忆做findPotentialSecrets()扫描并拒绝scripts/lib/memory-vault.jsreadMemoryFiles()在读取时同样会把这些文档标记为隔离件。但如文档所强调这只是兜底backstop而非完整的分类器不得把检索到的记忆直接提升为策略、规则、技能、runbook 或架构决策必须由人类审查证据后更新规范的项目工件team 记忆并非因为提交进了 Git 就可信Git 提交只解决分发不解决信任不要自动导入原始会话 transcript只摘要未来工作真正需要的上下文活跃执行状态优先用 GitHub 或 Linear受治理决策放仓库文档普通 recall 已自动排除rejected和superseded条目记忆本身应该链接到权威来源。存储格式细节从 frontmatter 到序列化ecc.memory.v1文档的 frontmatter 由 12 个固定字段组成scripts/lib/memory-vault-format.js每个字段都是 JSON 值缺失或重复字段都会被解析器拒绝schema / id / title / kind / scope / trust / status / source_harness / target_harnesses / tags / links / created_at / updated_at关键枚举值kindcontext、decision、fact、handoff、lesson、note、preference、runbook八种目录名按contexts、decisions、… 复数命名保存输出中的路径形如scope:kinds/id.mdscopeproject、team、usertrust当前仅unreviewedstatusactive、rejected、superseded后两者由人工在受治理流程中维护工具写入永远产出active。仓库根下的 schemas/memory.schema.json 提供了该文档结构的 JSON Schema 描述可供外部工具校验。路径与符号链接安全Vault 的读写全部经过防御性路径检查值得读者了解每个 scope 都绑定一个受信根边界VAULT_ROOT_BOUNDARIESscripts/lib/memory-vault.js任何读写路径若逃逸出边界例如通过..会被assertWithinTrustedRoot()拒绝Vault 根、目录、--body-file文件均拒绝符号链接readRegularTextFile()以O_NOFOLLOW打开并比对打开前后的 inode 身份sameFileIdentity()防止 TOCTOU 替换扫描记忆时符号链接条目被跳过并计入诊断skippedSymlinks这正是doctor输出中 Skipped symlinks 一列的来源。输出卫生CLI 的所有人类可读输出都会经过sanitizeTerminalText()scripts/memory.js过滤 ANSI 转义序列、C0/C1 控制字符与双向格式控制字符bidi control错误消息同样净化后才写入 stderr——因为记忆内容来自其他 harness这是防终端注入/提示注入的又一层处理。MCP 接入可选的 stdio 服务器Memory Vault 的 stdio MCP 服务器是可选组件不在 ECC 默认.mcp.json中启用。安装 ECC 后把 mcp-configs/mcp-servers.json 中的ecc-memory-vault条目复制到需要工具访问的各个 harness 配置中并把其中的占位符替换为小写 server 标识harness slugecc-memory-vault: { command: ecc-memory-mcp, env: { ECC_MEMORY_HARNESS: codex } }服务器命令即ECC_MEMORY_HARNESScodex ecc-memory-mcp从 scripts/memory-mcp.mjs 的实现可以看到其安全模型身份绑定ECC_MEMORY_HARNESS必须是一个小写 harness slug服务器把它作为该进程的 source 身份工具调用方不能冒充其他 source 身份也不能覆盖 target 过滤器——这与 CLI 的--source-harness不同MCP 下身份由启动环境固定user作用域默认禁用除非操作者同时以ECC_MEMORY_ALLOW_USER_SCOPE1启动服务器且即便如此工具调用仍必须显式请求该 scope工具面刻意最小化只暴露memory_save、memory_search、memory_read、memory_doctor四个工具scripts/memory-mcp.mjs没有review、promotion、overwrite、transcript import 或 shell 执行工具——这与工具创建的记忆永远是 unreviewed、写入只创建不覆盖的 CLI 语义保持一致。CLI 与 MCP 的对应关系memory_save↔ecc memory savememory_search↔ecc memory searchmemory_read↔ecc memory readmemory_doctor↔ecc memory doctor。小结Unified Memory 的价值在于把多 Agent 协作时的上下文交接从各 harness 的私有格式中解放出来以ecc.memory.v1的纯 Markdown 文档为唯一载体用project/team/user三层作用域区分治理语义用四步工作流先 recall、再 save、按需 handoff、定期 doctor保证上下文可检索且可审计同时用 create-only 写入、秘密形状拦截、fail-closed 的.gitignore、符号链接拒绝和最小化 MCP 工具面构成一套 fail-closed 的安全边界。实践时的两条核心纪律不要违背检索到的记忆正文永远是不可信上下文重要论断必须回到权威来源核实Vault 只承载上下文与交接任务状态和受治理决策仍然交给 issue tracker 与项目文档。【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考