wiki-smith — 维护仓库的 .wiki/
Wiki 是仓库的记忆,专为代理书写:它们在这里找到规则,而无需再次询问。日记记录发生了什么;主题页面记录当前不变的知识。只存在于日记中的经验将会丢失。wiki-smith 会判断当前会话需要哪种记录,按照此 wiki 自身的规则进行编写,并完成检查。
完整方法(文件类型、笔记格式、导入、链接、日期、提交):references/method.md。配置键:references/config.md。致谢:ATTRIBUTION.md。变更:CHANGELOG.md。自身记忆:.wiki/。
<skill> 下为此技能文件夹(例如 ~/.claude/skills/wiki-smith)。每个脚本接受 -w <wiki dir>(默认为 ./.wiki)和 -c <config>(默认为 <wiki>/wiki.config)。
步骤 0 — 找到 wiki 及其规则
- Wiki 位于仓库根目录下的
.wiki/。如果仓库没有 wiki,则说明情况并提供从 templates/ 创建的机会(首先创建wiki.config.example);切勿未经询问就创建。 - 如果存在
.wiki/wiki.config,则读取它(配置项:日记文件夹、收件箱、索引、页脚标签、日期键、主分支)。如果没有该文件,则使用默认的通用英文配置:journal/、inbox.md、index.md、Map:、## History、created/updated。 - Wiki 自身的规则优先。 如果仓库中有关于如何维护 wiki 的页面(通过
rg -n -i 'maintain|manter' .wiki -l查找),或者AGENTS.md中有关于 wiki 的规则,则读取该部分并遵循其中与本技能不同的部分。 - 如果用户要求“更新 wiki”,并且 wiki(通常是索引)规定需要先确认,则仅将步骤 1 和步骤 2 作为计划提出:每个页面一行,说明更改内容、新笔记的标题,然后询问“是否应用?”,仅在获得肯定答复后才进行编辑。否则直接执行。
步骤 1 — 查看发生了什么,然后路由
读取会话内容(以及 git diff、git log 以了解完成的工作)。选择所有适用的行,不要多选:
| 会话内容 | 操作 |
|---|---|
| 一项决策、交付、方向变更、事故或研究 | 创建日常笔记:使用 scripts/note.sh -b "Title that says what changed" 并将段落内容通过管道传入。然后在收件箱中添加当天的行。 |
| 一条超越当日有效的规则、经验教训或事实 | 同时更新主题页面:写入当前有效的规则,不包含历史(历史保留在笔记和页面的历史部分中)。修正页面之前所说的内容;切勿叠加“曾经是…”。 |
| 涉及多个方面的新主题(它会再次出现,用一个页面会混杂不同类型的内容) | 创建内容地图 moc-<topic>.md 以及页面 <topic>-<facet>.md(速查表、安装、集成、与当前工具的对比……)。参见下方“新主题”。 |
| 没有值得记录的内容(仅是中间步骤,或提交信息已说明的内容) | 用一行说明,不创建任何内容。填充日记会使其难以阅读。 |
仅创建新笔记作为日记条目;永远不重写其他代理的笔记。
步骤 2 — 编写
日常笔记。 scripts/note.sh "<title>" 在 UTC 时间创建 <DIARY_DIR>/<today>/<HHMM>-<slug>.md 并输出路径(slug 规则和碰撞时的 -2 处理在脚本中)。stdin 仅在 -b 参数下读取:代理 shell 和 CI 会永远保持 stdin 打开,因此没有 -b 时脚本不会等待输入。通过管道传入正文:printf '%s\n' '<paragraph>' | scripts/note.sh -b '<title>';-b 会在标题和正文之间放置一个空行。如果没有 -b,则文件仅包含标题行;如需后续添加段落,请以空行开头:printf '\n%s\n' '<paragraph>' >> "$path"。正文是一个写得通顺的段落:发生了什么、为什么重要、证据在哪里(提交、PR、问题),并包含指向主题页面的链接。链接相对于日记文件夹(../../page.md)。模板:templates/note.md。
当天第一条笔记: scripts/day-index.sh 创建当天的索引;然后在“最近天数”列表顶部添加当天。如果笔记改变了仓库的工作方式,还需在收件箱的“重点内容”中添加一行。收件箱从不包含笔记正文。
主题页面(导入)。 查找它(rg -n -i '<word>' .wiki);如果不存在且该主题会再次出现,则创建它(模板:templates/page.md);如果内容较少,则放入附近页面中的一个章节。写入当前有效的规则。如果某次更改改变了页面所声称的内容,则在其历史部分顶部添加一行。笔记中需链接到该页面。
新主题。
- 首先编写页面,每个方面一个页面,每个页面自第一句起即自成一体。典型的方面包括:速查表(最优先:地址、命令、快捷键)、安装、集成、与当前所用工具的对比。
- 创建
moc-<topic>.md(templates/moc.md):一段开场白、“页面”(每行一个,速查表优先)、“需要首先了解的内容”(几个关键的规则)。 - 为每个页面添加页脚(
Map: [moc-<topic>](moc-<topic>.md) · Related: ...),将内容地图和每个页面添加到索引中,并确保至少从一个其他内容地图链接到该地图。 - 在日记中创建一个笔记,说明创建了什么并链接到内容地图。
步骤 3 — 收尾(始终按此顺序)
scripts/dates.sh— 从 git 获取created/updated前置元数据。幂等操作。scripts/day-index.sh— 重新生成日常索引。永远不要手动编辑。python3 -I scripts/lint.py— 修正它输出的每一个file:line: type: message直到退出码为 0(退出码 2 表示问题)。不要提交 lint 失败的状态。- 提交仅你自己的文件,通过路径指定,永远不要使用
git add -A:scripts/sync.sh -m "wiki: <what>" <path>...。当检出的仓库位于主分支、为最新状态且你的路径之外没有更改时,它会在原地提交;否则,它会将你的路径带入一个从origin/<main>创建的新的git worktree中。无论哪种方式,它都会对即将提交的内容进行 lint 检查,并拒绝 lint 失败的情况(退出码 1,不修改原检出,移除 carry worktree)。在 carry 情况下,生成的日常索引不会被复制:它会在 worktree 中重新生成,因此只会列出本次提交中的笔记。将仓库或你的主机要求的署名行添加到提交信息中。- 共享文件(索引、收件箱)可能被其他会话同时编辑: 不要将它们传入 carry。
scripts/sync.sh -W会从origin/<main>打印一个新的 worktree;在其中进行你的编辑(wiki 位于相同的相对路径),运行dates.sh、day-index.sh、lint.py,然后在此 worktree 内运行sync.sh -m ... [-p] <paths>。它会在该 worktree 中提交,并且使用-p时,会变基、推送、尽可能快进主仓库的检出,并移除 worktree。一个 carry 如果携带了其他会话的行(例如指向仅存在于检出中的页面的链接)会导致 lint 失败并在提交之前停止;该失败是使用-W的信号。
- 共享文件(索引、收件箱)可能被其他会话同时编辑: 不要将它们传入 carry。
- 仅在用户要求同步时推送: 相同的调用加上
-p(fetch、rebase、push HEAD:<main>、快进检出、移除 worktree)。永远不要强制推送,永远不要触碰其他人修改的文件:对于与你推送的内容不同且可能包含其他会话编辑内容的文件(索引、收件箱),保持原样。如果检出无法快进(本地主分支分歧,或本地编辑冲突),它会说明情况,但依然以退出码 0 退出,因为推送已成功。仅在用户要求时打开 PR。
在同一会话中提交你所写的内容,无需等待指示;发布由用户决定。
查询 wiki
使用 rg -n -i '<keyword>' .wiki(或浏览索引),然后只读取匹配的页面或章节,绝不读取整个 wiki。要了解发生了什么:查看收件箱(简短),然后仅查看相关的天数;每天对应其索引和其中列出的笔记。如果仓库有规格说明,它们会说明系统承诺的内容:rg -n -i '<keyword>' <specs dir>。
陷阱
- 日记不是页面。 仅写在笔记中的规则会丢失;在同一会话中将其导入到主题页面。
- 规则不包含历史。 应该是“创建卡片前先搜索现有卡片”,而不是“我们过去常常重复创建卡片”。故事保留在笔记中。
- 一个文件一个笔记。 多个代理可能会在同一天进行写入;它们绝不能编辑同一个文件。日常索引用
day-index.sh重新生成即可解决冲突。 - 跨会话的共享文件。 日常索引、
index.md和收件箱在一个检出中包含了所有会话的未提交编辑。sync.sh永远不会 carry 日常索引(它会在 worktree 中重新生成),并在提交前进行 lint,但它无法区分手动编辑的index.md或收件箱中哪些块是你的:carry 会带走整个差异。当其他会话可能接触过它们时,请使用sync.sh -W并在 worktree 中进行编辑。一个恰好没有破坏 lint 的外部行仍然会被 carry 带走;这是 carry 的文档化限制。 - 永远不要在 stdin 上等待。
note.sh仅在-b参数下读取正文;在代理 shell 中,无参数的读取会永久阻塞。这同样适用于你添加的任何脚本。 - 不要记录瞬态信息: 一次失败但重试成功的命令、环境小故障、一次性任务。在主题页面上记录有效的修复方法,而不是“X 坏了”(当原因消失后,这可能会固化成一个拒绝)。
- 链接: 使用相对链接,每个章节仅首次出现时提及;锚点是 GitHub 对标题的 slug 化处理(小写,无标点,保留重音符号,空格变为连字符)。重命名标题会破坏其锚点;lint 会指出这一点。将链接示例放在反引号内,以便 lint 不读取它。
- 重命名或删除页面: 使用
rg -l 'old-name' .wiki并修复所有链接,包括锚点;仅在所有内容迁移后才删除。 - 页面大小: 大约超过 150 行,或当规则、过程、参考资料和历史混合时,按类型拆分。
- 私有数据不能放进去。 Wiki 页面会被提交;将秘密、令牌和个人数据排除在外,并引述秘密存放的位置。
- Lint 的局限性: 它不能发现页面间的矛盾或过时的声明;这需要代理在时间允许时进行审查。
day-index.sh的限制: 包含手动书写旧格式笔记的日记文件是一个错误(file:line),不会自动迁移;使用note.sh将每个笔记移动到其自己的文件中,然后重新运行。
步骤 4 — 维护你自己的 wiki
如果本次运行教会了你关于 wiki-smith 本身的一些东西(路由错误、脚本怪癖),在 .wiki/lessons.md 中添加一行:- YYYY-MM-DD — <规则 + 原因>。编辑源代码克隆(biliboss/wiki-smith)并重新安装(npx skills add biliboss/wiki-smith -g --copy -a claude-code -y),而不是编辑已安装的副本(重新安装会覆盖它)。设计决策记录在 .wiki/design.md 中。