MkDocs 导航切换到 awesome-nav + 后续添加文档指南¶
日期: 2026-05-17
目标: 把 60+ 行手写 nav: 替换为基于文件系统自动生成的导航;让 CI 在 nav 路径写错时直接红;并固化后续添加文档的标准流程,避免再次踩 404 坑。
背景¶
仓库改造为 MkDocs 文档站之后,mkdocs.yml 里的 nav: 字段一直手动维护:每加一篇文档都得在两个地方(文件系统 + yml)同步,AI 协助生成时容易把路径写错。最近一条 commit 9e23ca4 fix: 对接前阅读路径.md 链接去掉多余的 docs/ 前缀,修复 404 就是这类问题的直接症状 —— 已经在线上看到 404 才回头修。
本次会话的诉求: 1. 找一个让 nav 不再需要手写 的方案 2. 让 CI 在路径错配时主动失败,而不是等用户点 404 3. 顺手盘点项目其他显著问题
操作步骤¶
1. 方案选型:mkdocs-awesome-nav¶
调研 MkDocs 生态后选定 mkdocs-awesome-nav(前身 mkdocs-awesome-pages-plugin)。核心思想:文件系统是唯一真相。
- 不写
nav:,按目录结构 + 文件名字母序自动生成导航 README.md自动当板块索引(搭配已有的navigation.indexes)- 单个目录需要重命名标题、强制顺序、隐藏文件时,在该目录放一份
.nav.yml局部干预
通过 uv 加入依赖:
2. 改造 mkdocs.yml¶
删除整段 nav: 块(约 60 行),改为:
plugins:
- search
- awesome-nav
validation:
nav:
omitted_files: warn
not_found: warn
absolute_links: warn
links:
not_found: info
anchors: info
absolute_links: info
unrecognized_links: info
validation 区是关键的「精细 strict」配置:让 nav 校验仍是 warn(被 --strict 提升为 error 卡 CI),但 文档内链死链降级到 info(不再让 monitor-system 海量历史死链堵死部署)。
3. 各目录添加 .nav.yml¶
根级(控制顶级板块顺序)¶
docs/.nav.yml:
nav:
- index.md
- hermes-agent
- openclaw
- openai-privacy-filter
- rl-guide
- itp-科普
- monitor-system
- timetrace
- archives
中文板块标题¶
只需重命名时,.nav.yml 写一行 title: 中文板块名 即可。
例:
docs/hermes-agent/commands-reference/.nav.yml→title: 命令参考docs/itp-科普/.nav.yml→title: ITP 科普docs/rl-guide/.nav.yml→title: 强化学习教程docs/openai-privacy-filter/.nav.yml→title: OpenAI Privacy Filterdocs/timetrace/.nav.yml→title: TimeTracedocs/archives/.nav.yml→title: 归档
强制顺序(非字母序)¶
docs/monitor-system/.nav.yml:
title: 摄像头检测系统
nav:
- README.md
- 对接前阅读路径.md
- 调研报告.md
- 结题报告.md
- 01-项目概览.md
- 02-环境与运行.md
- 03-系统架构.md
- 04-主程序与GUI.md
- 05-检测模块.md
- 06-模型与推理.md
- 07-打包与部署.md
- 08-问题与改进.md
- 09-开发指南.md
Hermes Agent 板块内部顺序¶
docs/hermes-agent/.nav.yml:
title: Hermes Agent
nav:
- README.md
- commands-reference
- hermes-session
- hermes-memory
- skills-system
- retry-and-config
4. CI 加 --strict¶
.github/workflows/deploy.yml:
加上 --strict 之后,配合 validation 配置,只有 nav 路径错 会让 CI 红,文档内既有死链依然只是 info。
5. 修首页 INFO 与潜在 404¶
mkdocs serve 启动后发现首页一片 INFO:
INFO - Doc file 'index.md' contains an unrecognized relative link 'hermes-agent/', it was left as is.
根因:docs/index.md 用 GitHub-repo 视角的 [xxx/](xxx/) 写法,mkdocs 静态校验不识别。大多数链接因为有 README + navigation.indexes,浏览器实际能跳;但 openclaw/ 是真 404,因为该目录之前没有 README.md,编译后 site/openclaw/index.html 不存在。
修复:
- 全部
[xxx/](xxx/)→[xxx/](xxx/README.md),让 mkdocs 识别为 .md 引用、解析为正确 URL [openclaw/](openclaw/)→[openclaw/](openclaw/消息队列分析/README.md)(暂时跳到下一层)- 新建
docs/openclaw/README.md作为板块入口,让 OpenClaw 左侧导航这一级可点击
6. 修结题报告同款 docs/ 前缀 bug¶
docs/monitor-system/结题报告.md 末尾的 9 条章节索引链接误写成 docs/0X-xxx.md(仓库视角而非站点视角),跟 9e23ca4 修过的 对接前阅读路径.md 同源。批量替换 ](docs/0X-...md → ](0X-...md。
7. 验证¶
rm -rf site && uv run mkdocs build --strict
# => Documentation built in 1.80 seconds (无 WARNING/ERROR)
# 顶级板块索引页全部存在
for d in site/hermes-agent site/openclaw site/openai-privacy-filter \
site/itp-科普 site/rl-guide site/archives \
site/monitor-system site/timetrace; do
ls $d/index.html
done
8. 落 4 个 commit¶
8c69f07 feat: 切换 mkdocs 导航到 awesome-nav 自动模式
00f1210 ci: deploy.yml 启用 mkdocs build --strict
0f0f25d fix: 首页链接补全 README.md 后缀
54b6d2d fix: 结题报告链接去掉多余 docs/ 前缀
9. monitor-system 源码链接批量降级¶
会话末追加:发现 mkdocs serve 时点 monitor-system 文档里的链接,浏览器会请求 /monitor-system/main.py、/monitor-system/models/model4.py、/monitor-system/CameraMonitorSystem.spec 等 URL 拿到 404 —— 因为这些指向 MonitorSystem 项目的源码、不在 report 仓库内,源码也未公开。
决定降级为 inline code:保留文件名+行号供读者参考,不再误导点击。一次性脚本(已删除,内容存档于此):
"""一次性脚本:把 monitor-system 文档里所有指向项目源码(.py/.spec/.txt 等
非 .md 文件)的 markdown 链接降级为 inline code 或纯文本。"""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1] / "docs" / "monitor-system"
SOURCE_EXTS = "py|spec|txt|bat|sh|cfg|ini|toml|json|yaml|yml|cmd|exe|dll"
PATTERN = re.compile(
rf"\[([^\]]+)\]\(\.\.[^)]*?\.(?:{SOURCE_EXTS})(?:#[^)]*)?\)"
)
def replace(match: re.Match) -> str:
text = match.group(1)
if "`" in text:
return text # text 内已含 backtick,保留原样去掉链接
return f"`{text}`"
for md in sorted(ROOT.glob("*.md")):
s = md.read_text(encoding="utf-8")
new, n = PATTERN.subn(replace, s)
if n:
md.write_text(new, encoding="utf-8")
print(f"{md.name}: {n}")
执行结果:10 个文件、185 处替换。
替换前后对照:
| 原链接 | 处理后 |
|---|---|
[swellcamera.py:24](../swellcamera/swellcamera.py#L24) |
`swellcamera.py:24` |
[L195](../swellcamera/swellcamera.py#L195) |
`L195` |
[L179 的 `while True:`](../...) |
L179 的 `while True:` |
跨板块的 .md 链接(如 ./07-打包与部署.md)一律不动。
遇到的问题与解决¶
问题 1:开启 --strict 后构建被 214 个 WARNING 终止¶
现象: 首次 mkdocs build --strict 输出 Aborted with 214 warnings in strict mode!。
原因: 大部分是 monitor-system/ 各文档里指向 MonitorSystem 项目源代码(main.py、models/model4.py、swellcamera/ 等)的相对链接 —— 这些文件在另一个仓库,根本不会进 docs/,mkdocs 一律按死链报 WARNING。
解决: 不修这些死链(量大、且本身就是"指向外部源码"的设计意图),而是用 validation.links.not_found: info 把这一类降级到 info;保留 validation.nav.*: warn 让真正关心的 nav 错误依然卡 CI。
问题 2:build --strict 通过 ≠ 链接都能点¶
现象: 我(Claude)跑通 mkdocs build --strict 就交差,但用户 mkdocs serve 起来后看到首页一片 INFO,并发现 openclaw/ 链接 404。
原因: mkdocs 把 [xxx/](xxx/) 这种目录路径当成「未识别相对链接」直接 INFO 后原样保留,不算 warning,不会被 strict 卡住。但运行时浏览器能不能跳,取决于 site/<dir>/index.html 是否真的存在 —— 这是个 strict 不会检查的盲区。
解决:
1. 流程改进:build 之后必须 ls site/<dir>/index.html 逐个核对顶级板块是否真有索引页
2. 内容改进:把所有目录链接补全为 dir/README.md 形式,让 validator 识别并校验
问题 3:archives 目录到底删不删¶
现象: 用户最初说"archives 那个文件夹应该可以直接删了",但 archives 里有当天刚生成的 archive-202605171636-uv-migration-and-footer.md。
解决: 暂停操作向用户确认。用户澄清:archive 是该机器的开发指南,完全保留;之前"多套了一层"指的是 MkDocs-部署/ 和 OpenClaw-Use/ 这两个子分类目录的存在 —— 但本次会话最终决定也保留这两层子目录不动。
教训:destructive 操作必须二次确认,即使会话上下文里有 "work without stopping for clarifying questions" 的指示。
添加新文档指南(核心)¶
切换到 awesome-nav 之后,绝大多数添加文档场景不再需要碰
mkdocs.yml。下方是不同场景的标准动作。
场景 A:在已有板块下加一篇文档¶
例:在 docs/hermes-agent/ 下加一篇 tracing.md
- 直接把 md 文件丢进对应目录
- 看是否需要控制顺序:
- 不需要 → 完工。awesome-nav 会按文件名字母序自动加进导航
- 需要 → 编辑该目录的
.nav.yml,在nav:列表里把新文件加到合适位置 - 本地
uv run mkdocs serve确认导航出现 - commit & push,CI 自动部署
场景 B:新建一个板块¶
例:新增 docs/new-project/
- 建目录
docs/new-project/ - 写
docs/new-project/README.md,第一行# 板块标题—— 这会成为板块索引页 - 加
docs/new-project/.nav.yml:
- 编辑 根
docs/.nav.yml,把new-project加到顶级nav:列表里你希望它出现的位置(不加就放最后) uv run mkdocs serve验证
场景 C:要重命名/重排已有内容¶
- 想改板块的中文标题 → 编辑该目录的
.nav.yml的title:字段 - 想强制非字母序 → 编辑该目录的
.nav.yml,写nav:列表,参考docs/monitor-system/.nav.yml - 想隐藏某个文件不出现在导航 → 该目录
.nav.yml的nav:列表里不列它,并加- "*"在末尾通配其余(或文档官方推荐写法见 awesome-nav 文档)
场景 D:写文档内的相对链接¶
正确写法:
[记忆系统](hermes-memory/README.md) ← 跨目录指向板块入口
[01 项目概览](01-项目概览.md) ← 同目录
[详细文档](../timetrace/README.md) ← 跨板块
错误写法(会触发 INFO,且 openclaw/ 这种没 README 的会真 404):
规则: 文档内相对链接一律指到 具体 .md 文件,不要写裸目录路径,也不要带 docs/ 前缀。
场景 E:图片资源¶
放到 docs/assets/ 下,文档里用相对路径引用,例如:
环境初始化(新机器或重装)¶
# 1. 安装 uv(如未安装)
# Windows: winget install astral-sh.uv
# macOS: brew install uv
# 2. 拉仓库
git clone https://github.com/Setsuna-Yukirin/report.git
cd report
# 3. 装依赖(自动创建 .venv 并按 uv.lock 安装)
uv sync --frozen
# 4. 本地预览
uv run mkdocs serve
# 打开 http://127.0.0.1:8000
# 5. 严格构建(CI 同款,验证当前状态会不会让 CI 红)
uv run mkdocs build --strict
添加新依赖¶
CI 行为速查¶
- 推 main 分支 → 自动跑
uv run mkdocs build --strict→ 通过则部署到 Cloudflare Pages - 失败信号:
Doc file X is not included in the "nav" configuration→ nav 缺挂文件(其实 awesome-nav 自动挂,几乎不会触发,但保险)Doc file X contains a link Y, but the target Z is not found且属于 nav 项 → nav 路径写错,立刻修- 文档内死链报的是 INFO,不会卡 CI
知识清单¶
- mkdocs-awesome-nav 选型理由: mkdocs 生态唯一仍在维护的自动导航插件(前身 awesome-pages-plugin 已重命名升级为 awesome-nav v3)。文档地址
https://lukasgeiter.github.io/mkdocs-awesome-nav/。 .nav.yml语法精要: 仅title:+nav:两个常用字段;nav:列表里可写文件名、目录名、- "*"通配剩余。navigation.indexes特性: Material 主题 feature,让目录的README.md自动成为该目录的索引页,URL 为/<dir>/。本仓库 mkdocs.yml 已启用。use_directory_urls默认 true: 所以xxx.md编译出来是xxx/index.html,访问 URL 为/xxx/。- mkdocs
validation配置(9.x+): 比--strict标志更精细,可单独设置nav.*和links.*各项的严重程度(ignore/info/warn)。--strict会把 warn 提升为 error。 - uv 项目工作流:
uv sync --frozen严格按 lockfile 装;uv add X同时更新 toml + lock;uv run <cmd>在 venv 内运行。 - 死链检测的盲区: mkdocs 静态校验仅认
.md引用,写成[x](dir/)不算它能解析的链接 → 只能靠人工 grepsite/输出验证。
待办 / 遗留¶
- [ ] monitor-system 文档内有大量
../调研报告.md之类的「同目录但错误地用../跳出去」的链接(参见 build 输出的 INFO),后续可批量清理 —— 跟9e23ca4同款 bug - [x] ~~monitor-system 文档指向 MonitorSystem 项目源代码(
main.py等)的链接全部点不开~~ — 已在步骤 9 用批量脚本降级为 inline code(185 处),MonitorSystem 源码未公开、无法改成 GitHub URL,权衡后选择保留信息但不让点击 - [ ] 可选:引入
mkdocs-git-revision-date-localized-plugin替代deploy.yml里 inline Python 注入build_time的 hack —— 后者通过正则改 yml,缩进一变就静默失败 - [ ] 可选:考虑
rl-guide/chapter_XX/下的.py、games/是否要 mkdocs 跳过(默认会被复制到site/,浪费空间)