更新日志
本文件记录本代码库(脚本、配置、文档)的重要变更。知识内容的时序记录在你自己内容库的
_wiki/log.md。
v1.6 — 2026-08-06
小版本,公开版只有一处可见变化:文档站多了一个「服务」页。 本轮开发的绝大部分(私人集成的模块化与发行管线)不随公开版发布,如实说明如下。
新增:文档站「服务」页
https://aip.cab/services —— 介绍在本工具集之外、以发行版形式提供的 私人集成套件(当前是飞书个人数据备份:云文档 / 知识库增量备份成 Markdown), 邀请制内测、免费。
这一页刻意写成”劝退优先”:先讲门槛再讲能力。自托管意味着要会用终端、 能配 cron、要在自己的租户建自建应用并扫码授权、token 有 7 天刷新窗口需要 一条保活任务——这些成本都在使用者那边,写清楚比事后解释诚实。同时明确 两条边界:微信个人号消息同步永久不做(无官方 API,协议手段有封号与 法律风险),不做托管代跑(替人保管 token 与数据是另一种产品形态)。
工具集本体(本仓)始终开源免费,与发行版互不影响。
门禁:身份类配置的正向断言支持多变量
tests/test_no_personal_identifiers.py
里那条「姓名/群名无形态可匹配, 故断言脚本确实从 env
读取」的检查,原先一个文件只能声明一个环境变量。
现在改成一个文件可声明多个——同一个脚本往往有不止一处身份类配置
(比如既要读本人显示名、又要读一份名单),此前只能挑一个盯着。
对公开版的影响:清单里不存在的文件照常跳过(exists()
守卫), 新写脚本时这条门禁能覆盖得更全。
v1.5 — 2026-08-05
主题是「兜底存在,但没人验它还在不在」。这一版把三层此前只靠人眼的东西 变成了会自己叫的检查:定时任务失败的通知层、隐私忽略规则的运行时自检、 编译流水线里两处被吞掉的失败。外加两条如实更正。
新增:scripts/notify-on-failure.sh
—— 失败通知层
update-all.sh / compile.sh
的非零退出码此前没有任何消费者:cron 把 stdout/stderr
全量重定向进日志,失败只体现在日志文本里,而日志没人看。
「失败要能被看见」在编排层与编译层都做到了,通知层一直是空的。
用法是把原命令整条包进来:
30 9 * * * cd $MIND && bash scripts/notify-on-failure.sh \
bash scripts/update-all.sh >> $HOME/.mind-update-all.log 2>&1
渠道由 MIND_NOTIFY_CMD 指定(任意接收 stdin 的命令,如
mail -s "mind 定时任务失败" you@example.com);不配就静默跳过。
四条契约各对应一种「通知反而帮倒忙」的方式,都有测试钉着:
- 只在失败时发。天天一条「一切正常」很快没人看,真出事那条跟着被忽略。
- 退出码原样透传。
cmd || notify会把整体退出码变成 notify 的 —— 通知发成功整条 cron 就”成功”了,原始失败反被通知掩盖。这是最容易写错的一处。 - 发卡自己失败也不许改写退出码,否则两个故障互相掩盖。
- 未配置就静默跳过,不改退出码。没配通知的机器不该每天刷一屏 「通知发不出去」把真日志淹掉。
装上第一天就抓到一条「装上以来从没成功过」的定时任务 —— 这类静默失效 正是它要解决的。
新增:update-all.sh
开跑前自检隐私兜底网
真机事故:.gitignore 被整个覆盖成一行,129
行规则全没了,六天无人察觉。 后果是 CLAUDE.md
那条「个人目录已 gitignore,git add
会静默什么都不干」当场失效。
现在 update-all.sh
在拿锁之前先验一遍:个人内容软链与常见密钥形状 (.env /
*.key / *.pem / secrets.json /
credentials.json)是不是真的还被 git
忽略。破了就红着退 3 并说清怎么复原;确要跳过用
MIND_SKIP_SHIELD_CHECK=1。
关键在于查事实而不是查形式:用
git check-ignore 问 git 的实际判定, 而不是读
.gitignore 的文本找关键字 —— 后者在规则被覆盖、被更晚的
! 反选、或落在另一个 ignore 文件里时全都会误判。
新增:安装指南写上 sage-wiki 版本下限与行为验证
上面那次 .gitignore 事故查到根因是 0.2.6 之前的
sage-wiki init: 它把 .gitignore
整个改写成一行 .sage/、把 .manifest.json
清成空壳 (上游 #127 已修)。两条后果不对称,值得记住:
.manifest.json被清空 → 下一次compile看到空清单,把整库从头重编 (全额 API 费用)。至少它”自愈”了,只是花了钱。.gitignore被清空 → 没有任何东西会重建它,静默六天。
安装指南 §3.1 与 Linux 服务器指南 各加了一节。
别看版本号 —— 源码构建出来的二进制一律报
dev (commit none, built unknown),
看不出新旧;文里给的是一段一分钟的行为验证脚本(造两个文件、跑一次
init、
看它有没有毁掉),以及一条规矩:已初始化的仓库里永远不要跑
sage-wiki init。
修复:compile.sh
两处被吞掉的失败
第 3 步 build-index.py 与第 4 步 lint 主管线既无
|| 兜底也无退出码检查: build-index
挂掉只打一行 traceback,流水线照走到「✔ 流水线完成」退 0,
索引悄悄停在上一轮版本而 cron 天天报绿。
改成能做的做完,但如实报失败:不中止(中止会丢掉本轮编译产物 —— 第 6 步才提交), 改为记账 → 继续 → 末尾非零退出。
两处细节是刻意的:
- lint 那条管线要取
PIPESTATUS[0](引擎自己的退出码)。直接看$?拿到的是 末尾grep -v的 —— 它在一行都不剩时返回 1,会把「干净」误报成失败。 - 记账类步骤仍是 best-effort:保鲜复核 / 决策不变量 / OKF 体检报的是 内容发现(有页待补、有条目违规),不是基础设施故障。算进失败的话,cron 会因为 「知识库里有几页没写完」天天告警,那种告警很快没人看,真故障跟着被淹没。
修复:setup-linux-server.md
里 brain-server 的解释器
systemd 片段写的是 ExecStart=/usr/bin/python3,而依赖装在
.venv 里 —— 在系统 python
较旧的发行版上照抄会起不来(实测过同型故障)。已改为
.venv/bin/python,并把解释器门禁从
scripts/*.service 扩展到文档里的 内联 unit
片段。
门禁:登录二维码也算凭据
.gitignore 补 *-qr.png /
*-qrcode.png —— 有些 CLI 的 auth login 会在
仓库根生成登录二维码,扫一下就能登进账号,和密钥同级但长得不像密钥。
另加两条测试:八个密钥形状逐个用 git check-ignore
验、个人内容目录实际 是否被 git 跟踪(查事实,不查
.gitignore 文本)。
更正 ①:v1.3 里一条顺序约束的理由写错了
v1.3 说 okf.py --fix 必须早于
build-index.py,理由是「索引若在注入前重建, 会读到上一轮的旧
frontmatter」。这个理由不成立。
build-index.py 实际只读 entity_type /
concept / sources / source /
标题|title,并不读 okf.py
注入的 type / stale_after —— 两步的先后
目前对索引内容没有任何影响。
顺序仍然保留、测试仍然钉着,但理由改成防御性的:一旦索引哪天开始消费
type, 顺序反了会读到旧字段,而那种 bug 极难察觉。
代码、测试断言、文档与文档站图示已全部改准。把约定说成事实是本项目自己反复 批评的毛病,这次犯在自己身上,如实更正。
更正 ②:有一道”补齐了的门禁”,补的是一个不存在的配置键
这次栽的地方在一份不随公开版发布的部署脚本里(生成一段第三方工具的配置片段), 但教训是通用的,值得写进来。
上一轮改动声称「片段里的 exclude
列表比文档声明的硬门禁少收敛一项,已补齐,
并加测试锁住两处一致」。这条是错的。
那个键在上游工具里根本不存在 ——
片段里那段收敛配置从来没有生效过,它只是长得像一道门禁。当时读的是文档措辞
而不是工具的实际命令行接口,于是给一个永远不会被读取的键”补齐”了一项,
又写了一条测试把两份都错的配置焊死成一致。
由此得到一条比这个 bug 本身更值得记住的话:测试能钉住一致性,钉不住正确性。 一条断言「A 与 B 相等」的测试,在 A、B 同时错时会绿得格外理直气壮 —— 这正是本项目那条「Prompt 不是检查器」的反面:看起来像检查器的东西,也未必是。
处理:删掉那条把错误焊死的测试(删除处留了理由注释),片段里换成指向工具真实 命令行接口的说明,并按那个接口真正把该关的关掉。
v1.4 — 2026-08-03
纯文档发布,无代码行为变化。 两页各补一张全景信息图, 顺带把一条不太好看的查证结论摆到明面上。
新增:两张「四层一图」
《系统如何运作》 —— 按数据流画(与该页第 1 节的权责视图互补,不重复):
| 层 | 内容 |
|---|---|
| 来源层 | raw/*,只读,唯一真相 |
| 加工层 | 两条路:① sage-wiki compile 引擎批量 ②
LLM 对话式 ingest 人在环 |
| 知识层 | 引擎领地(LLM 只读)与 LLM 领地,各自的门禁标在写入点上 |
| 调用层 | 索引 / 浏览站 / 本地检索 / 引擎查询,含一条回流箭头 |
图里说清了三件文字不容易讲明白的事:加工是两条路而非一条(只有
raw/todo
走人工深度处理,clippings、flomo/delta、pdfs
三者都在 config.yaml 的 sources
里由引擎自动编译);门禁挂在写入点上而不是挂在嘴上;调用层那条
回流才是”知识复利”的实现——没有它,这就只是个搜索引擎。
《OKF 合规》 ——
按流水线环节画:来源层 → 引擎层 → 合规层 (①
okf.py --fix → ② build-index.py → ③
okf.py --check,标注顺序约束与自愈回环) →
消费层(各字段分别被谁读取)。
两张图共用同一套视觉语汇(单张内联 SVG、左侧层轨、CSS class
上色而非写死 fill),
并排看时不用重新学一套符号;浅/深主题自动跟随,窄屏时图容器自身横向滚动、不压缩图形。
一条如实的查证结论:type
目前没有消费者
v1.3 补齐了 OKF 要求的 type
字段。事后把整个代码库翻了一遍,结果是:
读 entity_type 的:build-index.py:71 build-wiki-site.py:107
读 「类别」 的: build-wiki-site.py:230
读 frontmatter type 的: 只有 okf.py 自己
indexlib / searchlib
一次没碰。也就是说,这个字段今天的实际产出是零 ——
真正划算的是顺带做成的
okf.py --check(编译引擎领地此前零校验)与
stale_after 链路,而那两件都不需要 OKF。留着
type 的理由只有一条: 成本≈0 的互操作期权,等 OKF
生态工具出现时才兑现。
这条结论已画进信息图的末层(四条实线通向真实消费者,type
一条虚线指向空框), 不是藏在正文里。若你 fork
了本项目,可据此自行决定要不要保留这一步。
门禁
文档站的「两份载体」检查改成完全表驱动:章节数与主题词都写在
PAIRS 表里,
加新页或改章节结构会被门禁挡下,不会出现”改了一边忘另一边”。
v1.3 — 2026-08-03
对齐 Open Knowledge Format;修掉一批「失败伪装成成功」的缺陷—— 它们的共同点是出错时看起来仍然是绿的,所以比崩溃更危险。
新增:OKF 合规(Open Knowledge Format v0.2)
OKF
是 「用 markdown + YAML frontmatter
表示知识」的中立格式。本项目的形态与它高度重合 (bundle=目录、保留
index.md/log.md、容忍未知键),硬性要求只有两条:
每页有合法 frontmatter、type 非空。
- 新增
scripts/okf.py:--check只读体检(不合规非零退出)/--fix幂等注入 type由目录 + 已有键确定性推出,不用 LLM:概念页直接取entity_type(值域 concept / technique / claim 如实传导,不是一律拍成 concept)- 只加不改:已有
type的页一字节不碰;entity_type、类别、decision_type等原有键一律保留——它们各有现成消费者,改名等于为合规砸自家管线 compile.sh从五步变六步:--fix在重建 index 之前(索引读 frontmatter 生成, 注入晚了就读到上一轮旧字段),--check进 lint 记账;顺序由测试钉死- 补上引擎领地的门禁:
validate_write_set.py的作用面不含_wiki/{summaries,concepts,entities},此前那三个目录零校验 stale_after:把既有的半衰期保鲜(volatility/half_life_days+last_confirmed) 映射成 OKF 键,由--fix自动算出
文档:docs/guide/okf.md(文字版)+ 文档站「OKF
合规」图解页,含对比表与流水线图示。
别假设 python3
就是对的解释器
真机上 43 个测试同时变红,同一个根因:系统 python3 可能是
EOL 的 3.6, 而依赖装在 .venv 里。
- 新增
scripts/_pyresolve.sh:解析顺序<repo>/.venv/bin/python→$MIND_PYTHON→python3(版本够才用)→ 扫python3.13…3.9→ 大声告警后回落 - 所有
scripts/*.sh统一走它;新增门禁tests/test_interpreter_hygiene.py, 裸调python3会被拦下
修复:失败必须长得像失败
| 位置 | 出错时会发生什么 | 此前看起来像 |
|---|---|---|
vault.sh 提交 |
git 没有身份配置、钩子拒绝……提交失败 | 「无改动可提交」 |
update-all.sh 互斥锁 |
系统没有 flock(1)(macOS 就没有) |
继续跑,像是拿到了锁 |
| 隐私门禁 | git ls-files 出错返回空清单 |
扫过了,零命中 |
| 隐私门禁 | 非 ASCII 文件名被 quotepath 转义、读不到 | 中文名文件是干净的 |
| 发布门禁 | 公开版树只 git init 没 git add |
扫了 0 个文件却报通过 |
vault.sh 那条最要命:git commit
对「没东西可提交」和「提交出错」返回同一个非零码,
老写法 commit || echo "无改动可提交"
把两者混为一谈——表现是编译流水线报成功, 而产物根本没入库。现在先用
git diff --cached --quiet
判断暂存区空不空,再决定这次非零是哪一种。
其他
update-all.sh:内容库的拉取/推送做进编排(此前只写在文档里,靠人记得手动跑); 跨进程锁改成可移植实现(无flock时用mkdir+ PID 存活检查,而不是跳过互斥)- 新增 DeepSeek
编译后端(
config.deepseek.yaml);sage-backend.sh改为 从磁盘上实际存在的config.*.yaml发现后端,不再三处维护硬编码清单 - 文档站的「两份载体」门禁改成表驱动:每个手工页都自动检查 文字版/可视化版都在、主题一致、章节数一致、首页与模板导航可达 (手工页不过 pandoc,漏挂导航就是个只有知道 URL 才进得去的孤儿页)
v1.2 — 2026-07-25
新增一页「系统如何运作」总览;发布门禁堵掉一个真实存在的盲区。
新增:《系统如何运作》
一页看完整套系统:三层架构 / 双库布局 / 七步编译流水线 / 四道防腐门禁 / 查询两条路 / 隐私边界 / 开发纪律。
- 文字版
docs/guide/architecture.md(GitHub 上可直接读) - 可视化版:文档站的「系统运作」页,首页与各生成页导航均已接入
发布门禁加固(重要)
此前的禁忌词门禁是纯文本 grep,对 PDF / Office
这类压缩容器一律盲视——
规则写得再全,也读不到它们的正文。修法不是继续加规则,而是整类拒收:
- 发布时新增「不可扫描格式门禁」:公开版树里出现
pdf/docx/xlsx/…即中止发布 - 相应地,
docs/prd/下的二进制导出件(PDF / DOCX)与一份 HTML 导出不再随公开版发布, 权威版本一律是同目录的 Markdown,内容不受影响 - 移除
scripts/convert-sina-blog.py:它读的raw/articles/在任何公开克隆里都不存在, 本就是死代码
文档修正
- 服务器部署指南的目录命名此前自相矛盾(第 1 步克隆成
mind,第 9 步却cd mind-kit)。 统一为mind-kit/(代码)+mind-vault/(内容)——后者是init-vault.sh的默认值。 已按旧指南装好的人不必改动,只需知道文档里的路径示例现在用mind-kit。 - 文档站互链改写不再依赖硬编码白名单,新增页面不会再漏改成死链
v1.1 — 2026-07-25
面向使用者的更新体验修复,以及 Linux 兼容性改进。
修复:可以正常
git pull 更新了(重要)
此前每次发布都会重写仓库历史,导致已克隆的使用者更新时直接失败:
git pull → fatal: refusing to merge unrelated histories
git pull --ff-only → fatal: Not possible to fast-forward, aborting
现在发布采用线性追加——新版本接在上一版之后,使用者直接
git pull 即可快进更新:
cd mind-kit && git pull想让服务器自动跟进上游更新,加一条 cron:
0 8 * * * cd $HOME/second-brain/mind-kit && git pull -q
git pull只更新工具代码,不碰你的内容库——你的知识内容在自己的私有仓里。
Linux 兼容性
update-all.sh的 PATH 补上/usr/local/bin与~/.local/bin,Linux 上对sage-wiki/pandoc的探测更可靠(此前只找 Homebrew 路径)- 服务器部署指南新增「更新代码」一节,含自动跟进 cron 与更新后自检
v1.0 — 2026-07-25(首个公开版)
第二大脑工具集的首个公开发布。核心能力:
编译与内容管线
- 双库布局:代码库(本仓)与私有内容库分离,内容目录经软链挂入;
scripts/init-vault.sh一键建内容库骨架 + 软链 - 编译流水线
compile.sh:编译 → 重建索引 → lint 记账 → 保鲜复核 → 决策队列校验 → 生成本地浏览站 → 经vault.sh提交 - 一键全量更新
update-all.sh:日报 → 编译 → 订阅台账 → 门户 → 文档站;缺工具自动跳过,支持网页按钮触发与定时自启 - 后端可切换:GLM(默认)/ Kimi,OpenAI
兼容端点,
sage-backend.sh一键切换
规模化不腐化的四道机器
- 本地检索栈
searchlib.py:BM25 + CJK bigram 分词 + RRF 三通道融合 + 双语同义扩展;/api/search秒级返回,不走 LLM,索引按输入指纹自动刷新 - 评测与回归
evaluation/:检索 golden case(MRR / Top-1)+ 质量 required/forbidden token 断言;三后端(fixture / local / brain),基线只增不减 - 决策队列
decision.py:须先确认的动作走状态机(new → approve/reject/defer → apply,审批与执行分离),Dataview 单一看板入口 - 保鲜复核
freshness.py:半衰期模型(volatility high/medium/low = 30/90/365 天),到点提示复核,只提示不自动改 - 写集校验
validate_write_set.py:提交前对变更页跑确定性校验(frontmatter 闭合与键值形态、含冒号值引号化、保鲜字段、决策不变量),坏页拦在入库前
服务与界面
- 本地服务
brain-server.py:静态托管门户 +POST /api/search(本地检索)+POST /api/query(引擎查询,带中文分词兜底与同义扩展)+/api/update-all(网页一键全量更新,本地 Origin 护栏、后台单飞) - 门户与站点:
build-portal.py个人入口、build-wiki-site.py本地浏览站(含关系图)、build-site.sh公开文档站 - 工作日志:
daily-report.py/weekly-report.py从 git 提交与 log 自动盘点,保留手写区
开发纪律
- 遵循 Superpowers 四原则:测试先行 / 系统化 / 简单 / 用证据
- 脚本改动强制 pytest-first(RED → GREEN → REFACTOR);pre-push 钩子跑全量 pytest;GitHub Actions 服务端兜底
- 可执行门禁:个人标识形状检查、决策状态机不变量、写集校验 —— 规范由脚本执行,而非只写在文档里
docs/ 下的 Markdown 生成(以 Markdown 为准)
回到顶部 ↑