deepseek-harness 的 Agent Note 归档机制:冻结双语三元组与追加式哈希封印
deepseek-harness 用一套名为 Agent Note 的决策记录体系来保存"代码和文档承载不了的 why"。当一份已实现的记录失去未来指引价值后,它会被整体移入 .agents/notes/archived/ 归档树并永久冻结:本仓库通过 归档树规则文件、内容封印清单 与 校验脚本 三层机制,保证归档历史不可被悄悄篡改。读完本文,你将掌握这套归档体系的目录契约、六行冻结头部格式、追加式 manifest 的校验原理,以及标准的归档操作全流程。
归档树定位:冻结的历史快照,而非现行权威
.agents/notes/archived/AGENTS.md 是归档树的治理规则,全文仅数行但约束极其严格。其核心立场可以概括为三条:
- 冻结即权威失效:kind 目录下的归档 Agent Note 三元组是"冻结的历史快照,不是现行权威"。任何情况下都不得编辑、重排、翻译、修复、删除或移动已封印的产物;新的判断必须依据活动 Agent Note 或当前文档。
- 归档变更的允许面是封闭的:一次合法的归档变更只做四件事——整体搬迁完整的英文/中文/sidecar 三元组、在两处
Status: implemented行下方插入相同的Archived: YYYY-MM-DD行、重新记录 sidecar 一致性哈希、修复或删除指向它的入站链接。除此之外的一切内容变更都是违规。 - 出站链接永不检查:明确禁止检查、验证或修复"从归档 note 出发"的链接——这是后面校验脚本中一个刻意保留的设计空隙。
这条规则与活动生命周期树形成对照:在 .agents/notes/README.md 定义的体系中,活动 note 位于 proposed/、implemented/、rejected/ 三种生命周期下,随状态在目录间迁移;只有 implemented 的记录才"有资格"进入归档树,且归档路径被编码为 archived/{class}/yyyy-mm-dd-topic-title.md——路径中刻意省略 implemented,因为"只有已实现的 note 才能进入归档"。
目录结构:封闭的 kind 集合与三元组命名
归档树的结构校验由 scripts/verify-archived-agent-notes.ts 执行,其目录契约是:
- 归档根目录下只允许两个根文件:
AGENTS.md与manifest.json(见 verify 脚本 中的allowedRootFiles);出现任何第三个根文件直接报错。 - 根目录下只允许六个 kind 目录,且六个一个都不能缺,缺任何一类都报
required kind directory is missing(verify 脚本)。 - kind 集合是封闭的,定义在 scripts/agent-note-tree.ts 的
AGENT_NOTE_CLASSES中:feature、bug-fix、simplification、architecture、process、testing。未知目录会被判定为unknown Agent Note kind。 - kind 目录内只允许普通文件(不允许子目录),文件名必须匹配正则
{kind}/yyyy-mm-dd-topic.{md,zh.md,i18n.yaml}——该正则在 scripts/archived-agent-notes.ts 的validateArchiveArtifacts中实现。
因此每一份归档记录天然是一个三文件一组的完整单元:英文 foo.md、中文 foo.zh.md、双语一致性 sidecar foo.i18n.yaml。以现存归档为例:2026-06-11-custom-schema-dsl.md、2026-06-11-custom-schema-dsl.zh.md 与 2026-06-11-custom-schema-dsl.i18n.yaml 组成 architecture 类下的一个完整三元组。validateArchiveArtifacts 会对每一份三元组做完整性检查,缺任一文件即报 incomplete archived triplet 并列出缺失项(scripts/archived-agent-notes.ts)。
冻结的六行头部:每份归档 note 的强制格式
归档 note 的头部六行是逐行校验的封闭格式。scripts/archived-agent-notes.ts 的 validateHeader 对英文版与中文版分别施加同一套规则(仅第 6 行语言切换器不同):
| 行号 | 强制内容 | 校验逻辑 |
|---|---|---|
| 1 | # Agent Note: <标题> |
必须以 # Agent Note: 开头且标题非空 |
| 2 | 空行 | 非空即报错 |
| 3 | Status: implemented |
归档 note 必须保留原始实现状态 |
| 4 | Archived: YYYY-MM-DD |
必须是真实历法日期(闰年感知),且不得早于文件名中的日期 |
| 5 | 空行 | 非空即报错 |
| 6 | 语言切换器 | 英文版固定为 English | 中文;中文版固定为 English | 中文 |
其中两个细节值得展开:
- 日期合法性不是简单的正则匹配。validDate 用
Date.UTC构造日期再取回年/月/日比对,因此2026-02-30这类"看起来合法"的日期会被拒绝。 - 归档日期必须晚于等于 note 首次提出日期:文件名本身编码了首次提出日期(
yyyy-mm-dd-topic.md),校验会拒绝Archived日期早于该日期的三元组(scripts/archived-agent-notes.ts),从机制上杜绝"时间线倒挂"的伪造归档。 - 英文与中文两侧的
Archived:日期必须完全一致,否则报English and Chinese archive dates differ(scripts/archived-agent-notes.ts)。
一个真实样例(2026-06-11-custom-schema-dsl.md 的头部):
# Agent Note: Custom typed tool-schema DSL instead of schemastery
Status: implemented
Archived: 2026-07-26
English | [中文](https://gitcode.com/gh_mirrors/de/deepseek-harness/blob/cd5ef8148158c3a752a658978873241fdf8e2bbc/.agents/notes/archived/architecture/2026-06-11-custom-schema-dsl.zh.md?utm_source=gitcode_repo_files)
Sidecar 一致性记录:双语双方的 Git Blob 哈希
三元组中的 .i18n.yaml 文件不是普通的 i18n 配置,而是一份双语一致性记录。以 2026-06-11-custom-schema-dsl.i18n.yaml 为例,注释行之后恰好是两行映射:
2026-06-11-custom-schema-dsl.md: e09fea6c4bb80e287b1b64471eee4c87f24fba4a
2026-06-11-custom-schema-dsl.zh.md: 2bacbde02838ef61b05f38796bbeeea262fc2d23
这里的值不是普通的 sha256,而是Git blob 对象 ID:gitBlobHash 按 Git 对象格式计算——对 blob <字节长度>\0<内容> 求 SHA-1。这样 sidecar 中的哈希与 Git 历史中的 blob 直接对应,归档产物在仓库对象数据库里可追溯。
校验时 pairMeta 要求 sidecar 去掉注释后恰好包含两行 <文件名>: <40位十六进制> 记录,且两个值必须与当前两份语言文件的 blob 哈希逐一相等(scripts/archived-agent-notes.ts)。这解释了为什么归档规则把"重新记录 sidecar"列为唯一允许的内容变更之一:插入 Archived: 行会改变两份语言文件的字节内容,从而改变 blob 哈希,sidecar 必须随之机械地重录。
manifest.json:追加式的内容封印
.agents/notes/archived/manifest.json 是覆盖全部归档产物的内容清单,目前为 512 行、记录了六个 kind 目录下所有三元组的哈希。它的格式是一个封闭 schema:
{
"version": 1,
"files": { "architecture/2026-06-11-custom-schema-dsl.md": "sha256:f05d…" }
}
parseArchiveManifest 的解析规则体现了封闭性:顶层字段排序后必须恰好是 files,version 两个,多一个少一个都抛错;version 必须等于 1;每个哈希必须是 sha256: 前缀加 64 位小写十六进制。这里的哈希由 archiveContentHash 计算,直接对文件字节求 SHA-256——注释明确说明它"独立于仓库的 Git 对象格式",即封印绑定的是内容本身而非 Git 对象。
追加式(append-only)语义分两层实现:
- 基线比对:validateArchiveManifestExtension 以某个 Git 提交中的旧 manifest 为基线,逐一检查其中每个已封印条目:在当前 manifest 中消失报
sealed manifest entry is missing,哈希变化报sealed manifest hash changed。已封印的历史条目既不能删也不能改。 - 全量重验 + 只增不删:extendArchiveManifest 对现有 manifest 中每个路径重新读取磁盘内容并重算哈希(不一致即
sealed content hash changed),然后仅为磁盘上尚未封印的新产物追加哈希,并返回追加清单。
基线从哪来?verify 脚本 用三条 Git 命令读出基线 manifest:git cat-file -e <ref>^{commit} 确认引用存在、git ls-tree 检查该提交中 manifest 路径是否存在、git show <ref>:<path> 读取内容。基线引用取自环境变量 DSH_ARCHIVE_BASE_REF,缺省为 HEAD——脚本注释写明了分工:CI 提供可信的变更前提交,本地写入则与已提交的 HEAD 比对(verify 脚本)。这意味着即使有人在工作区里同时篡改了磁盘文件与 manifest,只要 CI 以真实基线比对,篡改仍会被检出。
verify 命令:从校验到封印
归档体系的执行入口是 package.json 中的 npm script:
pnpm run verify-archived-agent-notes # 常规校验模式
pnpm run verify-archived-agent-notes --write # 追加封印模式
verify 脚本 的执行序列是:
- 检查归档根目录,只放行
AGENTS.md与manifest.json两个根文件,其余根文件直接报unexpected root file; - 校验六个 kind 目录齐全、kind 目录内只有普通文件,并把全部产物读入内存(verify 脚本);
- 调用
validateArchiveArtifacts做三元组完整性、六行头部、双语日期一致性、sidecar blob 哈希四项检查; - 读取基线 manifest 并做追加式比对;
- 调用
extendArchiveManifest重验全部封印并收集新产物。
两种模式的差异只有一处:非 --write 模式下,任何磁盘上存在但尚未封印的新产物都会报 archived artifact is not sealed in manifest.json(verify 脚本);--write 模式则允许把这些新哈希追加写回 manifest,且只追加、不改动任何既有条目。这正是规则文件所说的"正常校验器拒绝被改动或缺失的封印产物、不完整三元组、未知 kind 目录和非法归档元数据"的完整含义。纯函数部分(manifest 解析、渲染、扩展、产物校验)全部收敛在 scripts/archived-agent-notes.ts 中,由 scripts/archived-agent-notes.spec.ts 提供聚焦测试。
标准归档操作全流程
操作层面的完整流程由 dsh-archive-agent-notes 技能 定义,其归档一份已实现三元组的五步是:
- 整体搬迁:把
foo.md、foo.zh.md、foo.i18n.yaml三件套从implemented/<kind>/移到archived/<kind>/;implemented不出现在归档路径中。 - 仅插入元数据行:在两份语言文件的
Status: implemented正下方各插入一行Archived: YYYY-MM-DD,使用归档日期且两侧同值;正文一字不改。 - 机械重录 sidecar:仅为这次两处元数据编辑重新记录双语 blob 哈希(sidecar 注释给出的命令是
pnpm run verify-translation-pairing --write)。 - 处理入站链接:在活动文档中搜索指向该 note 的链接,要么改指当前权威、要么仅在刻意引用历史快照时改指归档路径、要么直接删除;绝不去修复归档 note 内部的出站链接。
- 封印并复核:运行
pnpm run verify-archived-agent-notes --write(追加模式先证明既有封印全部匹配,再只追加新三元组的哈希),随后再跑一次常规pnpm run verify-archived-agent-notes。
技能文档同时强调归档决策应基于语义判断而非字数、年龄或配额:已实现 note 中,其备选方案、所有权边界、负面保证、持久化/协议语义、安全规则或"重新引入条件"仍可能指引未来变更的,保留活动;一次性 UI 细节、窄适配器、已闭环的小 bug 才归档;proposed note 永不归档(废弃即 reject);rejected note 只有在其仍然防止一个"诱人且有意义"的错误时才保留。
设计要点小结
从源码结构看,这套机制把"历史不可篡改"落实成了四个相互咬合的工程约束:
- 内容封印而非对象封印:manifest 绑定文件字节的 SHA-256,独立于 Git 对象格式,改名、改换 blob 都无法绕过;
- 追加式 + 外部基线:
--write只增不改,且 CI 以变更前提交为基线比对,堵死"文件与 manifest 一起改"的作弊路径(verify 脚本); - 格式即约束:六行头部、封闭 kind 集合、三元组完整性全部是逐行/逐字校验,任何"顺手修一下"都会让校验器失败;
- 刻意的非功能:归档 note 的出站链接永不验证——历史快照的价值恰恰在于它保留的是当时的事实与链接状态,修复它反而破坏快照语义。
关键路径索引
- 归档树规则:.agents/notes/archived/AGENTS.md
- 封印清单:.agents/notes/archived/manifest.json
- 归档操作工作流:.agents/skills/dsh-archive-agent-notes/SKILL.md
- 活动 note 体系总则:.agents/notes/README.md
- 校验入口脚本:scripts/verify-archived-agent-notes.ts
- 纯函数校验实现:scripts/archived-agent-notes.ts
- 目录树与 kind 封闭集:scripts/agent-note-tree.ts
- 聚焦测试:scripts/archived-agent-notes.spec.ts
- 三元组实例:.agents/notes/archived/architecture/2026-06-11-custom-schema-dsl.md
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00