organize-vault
知识库目录结构生成与 MOC 维护助手。
When to Use
当用户说以下内容时激活:
- "整理一下 vault"、"把新笔记归类"、"更新 MOC"
- "帮我初始化 vault 结构"、"生成目录层级"
- "哪些笔记还没归类"
- "organize my vault"、"update MOC"
Core Constraints
在整个执行过程中,以下约束不可违反:
- 永不修改笔记内容:笔记的 body 文本不可改动。可移动文件位置、创建 MOC.md、在 MOC.md 中追加 wikilink。
- 变更必须经用户确认:所有文件移动和写入在执行前展示完整清单,等待明确确认。
- 模糊性是正常状态:无法归类的笔记归入
misc/,标注"待整理",不强制归入不合适的主题。 - git 是唯一回退:所有变更受 git 追踪,执行前告知用户可通过
git revert撤销。
目标结构
初始化完成后,vault 应呈现如下层级:
vault/
├── MOC.md # 根目录索引,链接所有主题目录
├── programming/
│ ├── MOC.md # 本主题笔记列表(含描述)
│ ├── python-async.md
│ └── docker-compose.md
├── tools/
│ ├── MOC.md
│ └── vim-config.md
├── reading/
│ ├── MOC.md
│ └── deep-work.md
└── misc/
├── MOC.md # 标注"待整理"
└── random-idea.md
入口:检测场景
1. 若 vault_root 未知,询问用户 vault 的根目录路径
2. 检测 git 状态:
git -C <vault_root> status --porcelain 2>&1
- 若返回 "not a git repository":提示用户执行 git init,停止
3. 检测是否存在 MOC 文件(见 MOC 识别规则):
- 若无 MOC 文件 → 走【场景 B:初次初始化】
- 若有 MOC 文件 → 走【场景 A:增量维护】
MOC 识别规则
以下任一条件满足,则该文件被识别为 MOC,不参与归类:
- 文件名为
MOC.md(大小写不敏感) - 文件顶部 frontmatter 中含
type: moc或moc: true
笔记描述提取规则
在读取笔记全文时,同步提取一句简短描述,用于写入 MOC.md。提取优先级:
- frontmatter 的
description字段(直接使用) - H1 标题后第一个非空段落的首句(截断到 50 字以内)
- 以上均无:不写描述,只写
- [[note-stem]]
描述只写入 MOC.md,不触碰原笔记文件。
场景 A:增量维护(已有 MOC)
Step 1 — 识别新增笔记
# 未提交的新增文件
git -C <vault_root> status --porcelain | grep '^?' | awk '{print $2}' | grep '\.md$'
# 或:相对上次 commit 新增的文件
git -C <vault_root> diff --name-only --diff-filter=A HEAD
过滤规则:
- 只保留
.md文件 - 排除
MOC.md(按 MOC 识别规则) - 若结果为空:告知用户"未发现新笔记(相对 git 状态)",结束
Step 2 — 读取现有目录结构
用 find 找到所有 MOC.md 文件,逐一读取,理解各主题目录的内容范围。
在内存中构建映射:
{
"programming/MOC.md": "涵盖编程语言和框架,已有:[[python-async]], [[docker-compose]]...",
"tools/MOC.md": "开发工具配置,已有:[[vim-config]], [[git-tips]]..."
}
Step 3 — 归类决策
对每个新笔记,Read 其全文,然后:
- 按【笔记描述提取规则】提取一句描述
- 对比各主题目录,判断归属:
- 高置信度:直接给出目标目录
- 低置信度:列出候选目录,给出理由,让用户选择
- 无法归类:归入
misc/,标注"待整理"
- 每篇笔记只移动到一个目录(主要主题);若同时匹配多个主题,在多个
MOC.md中均追加 wikilink - 检查目标
MOC.md是否已含该笔记链接:若已含,跳过
Step 4 — 展示变更预览
待执行的操作:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
移动:python-async.md → programming/python-async.md
更新:programming/MOC.md ← 追加
[[python-async]] — Python asyncio 事件循环机制详解
理由:笔记讨论 Python asyncio,归入 programming
移动:vim-config.md → tools/vim-config.md
更新:tools/MOC.md ← 追加
[[vim-config]] — Vim 配置文件与插件管理
理由:编辑器配置,归入 tools
无法归类(共 1 篇):
random-idea.md → misc/random-idea.md(标注"待整理")
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
所有变更受 git 追踪,可通过 git revert 撤销。
确认执行?(可指定"全部"或逐条接受/拒绝)
Step 5 — 执行变更
对每个用户确认的归类:
mv <vault_root>/<note>.md <vault_root>/<topic>/<note>.md- Edit
<topic>/MOC.md,在笔记列表末尾追加:- 有描述:
- [[note-stem]] — {描述} - 无描述:
- [[note-stem]]
- 有描述:
若目标目录不存在,先 mkdir -p 创建,再在其中创建 MOC.md(格式见下文)。
场景 B:初次初始化(无 MOC)
分四步执行,避免一次读取大量笔记导致上下文过长。
Step 1 — 标题扫描
find <vault_root> -name "*.md" -not -path "*/.git/*" -not -name "MOC.md"
对每个文件,只提取:
- 文件相对路径
- H1 标题(首行
# ...)或文件名 stem(若无 H1)
不读取笔记 body。
Step 2 — 分组提案
基于文件路径(目录结构)+ 标题,推断主题分组,向用户提出候选结构:
建议生成以下目录结构(基于 47 篇笔记的标题和路径):
programming/ — 约 18 篇(Python, TypeScript, 算法...)
tools/ — 约 12 篇(Docker, Vim, Git...)
reading/ — 约 9 篇(读书笔记, 摘录...)
projects/ — 约 5 篇(项目记录...)
misc/ — 约 3 篇(暂无明显归属)
是否采用这个结构?可以调整目录名、合并或拆分分组。
等待用户确认或修改。不执行任何文件操作。
Step 3 — 逐组细化
用户确认结构后,按分组逐批读取笔记全文(每批 10-15 篇),对每篇笔记:
- 按【笔记描述提取规则】提取一句描述
- 确认归属哪个目录:
- 归属明确的:记录目标目录 + 描述
- 跨主题的:移动到主要目录,在次要目录的
MOC.md中也追加链接 - 完全不匹配的:归入
misc/,标注"待整理"
记录所有归属决策(含描述),不写文件。
Step 4 — 目录重组
汇总所有归属决策,展示完整预览:
即将执行以下操作(共 47 个笔记):
新建目录:
programming/ tools/ reading/ projects/ misc/
移动文件(共 47 个):
python-async.md → programming/python-async.md
docker-compose.md → programming/docker-compose.md
vim-config.md → tools/vim-config.md
...(共 47 条,全部展示)
新建 MOC 文件(共 6 个):
MOC.md (根目录索引,5 个主题)
programming/MOC.md (18 个笔记,含描述)
tools/MOC.md (12 个笔记,含描述)
reading/MOC.md (9 个笔记,含描述)
projects/MOC.md (5 个笔记,含描述)
misc/MOC.md (3 个笔记,标注"待整理")
清理空目录(若有):移走笔记后变空的原目录将被删除
所有变更受 git 追踪,可通过 git revert 撤销。
确认执行?
用户确认后,按以下顺序执行:
mkdir -p创建所有主题目录mv移动所有笔记文件- Write 创建每个
<topic>/MOC.md(含描述) - Write 创建根目录
MOC.md rmdir清理空目录(失败则静默跳过)
MOC 文件格式
主题目录 <topic>/MOC.md:
# {主题名称}
## 笔记
- [[python-async]] — Python asyncio 事件循环机制详解
- [[docker-compose]] — 多容器应用编排配置示例
- [[algorithm-notes]]
(无描述的笔记直接写 - [[note-stem]],不强制加破折号)
根目录 MOC.md:
# Vault Index
## 主题
- [[programming/MOC|Programming]]
- [[tools/MOC|Tools]]
- [[reading/MOC|Reading]]
- [[projects/MOC|Projects]]
- [[misc/MOC|Misc]]
边界情况处理
| 情况 | 处理方式 |
|---|---|
| vault 未初始化 git | 提示执行 git init && git add -A && git commit -m "init",停止 |
| vault 无任何 .md 文件 | 告知 vault 为空,结束 |
| 无法确定 vault 根目录 | 询问用户,不猜测 |
| 根目录已有 MOC.md | 询问用户是覆盖还是追加,不默认覆盖 |
| 笔记同时匹配多个主题 | 移动到主要目录,在次要目录 MOC.md 中追加跨目录 wikilink |
| 移走笔记后原目录变空 | rmdir 删除,失败则静默跳过(可能含其他文件) |
| MOC.md 已含该笔记链接 | 跳过,不重复添加 |
| 新笔记本身是 MOC.md | 跳过归类,告知用户 |
| 笔记无可提取描述 | 只写 - [[note-stem]],不加破折号,不报错 |
| 大型 vault(> 100 篇笔记)初始化 | 严格执行分步策略,每批不超过 15 篇全文读取 |