Obsidian 里的笔记,靠 AI“自己长大”——打造第二大脑的机制
把散乱的 Obsidian 笔记交给 AI 读,半自动地加链接、做摘要、做整理。写入要谨慎、以读取为主,养出一个“自己长大的 Vault”的真实经历。
凌晨 0 点,我对着 Obsidian 的搜索框敲下:“那条命令,叫啥来着。”
两年前记下的,区区三行 shell 命令。它在,这点我确定。可在超过 500 条笔记里,它到底埋在哪一条,我是怎么也想不起来了。那天最后我放弃了搜,又重新去谷歌了一遍。
这事,我估计不止我一个人遇上。
Obsidian(一款笔记 app),越用越顺手。但与此同时,它也一定会越来越乱。每日记录、读书笔记、代码片段、文章选题、会议纪要,全都以 Markdown 文件的形式堆着,攒上半年,就成了“一座只属于你、却又死活搜不到东西的杂物屋”。
于是我开始做这么件事:让 AI 去读我的 Vault(笔记的存放处),把整理这活儿替我分担一半。贴链接、做摘要、把走丢的笔记捞回来。每天这么一点点地跑,原本散成一盘沙的笔记,竟然开始自己串起来了,真有点“第二大脑”那味儿了。今天就聊这个。
话说回来,“笔记会长大”是啥意思?
普通笔记,写下来那一刻就是巅峰。往后就只剩被遗忘。
可 Obsidian 有个写法 [[笔记名]],能把笔记彼此连起来(这叫 Wikilink)。连得越多,整个东西就越像一张地图。从“TypeScript 的类型错误”那条笔记,能跳到“那天被 Docker 坑了一整天”,再从那儿连到“上个月那次故障复盘”。点连成线,线连成面,就是这种感觉。
问题在于,这种串联,要是人来做,麻烦到根本坚持不下去。
这块就交给 AI。具体说,搭档是 Claude Code 这个工具。它本是写代码的 AI,但说白了,可以当成一个“能安全读写一整文件夹 Markdown 的作业员”来用。Obsidian 本地优先(文件就放在你自己电脑上)的好处原封不动留着,只把整理那份苦力交给 AI。这就是今天的作战计划。
不过有一条,我得先把丑话撂前头。把整个 Vault 的编辑权都交给 AI,这事绝对别干。
.obsidian/(设置文件夹)也好,已经发出去的文章也好,像合同那样的私人笔记、API key 也好,没有任何理由让 AI 去读。所以我的方针一直是:读取放宽点,写入超级谨慎。这跟我之前写的 给 AI 搭“脚手架”的做法 完全是同一套思路——说白了,就是先装好辅助轮,再让它跑。
这三个场景里它最管用(3 个)
光讲抽象的传不到位,挑三个我实打实感到“哦,这真行”的瞬间。
第一个,是早上的每日记录。 每天早上,让 AI 读昨天的笔记,吩咐它“把没做完的任务挪到今天,再把昨天的收获压成三行”。于是,昨天的自己随手撒下的烂摊子,就被整成今天的自己一上手就能动的样子端出来了。“啊,这就是昨天卡住的那个”,一瞬间就想起来。接班的人,是未来的自己。
第二个,是代码片段的救援。
就是刚才那个“两年前的命令”难题。把跑通过的命令往 snippets/ 文件夹一扔,AI 会自动给它补上“这是干嘛用的命令”的说明,再连上其他相关的笔记。一条光秃秃的命令,就这么摇身变成了“能被搜到的、像样的笔记”。
第三个,是文章选题的备料。
要写博客那天,把 content-ops/ 文件夹的选题本给 AI 看,问它“这篇文章,能往哪些旧文章上挂内链?”。它有时会把我自己都忘了的、半年前的某篇文章给翻出来,这一手是真不起眼地顶用。点和点连上的那一下,就是这个瞬间。
我亲手翻过的 3 次车
这块可能才是正题。最初那几周,我的 Vault 被 AI 祸害得不轻。我老实晒出来。
第一桩,一上来就让它“把整个 Vault 整理一下”。 这桩最惨。AI 连两年前那些不知所云的笔记都要“热心”地去整理,自作主张生出来一大堆标签和标题。Graph view(把笔记联系可视化的那个画面)成了一片满是陌生标签的丛林。旧笔记当初啥意图,AI 根本不懂,可它偏要靠猜来动手。从那以后,对象我必定只圈定在一个文件夹里。
第二桩,让 AI 擅自改了笔记名。
“标题给我弄得好认点。”——就这一句,[[旧笔记名]] 的链接齐刷刷全断了。Obsidian 里你自己改名,链接会跟着走;可外部的 AI 一口气把文件名改了,这种跟随就失灵了。断链尸横遍野。现在“重命名必须先问人”,是我立下的铁律。
第三桩,让它读了 private/。
这桩可不止后背发凉那么简单。一个装着合同金额笔记的文件夹,因为我偷懒没配权限,竟处在 AI 能读的状态。事故倒是没真出,可这无异于让一个新人光手去摸生产数据库。只要在 deny(拒绝清单)里老老实实写上,压根就没有出事的余地。教训就是:是我自己抠门没配设置,活该。
上手办法:只放三个文件
不难。在 Vault 根目录下,备齐三样就行。
先,把文件夹分一分。一开始就分得太细,必崩,所以粗粗地来就够。
# 在 Vault 根目录执行。只分出:每天用的地方、项目、公开作业、保护区
mkdir -p inbox daily projects content-ops snippets templates scripts archive private
各文件夹干啥的、AI 能管到哪,我是这么分派的。
| 文件夹 | 角色 | 交给 AI 的范围 |
|---|---|---|
inbox/ | 未整理笔记、网页剪藏的接收盘 | 读取与新建 |
daily/ | 每日记录、工作笔记 | 新建、追加、前一天的摘要 |
projects/ | 进行中任务、交接 | 新建、更新、整理未决事项 |
content-ops/ | 文章草案、内链、发布检查 | 整理草稿、确认链接 |
snippets/ | 代码片段与用法 | 补说明、整理标签 |
templates/ | Obsidian 模板 | 原则上先确认再编辑 |
archive/ | 已完成、已封存 | 禁止编辑 |
private/ | 个人信息、合同、机密 | 连读取也禁止 |
接着,在 Vault 根目录放一个 CLAUDE.md。这是写给 AI 的“咱家规矩”那张纸。与其大谈长篇理念,不如把希望它守的输入输出规则写得短小,反而更见效。
# Obsidian Vault 的规矩
## 角色
- 这个 Vault 是放每日记录、项目交接、代码片段、文章草案的地方。
- 即便不读 private,也要能正常干活。
## 文件夹方针
- `daily/`: 用 `YYYY-MM-DD.md` 新建、更新每日笔记。
- `projects/`: 每个进行中的案子,维护一张交接笔记。
- `snippets/`: 把跑通的命令,连同来龙去脉、失败例一起留下。
- `templates/`: 读随便读。编辑之前必须先问。
- `archive/` 和 `private/`: 不编辑。private 的内容连摘要都不许做。
## 写法规矩
- 内链用 `[[项目名]]` 这种 Wikilink 写法。
- 笔记开头加上 YAML 属性(status 等)。
- 一段控制在 5 行以内。
## 安全规矩
- 现有笔记的重命名,必须先确认。
- 不许改写 `.obsidian/` 的设置。
- 批量编辑前,先把目标文件列出来,等批准。
- 编辑完务必跑一遍 `node scripts/audit-wikilinks.cjs .`。
最后这个最要紧。用 .claude/settings.json 把权限物理地锁死。CLAUDE.md 是“拜托你”,这个才是“物理锁”。是为了让第三桩翻车再也不重演的门卫。读取放宽,写入只限作业文件夹,危险操作用 deny 彻底封死。设置细节看官方权限文档。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Read(./CLAUDE.md)",
"Read(./daily/**)",
"Read(./projects/**)",
"Read(./content-ops/**)",
"Read(./snippets/**)",
"Read(./templates/**)",
"Read(./scripts/**)",
"Edit(./daily/**)",
"Edit(./projects/**)",
"Edit(./content-ops/**)",
"Edit(./snippets/**)",
"Write(./inbox/**)",
"Write(./daily/**)",
"Write(./projects/**)",
"Write(./content-ops/**)",
"Write(./snippets/**)",
"Bash(node scripts/audit-wikilinks.cjs .)"
],
"ask": [
"Edit(./templates/**)",
"Bash(git *)"
],
"deny": [
"Read(./private/**)",
"Read(./**/.env)",
"Read(./**/.env.*)",
"Edit(./.obsidian/**)",
"Edit(./archive/**)",
"Write(./archive/**)",
"Bash(rm *)",
"Bash(del *)"
]
}
}
这三张放好,往后就只剩开口吩咐了。诀窍是别说“你整理整理”。范围、成品、禁止事项、验证,每回全给指明。
读一下 daily/2026-06-04.md 和 projects/site-refresh.md。
照着 templates/daily.md 做一份 daily/2026-06-05.md。
没做完的任务,只把负责人还是自己的接过来。
.obsidian/、archive/、private/ 都别碰。
编辑完跑一遍 node scripts/audit-wikilinks.cjs .,把结果报给我。
虽短,但输入、输出、禁区、验证命令全在里头。比起“整理整理”,可复现性高出好几倍。
收尾的门卫:用机器查死链
让外部的 AI 改文件,时不时就会把 Wikilink 改坏。人眼,会漏。所以最后,套一个脚本机械地把坏链都翻出来。把它存成 scripts/audit-wikilinks.cjs。
#!/usr/bin/env node
// 把 Vault 内坏掉的 / 含糊的内链([[...]])翻出来的门卫脚本
const fs = require("node:fs");
const path = require("node:path");
const vaultRoot = path.resolve(process.argv[2] || ".");
const ignoredDirs = new Set([".git", ".obsidian", ".trash", "node_modules"]);
const allFiles = [];
const markdownFiles = [];
function walk(dir) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (ignoredDirs.has(entry.name)) continue;
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(full);
} else if (entry.isFile()) {
allFiles.push(full);
if (entry.name.toLowerCase().endsWith(".md")) markdownFiles.push(full);
}
}
}
function toPosix(filePath) {
return filePath.split(path.sep).join("/");
}
function withoutMd(value) {
return value.replace(/\.md$/i, "");
}
function stripTarget(raw) {
return raw.split("|")[0].split("#")[0].split("^")[0].trim();
}
function safeDecode(value) {
try {
return decodeURIComponent(value);
} catch {
return value;
}
}
function isExternal(target) {
return /^(https?:|mailto:|obsidian:|#|\/)/i.test(target);
}
function candidateKeys(target, fromFile) {
const clean = safeDecode(stripTarget(target));
if (!clean) return [];
const keys = new Set();
const normalized = toPosix(path.normalize(clean));
keys.add(normalized);
keys.add(withoutMd(normalized));
if (clean.includes("/") || clean.includes("\\")) {
const fromDir = path.dirname(toPosix(path.relative(vaultRoot, fromFile)));
const relative = toPosix(path.normalize(path.join(fromDir, clean)));
keys.add(relative);
keys.add(withoutMd(relative));
} else {
keys.add(withoutMd(path.posix.basename(normalized)));
keys.add(path.posix.basename(normalized));
}
return [...keys].filter(Boolean);
}
walk(vaultRoot);
const byPath = new Map();
const byBase = new Map();
for (const file of allFiles) {
const rel = toPosix(path.relative(vaultRoot, file));
const lowerRel = rel.toLowerCase();
byPath.set(lowerRel, file);
if (rel.toLowerCase().endsWith(".md")) byPath.set(withoutMd(lowerRel), file);
const base = rel.toLowerCase().endsWith(".md")
? withoutMd(path.posix.basename(rel)).toLowerCase()
: path.posix.basename(rel).toLowerCase();
const list = byBase.get(base) || [];
list.push(file);
byBase.set(base, list);
}
const problems = [];
const wikilink = /!?\[\[([^\]]+)\]\]/g;
const markdownLink = /!?\[[^\]]*\]\(([^)]+)\)/g;
for (const file of markdownFiles) {
const text = fs.readFileSync(file, "utf8");
const rel = toPosix(path.relative(vaultRoot, file));
const targets = [];
let match;
while ((match = wikilink.exec(text))) targets.push(match[1]);
while ((match = markdownLink.exec(text))) {
const target = match[1].replace(/^<|>$/g, "").trim();
if (!isExternal(target)) targets.push(target);
}
for (const target of targets) {
const clean = stripTarget(target);
if (!clean || isExternal(clean)) continue;
const keys = candidateKeys(clean, file);
const pathHit = keys.some((key) => byPath.has(key.toLowerCase()));
const baseHits = keys.flatMap((key) => byBase.get(path.posix.basename(key).toLowerCase()) || []);
if (!pathHit && baseHits.length === 0) {
problems.push(`${rel} -> missing [[${clean}]]`);
} else if (!pathHit && baseHits.length > 1) {
problems.push(`${rel} -> ambiguous [[${clean}]] (${baseHits.length} matches)`);
}
}
}
if (problems.length) {
console.error("发现坏掉/含糊的内链:");
for (const problem of problems) console.error(`- ${problem}`);
process.exit(1);
}
console.log(`OK: 已检查 ${vaultRoot} 下的 ${markdownFiles.length} 个 Markdown 文件`);
运行就这一行。
node scripts/audit-wikilinks.cjs .
链接全活着,就吐个 OK。有断的,就给你列出来:哪个文件的哪条链接死了,一目了然。AI 整理完立刻跑这一下,是我每天的收尾仪式。
另外,Obsidian 自身那套机制(Daily notes、Templates、Properties、内链)的准确规格,请去查Obsidian 官方帮助。交给 AI 之前,自己先把这艘母舰的规格摸清,就不至于下出些莫名其妙的指令。
我实际试下来的结果
用这套机制把自己的 Vault 跑了三个月。
最顶用的,果然还是“每日记录的交接”和“发布前的链接审计”这两样。一早让 AI 把前一天摘要一下,发动机明显热得快。“昨天的自己,原来卡在这儿了”,一眼就清楚,趁冲咖啡的工夫,脑子就切到今天的模式了。自从把链接审计嵌进流程,文章发出去之后再“啊,内链断了”而脸色发青的夜晚,归零了。拿数字说,审计前每月总有两三回带着断链就发出去,现在是零。
还有个没料到的副产品。有了“每天都让 AI 来碰”这个前提,我自己写笔记的方式也变了。一想到回头要给机器读,就自然而然会加上 status:,再潦草的笔记也会补一行交代上下文。本以为是在为 AI 整理,结果到头来读着最顺的,是人类的我自己。
反过来,最初一口气整理全 Vault 那回,明摆着是失败。AI 把旧笔记的意思猜过了头,标签和标题不减反增,更乱了。结论很简单:“许可范围划窄、模板做薄、最后用 Node 审计”,这三点守得越牢,就越顺。
有意思的是,半年前我打死也想不起来的、两年前那条命令,如今 5 秒就能摸到。AI 一点一点替我贴好的链接,我只管顺着走就行。笔记,是真的开始变成大脑了。
小结
“笔记自己长大”的真相,不是什么魔法。读取放宽、写入收窄、最后用机器核一遍。 不过是把这条天经地义的事,做成了机制而已。
要做的就三件:把文件夹分好,用 CLAUDE.md 写下规矩,用 .claude/settings.json 把危险操作物理封死。剩下就是别说“整理整理”,圈好范围再开口。今天先从 daily/ 一个文件夹起步。明天的自己,会轻松那么一点点。
想更细地搞懂权限和沙箱的思路,可以读 Claude Code 的审批与沙箱设计。能动手的模板、团队落地的咨询入口,都整理在 教程一览 里。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
让 Claude Code 真正进入可验证的工作流
先用免费 PDF 固定基础,再用 Gumroad 教材复用工作流;如果涉及团队导入、权限或收入路径,可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
怎么写指令,让 Claude Code 只改一个文件
从一句「改得更好一点」却被动了 40 行的翻车经历,总结出一套把改动范围、验证、回滚打包在一起的 Claude Code 请求模板。
Claude Code 权限拒绝后的恢复流程:不要削弱护栏
把 Claude Code 被拒绝的命令拆成拒绝原因、安全替代步骤、证据命令和重试条件,而不是立刻放宽权限。
Claude Code Harness Smoke Test:信任代理前的15分钟验证循环
用15分钟确认 Claude Code 的范围、禁止区域、验证命令、公开 URL 和收入 CTA。