Skip to content

Releases: shiftu/keel

keel v0.7.1 · 产物不存在时重建

Choose a tag to compare

@shiftu shiftu released this 16 Sep 09:10

修复

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)

Choose a tag to compare

@shiftu shiftu released this 11 Sep 10:24

新增

  • keel deinit [--purge] [--dry-run]:init 的逆操作,从仓库里优雅退出。
    只带走 keel 自己写过的东西——所有权唯一来源是 generated.yaml 的 digest/owned_json
    和 git hook 里的 # keel:begin 标记,不猜、不按文件名或路径推测。

    顺序是 init 的严格倒序,先撤依赖 .keel/ 的部分,最后才碰 .keel/:

    1. 工具侧产物:技能副本、.claude/rules/keel.md 这类整文件删掉;CLAUDE.md /
      AGENTS.md / .codex/config.toml 只去掉标记块;.claude/settings.json /
      .codex/hooks.json / .mcp.json 只撤 keel 写过的那几条。块外内容、你自己的
      hook 条目、别的字段一律原样保留,去掉 keel 的部分后什么都不剩才删文件。
    2. git hook:含 keel 标记的才动。--adopt-hooks 串联过的把原脚本从
      .keel-local 换回去;不含标记的是别人的,一个字节不碰。
    3. .keel/cache/ 清掉。
    4. .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-missing

keel v0.6.0

Choose a tag to compare

@shiftu shiftu released this 11 Sep 03:38

新增

  • 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-missing

keel v0.5.0:M5 索引收敛

Choose a tag to compare

@shiftu shiftu released this 11 Sep 02:04

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

Choose a tag to compare

@shiftu shiftu released this 10 Sep 10:49

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

Choose a tag to compare

@shiftu shiftu released this 10 Sep 10:21

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

Choose a tag to compare

@shiftu shiftu released this 10 Sep 09:50

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          # Windows

SHA256SUMS 一并发布,shasum -a 256 -c SHA256SUMS 可对。

keel v0.1.0

Choose a tag to compare

@shiftu shiftu released this 10 Sep 09:20

第一个可用版本: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 可对。