跳转至

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 加入依赖:

uv add mkdocs-awesome-nav

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.ymltitle: 命令参考
  • docs/itp-科普/.nav.ymltitle: ITP 科普
  • docs/rl-guide/.nav.ymltitle: 强化学习教程
  • docs/openai-privacy-filter/.nav.ymltitle: OpenAI Privacy Filter
  • docs/timetrace/.nav.ymltitle: TimeTrace
  • docs/archives/.nav.ymltitle: 归档

强制顺序(非字母序)

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

- name: Build site
  run: uv run mkdocs build --strict

加上 --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 不存在。

修复:

  1. 全部 [xxx/](xxx/)[xxx/](xxx/README.md),让 mkdocs 识别为 .md 引用、解析为正确 URL
  2. [openclaw/](openclaw/)[openclaw/](openclaw/消息队列分析/README.md)(暂时跳到下一层)
  3. 新建 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.pymodels/model4.pyswellcamera/ 等)的相对链接 —— 这些文件在另一个仓库,根本不会进 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

  1. 直接把 md 文件丢进对应目录
  2. 看是否需要控制顺序:
  3. 不需要 → 完工。awesome-nav 会按文件名字母序自动加进导航
  4. 需要 → 编辑该目录的 .nav.yml,在 nav: 列表里把新文件加到合适位置
  5. 本地 uv run mkdocs serve 确认导航出现
  6. commit & push,CI 自动部署

场景 B:新建一个板块

例:新增 docs/new-project/

  1. 建目录 docs/new-project/
  2. docs/new-project/README.md,第一行 # 板块标题 —— 这会成为板块索引页
  3. docs/new-project/.nav.yml
title: 新板块中文标题
  1. 编辑 docs/.nav.yml,把 new-project 加到顶级 nav: 列表里你希望它出现的位置(不加就放最后)
  2. uv run mkdocs serve 验证

场景 C:要重命名/重排已有内容

  • 想改板块的中文标题 → 编辑该目录的 .nav.ymltitle: 字段
  • 想强制非字母序 → 编辑该目录的 .nav.yml,写 nav: 列表,参考 docs/monitor-system/.nav.yml
  • 想隐藏某个文件不出现在导航 → 该目录 .nav.ymlnav: 列表里不列它,并加 - "*" 在末尾通配其余(或文档官方推荐写法见 awesome-nav 文档)

场景 D:写文档内的相对链接

正确写法:

[记忆系统](hermes-memory/README.md)    ← 跨目录指向板块入口
[01 项目概览](01-项目概览.md)            ← 同目录
[详细文档](../timetrace/README.md)     ← 跨板块

错误写法(会触发 INFO,且 openclaw/ 这种没 README 的会真 404):

[记忆系统](hermes-memory/)             ← mkdocs 不识别,原样保留
[首页](docs/index.md)                  ← docs/ 前缀是仓库视角,站点视角下错的

规则: 文档内相对链接一律指到 具体 .md 文件,不要写裸目录路径,也不要带 docs/ 前缀。

场景 E:图片资源

放到 docs/assets/ 下,文档里用相对路径引用,例如:

![logo](../assets/logo.png)

环境初始化(新机器或重装)

# 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

添加新依赖

uv add <package-name>
# uv 会自动更新 pyproject.toml + uv.lock,commit 这两个文件

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/) 不算它能解析的链接 → 只能靠人工 grep site/ 输出验证。

待办 / 遗留

  • [ ] 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/ 下的 .pygames/ 是否要 mkdocs 跳过(默认会被复制到 site/,浪费空间)