11 KiB
name, description
| name | description |
|---|---|
| dev-changelog | 三层开发进程记录系统(fragment 源 + 自动生成视图)。Agent 完成代码改动后, 写入一条独立的 fragment 文件并重建视图,提供从一句话概要到完整日志的多级上下文, 帮助 Agent 跨会话保持对项目进展的感知,并支持多人协作下的低冲突合并与作者区分。 当用户提到"开发日志"、"changelog"、"最近改了什么"、"回顾改动"等时触发。 |
Dev Changelog
跨会话开发进程记录系统。数据源是一条一文件的 fragment,三层视图由脚本自动生成。 这套设计同时解决了三个老问题:体量失控、三层手动同步漂移、以及多人协作时 git merge 冲突。
架构总览
.cursor/changelog/
├─ entries/<author>/<id>.md ← 唯一数据源(一条改动 = 一个文件,提交进 git)
├─ changelog-full.md ← 视图(L1 完整,全部条目) \
├─ changelog-recent.md ← 视图(L2 摘要,最近 ~20 条) | 全部由
├─ changelog-headlines.md ← 视图(L3 一句话,最近 ~50 条) | 生成器产出
├─ changelog-by-author.md ← 视图(按作者聚合) /
└─ tools/
├─ changelog_build.py ← 生成器:entries/ → 4 个视图(确定性、stdlib-only)
├─ migrate_changelog.py ← 一次性迁移脚本(已执行,留作参考)
├─ install-git-hooks.ps1/.sh ← 安装 pre-commit / post-merge git hook
└─ git-hooks/{pre-commit,post-merge}
| 层级 | 视图文件 | 信息密度 | 窗口 | 注入方式 |
|---|---|---|---|---|
| L1 完整版 | changelog-full.md |
高(完整正文) | 全部 | 用户手动唤醒 |
| L2 中期版 | changelog-recent.md |
中(3-5 行摘要) | ~20 条 | 检测到关联时自动读取 |
| L3 概要版 | changelog-headlines.md |
低(1 行) | ~50 条 | 每次会话自动注入 |
| 作者视图 | changelog-by-author.md |
索引 | 全部 | 按需 |
重要:视图文件顶部都标了"由 changelog_build.py 自动生成,请勿手改"。 一切修改都改 fragment,再跑生成器。视图改了不算数(下次生成会被覆盖)。
锚点 ID 机制
格式 CL-YYYYMMDD-HHMM-<author>(如 CL-20260715-1521-alice)。同一分钟多条时在 HHMM
后追加字母(CL-...-1521a-sq)。历史迁移条目无作者后缀(author: legacy),保持原 ID 不变
以维持 pitfalls / deferred / source_chat 等处的交叉引用有效。
锚点 ID 在 fragment 与三层视图中一致,用于逐级 Grep 精准定位(L3 → L2 → L1)。
作者标识(多人协作核心)
每条 fragment 记录作者,体现在三处:① 目录 entries/<author>/、② 文件名 / ID 后缀、
③ frontmatter author 字段。视图层 L3 行前缀 @<author>、L2/L1 有 author 字段、
另有按作者聚合的 changelog-by-author.md。
作者 handle 的确定顺序(写入时):
- 读
.cursor/local-env.json的changelog-author字段(设备绑定、gitignored,每位开发者各自配一次,最稳) - 缺失则取
git config user.name,转小写、取首个英文单词或姓名缩写作为 handle - 仍无法确定则用
unknown
建议每位协作者在本机
.cursor/local-env.json里加"changelog-author": "<你的handle>", 保证 handle 稳定(不随 git user.name 大小写/格式变化而漂移)。
fragment 文件格式
---
id: CL-20260715-1521-alice
date: 2026-07-15 15:21
author: alice
author_name: Alice
type: fix
merge_source: HEAD
status: active
superseded_by:
title: 一句话标题(用于视图的 H3 标题)
source_chat: [对话简述](chat-uuid)
tags:
- tag1
- tag2
affected_files:
- scripts/player/player_controller.gd
- scenes/player/player.tscn
---
<!-- L3 -->
一句话描述改动内容(≤80 字,进 headlines)
<!-- L2 -->
做了什么 + 为什么(3-5 行摘要,进 recent;当本条进入最近 20 时被展示)
<!-- L1 -->
- **what**: ...
- **why**: ...
- **decisions**: ...
- **notes**: ...
(symptom / root-cause / fix / tests / followups / relation 等按需,正文原样进 full)
字段说明:
type:feat/fix/refactor/docs/chore/infra(机读,便于统计)merge_source:本条记录时所在分支(HEAD/master/ 分支名),留空则视图不显示status:active(默认)/reverted/superseded;后两者配superseded_by: CL-xxxaffected_files:必须全路径(视图 L2 的硬匹配靠它,缩写路径会失效)tags/affected_files为块列表;其余为标量。frontmatter 之外的三段用<!-- L1/L2/L3 -->分隔
操作 A:记录写入(核心流程)
触发条件
Agent 完成涉及代码或配置文件实质性改动的任务后自动触发。
不触发:纯对话/方案/答疑(无文件改动)、只读操作、只改 .cursor/ 下基础设施文件
(画像、延期、changelog 自身、hooks、tools 等)。
写入流程
1. 确定作者 handle(见上「作者标识」三步顺序)
2. 生成锚点 ID:CL-YYYYMMDD-HHMM-<author>
- 检查 entries/ 下是否已存在同 ID(含其他作者目录),冲突则 HHMM 后加字母后缀
3. 从刚完成的任务提取:what / why / where(affected_files, 全路径) / decisions / notes,
并判定 type、merge_source(当前分支)、tags
4. 用 Write 工具创建单个 fragment 文件:
.cursor/changelog/entries/<author>/<id>.md
- 按上面的格式填好 frontmatter + L3/L2/L1 三段
- L3 ≤80 字一句话;L2 3-5 行;L1 完整正文
5. 跑生成器重建视图:
python .cursor/changelog/tools/changelog_build.py
(Windows 控制台先 set PYTHONIOENCODING=utf-8)
6. 在回复末尾附 "[已记录到开发日志]"
与旧流程的关键区别
- 不再用 StrReplace 往三个文件顶部插入——只新建一个 fragment 文件,零冲突、零半损坏风险 (旧的 StrReplace 顶部插入曾导致条目半损坏,fragment 模型下该风险彻底消失)。
- 不再手动维护滚动窗口——recent/headlines 的 ~20/~50 截断由生成器自动算。
- 不再手动保持三层同步——三层都是同一 fragment 的不同密度渲染,天然一致。
静默写入原则
- 不需要用户确认(Agent 对自己的改动是一手认知)。
- 回滚也要记录(新建一条
type: chore/ 在被回滚条目里置status: reverted+superseded_by)。
操作 B:L2 自动触发读取
由 changelog-recall.mdc 调度,读取 changelog-recent.md:
- 硬匹配:当前任务涉及的文件出现在条目
affected_files(现为全路径) - 软匹配:当前任务语义关键词与条目
tags有交集 任一命中即纳入上下文。读取的是视图,无需读 fragment。
操作 C:L1 手动检索
用户要求回顾完整记录时,读取 changelog-full.md 并按时间 / 模块 / tags 过滤展示。
逐级上溯机制
L3 信息不足时(语义模糊),按 ID 逐级 Grep:
1. 从 L3 提取锚点 ID
2. Grep changelog-recent.md(L2)→ 命中读该条
3. 仍不足 → Grep changelog-full.md(L1)拿行号,Read 该行 ±20 行
(也可直接 Read 对应 fragment:entries/*/<id>.md)
原则:按需触发、精准读取、一次 1-3 条、不全文读 L1。
操作 D:记录管理
- 修改:编辑对应
entries/*/<id>.md后跑生成器(不要直接改视图)。 - 删除:删除对应 fragment 文件后跑生成器。
- 标记取代/回滚:在 fragment 里置
status: superseded/reverted+superseded_by。
滚动窗口(自动)
生成器按 ID 时间倒序排序后:headlines 取前 50、recent 取前 20、full 全量、by-author 全量。 无需任何手动修剪,被移出窗口的条目仍完整保留在 fragment 与 full 视图中。
git 协作与冲突
- fragment 几乎不冲突:不同人写不同文件、不同作者写不同子目录。
- 视图冲突自动吸收:
.gitattributes给 4 个视图设merge=union(merge 不中断), pre-commit / post-merge git hook 跑生成器从 fragment 确定性重建视图,所有人收敛到一致。 - 新克隆需跑一次
tools/install-git-hooks.ps1(或.sh)装 hook。 - CI 可加
changelog_build.py --check校验"视图 == 重建(fragment)"防止有人没装 hook 就提交。 - 合并尚未 fragment 化的旧分支(如重构前的 master):先
git merge --no-commit --no-ff <分支>(union 让视图不冲突、--no-commit防止 hook 过早重建),再跑tools/merge-import.ps1 [-Ref <分支>](或.sh)把对方旧格式条目收割成 fragment(只补缺失 ID、不覆盖已有),自动重建并校验无丢失,最后git add -A; git commit。 - 两条改动撞了同一个 fragment ID(生成器遇重复 ID 会直接报错):给其中一条改 ID(
HHMM后加字母,如1521→1521a), 文件名与 frontmatterid同步改,再跑生成器。两条都保留、不丢内容。
与其他系统协作
| 系统 | 关系 |
|---|---|
changelog-recall Rule |
下游消费者:注入 L3、按需读 L2、上溯 L1 |
deferred-decisions |
互补:记"没做什么" |
profile-memory |
结构对称:记"是什么" |
epee-orchestrator |
在 registry.md 注册本 Skill |
自迭代日志
已知必要检查
-
大任务收尾不要遗漏写入 — 单次 5+ 文件改动时,先按
changelog-recall.mdc的 "任务完成 Checklist" 写完 fragment + 跑生成器,再输出回复;绝不"先回复再补写"。 -
affected_files 必须全路径 — 视图 L2 的硬匹配依赖全路径;缩写路径(如只写文件名) 会让 recall 的硬匹配失效。迁移前的旧 L2 缩写路径问题已由本次重构(从 frontmatter 全路径渲染)解决。
-
写完务必跑生成器 — 只建 fragment 不跑
changelog_build.py,视图就不会更新(recall 读的是视图)。 pre-commit hook 会兜底重建,但当前会话内的 recall 注入读的是已落盘视图,故应即时生成。 -
作者 handle 要稳定 — 优先用
.cursor/local-env.json的changelog-author,避免每次从git config user.name推导导致 handle 漂移(同一人出现多个目录)。 -
Windows 控制台编码 — 跑脚本前
set PYTHONIOENCODING=utf-8(或 PowerShell$env:PYTHONIOENCODING="utf-8"), 否则中文输出在 GBK 控制台显示乱码(不影响 UTF-8 文件写入,仅影响 stdout 观感)。