Obsidianは、ローカルのMarkdownファイルを知識ベースとして活用できるノートアプリです。OSSではないですが、コミュニティによるプラグインの開発が活発で色々とカスタマイズできます。

「ローカルにすべてある」、「拡張可能性が高い」というところがLLMと組み合わせてテキストであれこれするのにとても相性がいいと思い使い始めました。

まだ使い始めて日が浅いんですが、今のところうまいことワークしており、NotebookLMとかはもはや使わなくなってしまいました。Obsidian x LLM周りのやってることを紹介したいと思います。

考え方

Obsidianは普通デイリーノートを取ったり日々のアイデアを書き留めてノート同士をリンクし、非線形な知識の構造化みたいなことを目指すのだと思いますが、私は自分だけが参照するために文章を書く習慣があまりないです。

Obsidianにはとにかく情報をぶち込みまくって、LLMの補助を受けながら解釈してアウトプットすることを目的に利用しています。

なのでグラフビューとか全く使ってないです。(たぶん邪道ではある、が満足してる)

情報収集: 「後で読む」にぶち込むと同時にAI要約する

Obsidian Web ClipperというChrome拡張で開いているwebページのコンテンツをObsidianにノートとしてぶち込むことができます。

そのまま使っても割といい感じにメインのコンテンツだけ切り出してmarkdown化してくれますが、Web Clipperには Interpreter 機能があり、これを使うとノートを作成する前にLLMによる処理を挟むことができます。

例えばこんな感じで記事を要約し、この記事を読んで取るべきNextActionを挙げてくれます。

(青っぽいcallout部分がAIが生成したテキストです)

後で読もうと思った記事が新規タブに溜まりがちでしたが、とりあえずweb clipperで要約付きのノートを作成しておいて、後でまとめて目を通すようになりました。

後で読むリストは、優先度と読んだフラグ付きで一覧化され、優先度の降順で表示されるようにしています。

web clipperの設定

Obsidian Web Clipperから拡張機能をインストールし、拡張機能の settings > Interpreter で任意のモデルを追加してAPIキーを入力します。

その後、 New template からテンプレートを作成し、Note contentを以下のようにします。

> [!abstract] Interpreter Note
> 
> {{"コンテンツを日本語で要約してください。\n- **共通ルール**\n  - 読者はベンチャーキャピタリストかつソフトウェア開発者\n  - 空白行やheading含むすべての行は `> ` で開始して引用であることを示す\n  - listで句点を利用せず、補足はインデントを付ける\n- **フォーマット**\n> ## Summary\n最大10個のbullet list(`- `)で箇条書きにより要約する。 \n> ## NextAction\n最大で3個のcheckbox(`- [ ] ` で出力する。"}}

{{content}}

スニペットは改行できなかったので \n で改行を表現している感じです。 {{content}} に実際に保存されるコンテンツがmarkdownで入るので、要約以外にも色々やれます。

リスト化の設定

Dataviewプラグインを使います。プラグインをインストールし、 _index などリストを表示したいページに以下のようにfrontmatter yamlとdataviewで実行したいjsのコードを書きます。

---
search: 
cssclasses:
  - table-wide
  - table-nowrap
  - table-tiny
  - row-alt
---

dataviewに実行させるには、jsの部分は以下のようにcodeblockで入力する必要があります。

```dataviewjs
const MAX = 64000
 
const q = dv.current().search || ""
const s = dv.current().file.folder
 
const d = dv.pages(`"${s}"`).file
  .filter(x => x.name.includes(q))
  .filter(x => x.name !== "_Index")
  .sort(x => x.mtime, "desc")
  .sort(x => {
    const priority = x.frontmatter.priority;
    if (priority === undefined || priority === null) return 1;
    const numPriority = Number(priority);
    return isNaN(numPriority) ? 1 : -numPriority;
  })
  .sort(x => x.frontmatter.read ? 1 : 0)
  .limit(100)
  .map(x => {
  return [
    x.frontmatter.read ? '✅' : '', 
    x.frontmatter.priority,
    x.link, 
    `<progress value=${x.size/MAX}></progress>`,
    x.mday.toLocaleString()
  ]})
  dv.table(["read", "priority", "", "size", "updated"], d)
`\`` <- バッククオートはエスケープです。消してください!

この例では日付で降順にしたあとpriorityでまた降順にし、readが true になっているものを最後に持っていっています。jsなので好きに実装可能です。

情報へのアクセス: CursorとObsidian Copilot

ObsidianのvaultはCursorなどのエディタで開けば単なるmarkdownファイルなので、Q&Aやプランニングなど、様々なことに活用できます。

例えば筋トレの計画を立てるときは、YouTubeでもブログでもなんでもいいのでweb clipperで参照できる情報をどんどん突っ込んで、LLMといっしょに目標達成の道筋を考えることができます。

.cursor/rules にディレクトリ構造など明示して育てていくのが良いと思います。

一応 Obsidian Copilot というプラグインもあり、vaultをindex化してchatしたり、事前に設定した機能(選択範囲の翻訳など)にインスタントにアクセスすることもできます。こんな感じに。

まあCursorで代替できるのであまり使ってないです。 設定手順は Obsidian Copilotのすゝめ:ノート活動を変えるかもしれない壁打ち相手 - Qiita で詳しく解説されています。

アウトプット: CursorとObsidianでブログを書く

このブログはObsidianで書いています。詳しい構築方法は Obsidian vaultの一部のディレクトリだけをQuartzで公開する で紹介しています。

上記までのプライベートな用途のvaultと同じvault内でブログ記事も管理しており、そうすることでLLMで相互に参照しやすくしています。

現状は、Cursorで記事の一部を書いてもらったり、記事のレビューをしてもらったりしているくらいですが、将来的には人間はレビューして承認するだけみたいな運用にしても良さそうです。(もちろん、ネットの海にゴミを増やすようなマネはしないようにケアしつつ)

まとめ

という感じに、情報のインプットからアウトプットまでをObsidianをハブにして運用しつつ、ほんのりLLMのサポートを受けているという感じです。

Notion MCPが公式から公開されましたが、このユースケースは代替できないと思います。(APIをガンガン叩かないといけなかったりなど)

なので移行とかはせずにどっちも使っていきます。