ObsidianのメモがAIで“勝手に育つ”。第二の脳をつくる仕組み
バラバラなObsidianのメモをAIに読ませて、リンク付け・要約・整理を半自動化する方法。書き込みは慎重に、読み取り中心で“勝手に育つVault”をつくる実体験。
夜中の0時、僕はObsidianの検索窓に「あのコマンド、なんだっけ」と打ち込んでいました。
2年前にメモした、たった3行のシェルコマンド。あるのは確かなんです。でも500個を超えたノートのどこに埋まっているのか、まったく思い出せない。結局その日は探すのを諦めて、もう一度ググりました。
これ、僕だけじゃないと思うんです。
Obsidian(メモアプリ)って、使えば使うほど便利になる。でも同時に、確実に散らかる。日次ログ、読書メモ、コード断片、記事ネタ、会議メモ。全部Markdownのファイルとして溜まっていって、半年もすると「自分専用の、検索しづらいゴミ屋敷」になります。
そこで僕がやり始めたのが、Vault(メモの置き場)をAIに読ませて、整理を半分くらい肩代わりしてもらうこと。リンクを貼り、要約をつくり、迷子のメモを拾い上げる。これを毎日ちょっとずつ回すと、バラバラだったメモが勝手に繋がりはじめて、本当に「第二の脳」っぽくなってきたんです。今日はその話をします。
そもそも「メモが育つ」ってどういうこと?
普通のメモは、書いた瞬間がピークです。あとは忘れられていくだけ。
でもObsidianには [[ノート名]] という書き方でノート同士を繋ぐ機能があって(Wikilinkといいます)、繋げば繋ぐほど一枚の地図みたいになっていく。「TypeScriptの型エラー」のメモから「あの日ハマったDockerの話」へ飛べて、そこから「先月の障害対応の振り返り」へ繋がる。点が線になって、線が面になる感覚です。
問題は、この繋ぎ込みを人間がやると、面倒すぎて続かないこと。
ここをAIに任せます。具体的には、相棒としてClaude Codeというツールを使います。これはコードを書くためのAIなんですが、要は「Markdownファイルが詰まったフォルダを、安全に読み書きできる作業係」として使えるんですね。Obsidianのローカルファースト(自分のPCにファイルが置かれる)な良さはそのまま、整理の手間だけAIに渡す。これが今日の作戦です。
ただし、ひとつだけ最初に釘を刺させてください。Vault全体にAIの編集権限を渡すのは、絶対にやめたほうがいい。
.obsidian/(設定フォルダ)も、公開済みの記事も、契約書みたいな個人メモも、APIキーも、AIに読ませる理由はありません。だから僕は「読み取りは広めに、書き込みは超慎重に」という方針でやっています。これは前に書いたAIに仕事を任せる“足場”の作り方の考え方そのままで、要は補助輪をつけてから走らせる、という話です。
こんな場面で効く(3つ)
抽象論だと伝わらないので、僕が実際に「お、効くな」と感じた瞬間を3つ。
1つ目は、朝の日次ログ。 毎朝、前日のノートをAIに読ませて「終わってないタスクだけ今日に移して、昨日の学びを3行に圧縮して」と頼みます。すると、昨日の自分が散らかしたメモが、今日の自分が動ける形に整って出てくる。「ああ、これ昨日詰まってたやつだ」と一瞬で思い出せる。引き継ぎの相手が、未来の自分なんです。
2つ目は、コード断片の救出。
さっきの「2年前のコマンド」問題。snippets/ フォルダに動いたコマンドを放り込んでおくと、AIが「これ、何のためのコマンド?」という説明文と、関連する他のメモへのリンクを勝手に足してくれる。裸のコマンドが、検索で見つかる“ちゃんとしたメモ”に化けます。
3つ目は、記事ネタの仕込み。
ブログを書く日、content-ops/ フォルダのネタ帳をAIに見せて「この記事、どの過去記事に内部リンクできそう?」と聞く。自分でも忘れていた半年前の記事を引っ張ってきてくれることがあって、これが地味に効く。点と点が繋がる、あの瞬間です。
僕がやらかした失敗3つ
ここからが本題かもしれません。最初の数週間、僕のVaultはAIに荒らされまくりました。正直に晒します。
ひとつ目。いきなりVault全体を「整理して」と頼んだ。 これが一番ひどかった。AIは2年前の意味不明なメモまで「親切に」整理しようとして、勝手なタグと見出しを大量に生やしたんです。Graph view(メモの繋がりを可視化する画面)が、知らないタグだらけのジャングルになりました。古いメモの意図なんてAIには分からない。なのに推測で動く。あれ以来、対象は必ず1フォルダだけに絞っています。
ふたつ目。ノート名をAIに勝手に変えさせた。
「タイトル、分かりやすくしといて」。これで [[旧ノート名]] のリンクが一斉に切れました。Obsidianは自分で名前を変えればリンクも追従してくれるんですが、外部のAIが一括でファイル名を書き換えると、その追従が効かない。リンク切れの死屍累々。今は「リネームは必ず人間に確認」を鉄の掟にしています。
みっつ目。private/ を読ませてしまった。
これはヒヤッとどころじゃなかった。契約金額のメモが入ったフォルダを、権限設定をサボったせいでAIが読める状態にしていたんです。事故は起きませんでしたが、本番のDBを新人に素手で触らせていたようなもの。deny(拒否リスト)にちゃんと書いていれば、そもそも事故りようがない。設定をケチった自分が悪い、という教訓です。
始め方:3つのファイルだけ置く
難しくありません。Vaultの直下に、3つ用意するだけです。
まず、フォルダを分けます。最初から細かく分類しすぎると必ず破綻するので、ざっくりで十分。
# Vaultの直下で実行。毎日使う場所・プロジェクト・公開作業・保護領域だけ分ける
mkdir -p inbox daily projects content-ops snippets templates scripts archive private
各フォルダの役割と、AIにどこまで任せるかはこんな割り振りにしています。
| フォルダ | 役割 | AIに任せる範囲 |
|---|---|---|
inbox/ | 未整理メモ、Webクリップの受け皿 | 読み取りと新規作成 |
daily/ | 日次ログ、作業メモ | 作成・追記・前日の要約 |
projects/ | 進行中タスク、引き継ぎ | 作成・更新・未決事項の整理 |
content-ops/ | 記事案、内部リンク、公開チェック | 下書き整理・リンク確認 |
snippets/ | コード断片と使い方 | 説明追加・タグ整理 |
templates/ | Obsidianテンプレート | 原則は確認してから編集 |
archive/ | 完了・保管済み | 編集禁止 |
private/ | 個人情報・契約・秘密 | 読み取りも禁止 |
次に、Vault直下に CLAUDE.md を置きます。これはAIへの「うちのルール」を書いた紙です。長い理念を語るより、守ってほしい入出力ルールを短く書くほうが効きます。
# Obsidian Vault のルール
## 役割
- このVaultは日次ログ・プロジェクト引き継ぎ・コード断片・記事案を置く場所。
- privateを読まなくても役立つように動くこと。
## フォルダの方針
- `daily/`: `YYYY-MM-DD.md` で日次ノートを作成・更新する。
- `projects/`: アクティブな案件ごとに引き継ぎノートを1枚維持する。
- `snippets/`: 動くコマンドと、その背景・失敗例をセットで残す。
- `templates/`: 読むのは自由。編集する前に必ず聞く。
- `archive/` と `private/`: 編集しない。privateの中身は要約もしない。
## 書き方のルール
- 内部リンクは `[[プロジェクト名]]` のWikilink形式で書く。
- ノート先頭にYAMLプロパティ(status等)を付ける。
- 1段落は5行以内に収める。
## 安全のルール
- 既存ノートのリネームは、必ず先に確認する。
- `.obsidian/` の設定は書き換えない。
- 一括編集の前に、対象ファイルを一覧で出して承認を待つ。
- 編集後は必ず `node scripts/audit-wikilinks.cjs .` を走らせる。
最後が一番大事。.claude/settings.json で権限を物理的に縛ります。CLAUDE.md は「お願い」ですが、こっちは「物理ロック」。失敗談の3つ目を二度と繰り返さないための門番です。読み取りは広め、書き込みは作業フォルダだけ、危険な操作は 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 *)"
]
}
}
この3枚を置いたら、あとは頼むだけ。コツは「いい感じに整理して」と言わないこと。範囲・成果物・禁止事項・検証まで、毎回ぜんぶ指定します。
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} の Markdown ${markdownFiles.length} 件を確認しました`);
実行はこれだけ。
node scripts/audit-wikilinks.cjs .
リンクが全部生きていれば OK が出る。切れていれば、どのファイルのどのリンクが死んでいるか一覧で教えてくれる。AIが整理した直後にこれを走らせるのが、僕の毎日のシメです。
なお、Obsidian側のしくみ(Daily notes、Templates、Properties、内部リンク)の正確な仕様はObsidian公式ヘルプに当たってください。AIに任せる前に、自分が母艦の仕様を分かっておくと、変な指示を出さずに済みます。
実際に試した結果
3ヶ月、この仕組みで自分のVaultを回してみました。
一番効いたのは、やっぱり「日次ログの引き継ぎ」と「公開前のリンク監査」でした。朝イチでAIに前日を要約させると、エンジンのかかりが明らかに速い。「昨日の自分、ここで止まってたのか」が一目で分かるから、コーヒーを淹れている間に頭が今日のモードに切り替わる。リンク監査を挟むようになってからは、記事を公開したあとに「あ、内部リンク切れてた」と青ざめる夜がゼロになりました。数字で言うと、監査前は月に2〜3回はリンク切れを公開していたのが、今はゼロです。
もうひとつ、思わぬ副産物がありました。AIに毎日触らせるという前提ができたことで、僕自身のメモの書き方が変わったんです。後で機械に読ませると思うと、自然と status: を付けたり、雑なメモでも一行だけ文脈を足したりするようになる。AIのために整えていたつもりが、結局いちばん読みやすくなったのは人間の自分でした。
逆に、最初に全Vaultを一気に整理させた回は、はっきり失敗でした。古いメモの意味をAIが推測しすぎて、タグと見出しがむしろ増えて散らかった。結論はシンプルで、「許可範囲は狭く・テンプレートは薄く・最後にNode監査」の3点を守るほど、うまくいく。
面白いのは、半年前なら絶対に思い出せなかった2年前のあのコマンドに、今は5秒で辿り着けることです。AIがコツコツ貼ってくれたリンクを、僕がただ辿るだけ。メモが、ちゃんと脳になってきました。
まとめ
「メモが勝手に育つ」の正体は、魔法じゃありません。読み取りは広く、書き込みは狭く、最後に機械で検算する。 この当たり前を仕組みにしただけです。
やることは3つ。フォルダを分けて、CLAUDE.md でルールを書いて、.claude/settings.json で危ない操作を物理的に塞ぐ。あとは「いい感じに」と言わず、範囲を絞って頼むだけ。今日はまず daily/ ひとつから始めてみてください。明日の自分が、ちょっと楽になります。
権限とサンドボックスの考え方をもっと詳しく知りたい人はClaude Codeの承認・サンドボックス設計もどうぞ。手を動かすテンプレートや、チーム導入の相談先は教材一覧にまとめてあります。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Code権限セーフティラダー: 初心者がallowを広げる順番
Claude Codeの権限をread-onlyからbuild、限定編集、deploy確認まで段階的に広げる安全な運用手順。
Claude Code Small PR Proof Pack: 小さなPRをレビュー可能にする証拠セット
Claude Codeの小さなPRに、差分・検証・公開URL・CTA・rollbackを添える実務チェックリスト。
Claude Codeのコミット前レビューゲート: 差分、テスト、CTAをまとめて止める型
Claude Codeでcommit前に差分をレビューする実践手順。build、公開URL、CTA、Gumroadリンク、未翻訳本文を検知します。