Releases: shiftu/keel
Release list
keel v0.7.1 · 产物不存在时重建
修复
keel sync 在产物文件整个不存在时误报冲突,导致 sync 永久失败。
.codex/ 这类产物目录常被 gitignore,而 .keel/generated.yaml 是进 git 的。于是「清单里有记录、磁盘上没文件」会在每次 clone、每个新 worktree、每次清理之后出现 —— 这是常态,不是异常。
v0.7.0 在这种情况下报:
✘ .codex/hooks.json
hooks.SessionStart 里 keel 写过的条目被改过或删掉了
但文件压根不存在,没有任何用户内容需要保护。renderHookEntries 判冲突前漏了 existed:文件不在时条目列表为空,必然对不上记录条数,于是必然报冲突。另外两个渲染模式一直是对的(ModeWholeFile 用 existed && hasRec,renderJSONObjectKeys 有 if !ok { continue }),只有 hook 条目把「不存在」塌进了「被篡改」。
现在:文件不存在 → 重建;文件存在但 keel 的条目被改过或被摘掉 → 仍然报冲突,行为不变。
新增 sync-rebuilds-missing-artifact.txtar 锁住这条路径。
升级
keel update
被这个问题卡住的仓库升级后直接 keel sync 即可,不需要任何手工清理。
keel v0.7.0: 优雅退出(keel deinit)
新增
-
keel deinit [--purge] [--dry-run]:init的逆操作,从仓库里优雅退出。
只带走 keel 自己写过的东西——所有权唯一来源是generated.yaml的 digest/owned_json
和 git hook 里的# keel:begin标记,不猜、不按文件名或路径推测。顺序是
init的严格倒序,先撤依赖.keel/的部分,最后才碰.keel/:- 工具侧产物:技能副本、
.claude/rules/keel.md这类整文件删掉;CLAUDE.md/
AGENTS.md/.codex/config.toml只去掉标记块;.claude/settings.json/
.codex/hooks.json/.mcp.json只撤 keel 写过的那几条。块外内容、你自己的
hook 条目、别的字段一律原样保留,去掉 keel 的部分后什么都不剩才删文件。 - git hook:含 keel 标记的才动。
--adopt-hooks串联过的把原脚本从
.keel-local换回去;不含标记的是别人的,一个字节不碰。 .keel/cache/清掉。.keel/默认保留——决策、规则、记忆、证据是项目的记录,不是工具的产物。
托管内容被人手改过就报冲突、一个文件都不写,退出码 1,和
sync同一条规则。
--purge才连.keel/一起删,且要求它在 git 里是干净的,没有跳过开关。退出后
keel init能原地接回来:keel.yaml没动过,tools和mcp都还在。 - 工具侧产物:技能副本、
升级
keel update或者重新跑一次安装脚本:
curl -fsSL https://raw.githubusercontent.com/shiftu/keel/main/install.sh | bash校验
sha256sum -c SHA256SUMS --ignore-missingkeel v0.6.0
新增
-
keel completion:bash / zsh / fish / powershell 四家 shell 补全。
--install自动探测当前 shell 并装到位(脚本落到该在的位置,rc 文件里加一段带标记、
可安全重装的加载语句)。候选一律现问二进制要——命令、选项、以及仓库里规则和记忆的 ID
都跟着当前这个.keel/走,不会随升级或仓库变化而过期撒谎。 -
keel update:从 GitHub Releases 换成最新版。下完先对本次发布一起传的SHA256SUMS,
对不上当场删掉、不安装;发布里没有校验和文件直接拒绝。支持--check(只问不下,可加
--json)、--version vX.Y.Z(装/降级到指定版本)、--force(版本一样也重装)。
install.sh / install.ps1 装完会顺手跑一次 keel completion --install,认不出当前
shell 就跳过,不影响安装本身。
升级
keel update或者重新跑一次安装脚本:
curl -fsSL https://raw.githubusercontent.com/shiftu/keel/main/install.sh | bash校验
sha256sum -c SHA256SUMS --ignore-missingkeel v0.5.0:M5 索引收敛
M5 = 索引收敛。一句话:索引是视图,淘汰是显式动作。
起因是一个具体问题:commit 到了成百上千之后,.keel/knowledge/INDEX.md 会不会跟着暴涨。
索引长度跟 commit 数无关,跟对象数有关。真正单调增长的是三类「不再声称适用」的对象——
被替代的决策、被撤回的规则、被归档的记忆。它们一条都不能删,于是现行结论会被历史淹掉。
变更
- 知识索引分两层。 主表只出现行对象;历史退到一张最多四行的计数表,跟历史有多少条无关。
knowledge.index_history: true才展开逐条清单。历史一条都没删,keel why --history查得到。 - 新增
keel archive <M-…> --reason。 记忆退场的显式入口,与keel retire对称。
原因写进正文,文件留在.keel/memory/;有derived_from指向它时提示但不代劳。 keel review新增两个候选。memory_archive_candidate(过了复查日期且从来没有过证据)
与index_pressure(现行对象超过knowledge.index_soft_limit,默认 200)。IsHistory()统一到三个状态机上,why --history与索引口径一致。
两条边界
不做自动淘汰。 状态转换只有两个入口:keel verify 真跑完一次验证器,或人显式改。
「超过 N 天没验证就自动归档」是第三个入口,它在没有任何新证据的前提下改变结论的效力。时间不是证据。
index_pressure 不做门禁。 只出现在 review 里,不进 check,更不进 pre-commit。
现行对象太多不是错误,是体检结果。做成门禁会产生「为了过门禁而删记忆」的反向激励。
顺带修的 bug
keel why 原先用 !IsActive() 判断历史,proposed 决策因此默认查不到。一个正在等人拍板的
方案比大多数已生效结论更该被看见。现在默认可见。
升级说明
这一版给 keel.yaml 加了两个字段(knowledge.index_history / knowledge.index_soft_limit)。
keel.yaml 是严格解析:仓库里写了新字段之后,旧版 keel 会直接报解析失败,协作者需要一并升级。
反过来是安全的——新版读缺字段的旧配置,由默认值兜底,不需要重新 keel init。
安装
curl -fsSL https://raw.githubusercontent.com/shiftu/keel/main/install.sh | bash🤖 Generated with Claude Code
keel v0.4.0
M4:复用与扩展
跨仓库复用一套 keel 配置。一句话:模板给的是建议,不是既成事实。
模板导入
keel init --from https://github.com/org/keel-template.git@v1导入模板仓库 .keel/ 的可复用部分,并把来源解析成一个 commit 钉进 .keel/template.yaml。
导入面:keel.yaml(tools 除外,它是本机探测结果)、skills/**、rules/*.md、cases/**。
不导入:decisions/、memory/、evidence/、intent.md。它们是源仓库的项目事实——
证据的 digest 是对着那边的代码算的,在你这边永远对不上;intent.md 是你自己项目要回答的问题。
导入的规则一律落成 candidate,模板里写 active 也一样,同时清空 evidence、verifier_digest
和 from,用 from_template 记下 <source>@<commit>。M3 定的「promote 不能自我批准」不许绕开:
装个模板不等于让别人的仓库决定你这边执行什么代码。要生效,仍得本地 keel decide 记依据、
keel promote 跑对照验证。
三方更新
keel template status # 不联网,只答「本地相对导入基线动过什么」
keel template update [--to <ref>] [--dry-run]update 拿模板新版、上次导入的基线、你现在这一版做三方比较:
| 你改过吗 | 模板改过吗 | 结果 |
|---|---|---|
| 没有 | 改了 | 快进写入 |
| 改了 | 没改 | 保留你的 |
| 改了 | 也改了 | 一个字节都不写,退出码 1 |
| 没这个文件 | 新增 | 写入 |
| 你删了 | — | 不写回 |
| — | 模板删了 | 不删你的 |
冲突不阻塞其他文件;冲突文件的基线不推进,会一直报到人处理为止。
keel.yaml 比的是配置的含义而不是字节,快进时保留本地 tools。
sync --codemap
按目录列的仓库地图,写 .keel/knowledge/CODEMAP.md。输入是 git ls-files 不是工作树遍历,
两台机器生成的逐字节一致。只列目录,没有 AST 也没有调用图。
长期开启用 knowledge.codemap: true。
未做
claude / codex 之外没有加新适配器。技能的对照评估继续后置(仍缺宿主任务集);
M4 只把技能的版本定义成模板钉住的那个 commit。
go test ./... 全绿。SHA256SUMS 随本次发布附带,可用 shasum -a 256 -c SHA256SUMS 校验。
keel v0.3.0
M3:受控进化
规则从候选到生效只有一条路:keel promote;撤回只有一条路:keel retire。
- 规则要过对照验证:
cases/下 pass 和 fail 两个方向的夹具必须都在,只证明"该过的过了"不算数——一条永远 exit 0 的检查也能满足。 - promote 前置条件缺一不可:candidate 状态(或证据已过期需重新验证)、
check.argv、指向有效决策的from,全部满足才转 active 并写证据;不满足则留在 candidate,失败证据同样写入仓库。 - definition_digest 覆盖面扩大:argv、cases、正文、argv[0] 指向的检查脚本内容一并纳入。改了其中任何一项都会报
rule_evidence_stale(warn)。 - retire:转 retired,原因写进正文,历史保留;被替代的旧规则只提示不自动改。
- 规则执行范围限定:只在人显式发起的验证(worktree/index/range)中运行,且只跑 scope 与变更集有交集的规则;Stop hook 不再执行规则,只做对象层检查。
keel review:只读命令,展示到期、失效冲突、确定性学习候选簇与统计,不执行任何规则。
技能版本与对照评估后置到 M4。
go test ./... 全绿;SHA256SUMS 随本次发布附带,可用 shasum -a 256 -c SHA256SUMS 校验。
keel v0.2.0
M2 · 可信记忆。记忆终于有了可推导的生死,任务能跨工具接上。
升级:重跑一次安装脚本即可,.keel/ 的格式向后兼容,v0.1.0 建的仓库不用改。
keel sync 会新增 .keel/knowledge/INDEX.md 并更新 CLAUDE.md / AGENTS.md 的协议块。
证据只能跑出来
keel verify <M-…|D-…> -- go test ./internal/store/...
keel verify <M-…|D-…> --rule R-…
真的 exec 一次验证器,把退出码翻译成 pass/fail/error/timeout,写成 .keel/evidence/E-<uuid>.md。
没有「登记一条我认为它通过了」的入口。 自述的通过既不能被别人重跑,也不能被撤回,
写进仓库就成了不可证伪的事实。
- 记忆:pass →
verified并写verified_at;fail →disputed。 - 决策:只追加证据,不改状态。
proven是人的判断,不是跑通一条命令的自动结果。 - 验证器跑不起来或超时:照实记进证据,但不做任何状态转换——那既不是通过也不是失败。
证据记两个摘要,回答两个不同的问题:subject_digest 盯结论本身,
target.content_digest 盯 scope 覆盖的代码。改了记忆正文,旧证据就对不上;
代码变了但结论没变,验证结果算过期。两种失效模式不同,必须分开报。
记忆生命周期由证据推导,check 不改写文件
| finding | 条件 | severity |
|---|---|---|
memory_status_unsupported |
自称 verified,但没有一条 pass 证据的 subject_digest 对得上 |
error |
memory_evidence_stale |
证据验的那份代码之后变过了 | warn |
memory_review_due |
review_after 已过 |
warn |
memory_conflict |
反例指向的结论仍是 verified | warn |
memory_status_unsupported 是 error 而不是提醒:文件自称 verified、证据却撑不住,
等于把未验证的经验当项目规则用。
状态转换的入口只有两个:keel verify 真的跑完一次,或人手工编辑文件。
check 只推导并报告——让 pre-commit 顺手改文件,改动就从 git diff 里消失了。
任务能跨工具接上
keel task set --goal "给存储层加缓存" --done "读完 internal/store" --next "写 LRU"
keel task show
同一个 worktree 上 Claude 与 Codex 之间的交接。摘要出现在 brief 和 SessionStart 最前面。
它在 .keel/cache/ 里、不进 git——这是交接,不是长期记忆;要跨 clone 留下的经验仍走 note / decide。
HEAD 往前走之后会照实说「摘要可能已经落后」,不假装还准确。
检索按任务收敛
brief 改成六档确定性排序:显式 ID > 路径 > 冲突与失败 > 有效证据 > 主题 > 兜底。
「适用条件」不参与打分,而是逐条原样展示:判断它适不适用是宿主 agent 的活,不是 keel 的。
上限为 1(有适用先例才自决)时,额外列出适用先例及其有没有跑出来的证据。
policy.Precedents.Verified 现在接的是真实证据,但它只出现在说明里,不参与上限计算——
扩大自决范围仍然只能改配置。
knowledge/INDEX.md
keel sync 生成并进 git:决策、规则、记忆各一张表,记忆那张带验证时间和证据条数。
clone 之后不装 keel 也能读。内容只来自仓库里的对象,两台机器 sync 出来一模一样。
修复
- 列表选项重复给时静默只留最后一个。
--tag a --tag b会丢掉 a,
--scope/--path/--condition/--rule-migration同样。现在既可重复也可逗号分隔,两种写法等价。
这正是 keel 在别处拒绝的静默丢弃。
还没做
M3 的 keel review 与受控进化;M4 的 init --from、--codemap。
装
curl -fsSL https://raw.githubusercontent.com/shiftu/keel/main/install.sh | bash # macOS / Linux
irm https://raw.githubusercontent.com/shiftu/keel/main/install.ps1 | iex # WindowsSHA256SUMS 一并发布,shasum -a 256 -c SHA256SUMS 可对。
keel v0.1.0
第一个可用版本:M0(协议定稿)与 M1(统一底座)。
keel 把项目目标、开发约定、任务经验和验证证据保存在 git 仓库里,为 Claude Code / Codex
提供一致、可追溯的工作上下文。无服务、无账号、无数据库,核心命令离线。
装
curl -fsSL https://raw.githubusercontent.com/shiftu/keel/main/install.sh | bash # macOS / Linux
irm https://raw.githubusercontent.com/shiftu/keel/main/install.ps1 | iex # Windows然后 cd <你的仓库> && keel init。装完确认 command -v keel 找得到它 ——
git hook 就是靠这个定位二进制的,不在 PATH 里会静默放行。
这版有什么
init / sync / decide / why / note / check / brief / hook / version。
review 属于 M3,会明确报「尚未实现」。
- 四种检查目标不可互相替代:
worktree只诊断、index用git checkout-index导快照验证真正要提交的内容、
commit-msg验证 trailer、range供 CI。暂存了坏代码但工作树已改好时,worktree通过而index失败。 - 提交门禁真的会拦:hook 里是
if command -v keel …; then keel check … || exit $?; fi,不吞退出码。
新增依赖而没有覆盖它的有效决策时退出码为 1;空 ADR 和不相关的 ID 不算覆盖。 - 不静默覆盖任何东西:CLAUDE.md / AGENTS.md 只碰
<!-- keel:begin -->到<!-- keel:end -->之间,
settings.json 只碰自己写过的 hook 条目,认领靠内容摘要而不是命令前缀。手改了托管块就报冲突,一个文件都不写。
遇到别人的 git hook 会失败并说明怎么接,--adopt-hooks才串联。 - 自决范围不会自己变大:
auto_promote: true直接报错;手写的proven不提高上限。
上限看项目策略,不看 tag。 - 规则只走 argv:不接 shell 字符串。退出码 0=通过、1=失败、其余一律是错误,
「目录不存在」不会被! grep翻转成通过。 keel hook永远 exit 0 且输出合法 JSON,和业务的 0/1/2 完全分开。- 一侧工具写下的记忆,另一侧的 SessionStart 拿得到,未验证的标注为「候选」。
M2 起的证据记录、任务接续、冲突与过期推导、keel review 和受控进化未做。
校验
SHA256SUMS 一并发布,shasum -a 256 -c SHA256SUMS 可对。