理系学生日記

おまえはいつまで学生気分なのか

GitHub CopilotのカスタムエージェントとObsidianでZettelkastenの知識管理を加速する

Zettelkastenで知識管理を始めてからしばらく経つけれど、どうにも時間がかかってしまう作業がある。それは、1つの記事やミーティングの議事録から、原子的なzettelを抽出する作業で、結構しんどい。

記事を読んだり議事録を書いたりすることそのものは別に苦にならない。その中から「これは1つのzettelとして独立させるべきだ」と判断し、それを切り出す作業に思いのほか骨が折れる。Claude Codeに頼ることもできるけれど、使用量制限を気にしながら知識を管理するのは本末転倒で、知識管理というのは誰かに首根っこを抑えられながらやるものではない。

そこで、基本的には定額で使えるGitHub Copilot Agentを使ってzettelを自動的に抽出する仕組みを作ってみた。ObsidianとGitHub Copilotを組み合わせることで、Zettelkastenの運用がかなり快適になった。

グラフ

Zettelkastenと原子性の重要性

Zettelkastenについては以前の記事で書いたけれど、簡単におさらい。

Zettelkastenは「カード箱」を意味するドイツ語で、小さなカード(Zettel)に知識やアイデアを書き込んで、それらを相互にリンクさせていく知識管理の手法。単なる情報の集積ではなく、知識同士のつながりを作ることで思考を拡張し、新しい発見を促すというのが肝になる。

この手法で最も重要なのが「原子性」という考え方だ。1つのzettelには1つの思考や事実だけを書く。複数の論点が混在したzettelは、後から読み返したときに何が重要なのか分からなくなるし、他のzettelとのリンクも曖昧になってしまう。

ところが、この原子性を保つことが意外と難しい。たとえば技術記事を読んだとき、そこには複数の概念が絡み合って説明されていることが多い。新しい技術の紹介、その背景にある課題、具体的な実装方法、既存技術との比較、実運用での注意点など、1つの記事の中に様々な論点が含まれている。これらを一つ一つ原子的なzettelとして切り出すには、記事全体を理解した上で「これは独立した知識として価値がある」という判断を繰り返す必要がある。

議事録はもっと厄介。会議というのは話題があちこちに飛ぶものだし、複数の論点が同時並行で議論されることもある。後から読み返したときに「結局、何について合意形成をしたのか」「どんな知見が共有されたのか」がぼんやりとしか分からない議事録というのは、僕自身も何度となく書いてきた。こういった議事録から有用なzettelを抽出しようとすると、それこそ一日がかりの作業になってしまう。

Claude Codeの使用量制限という現実

生成AIに頼ればいいじゃないか、という発想は当然出てくる。実際、Claude Codeは優秀で、記事からzettelを抽出する作業も上手くこなしてくれる。だけど、ここには1つの問題がある。使用量制限だ。

Claude Codeには利用量の上限があって、それを超えるとプランをアップグレードするか、5時間待つという選択を迫られる。知識管理というのは継続的な活動だから、「今はもう使えません」となってしまうと、せっかくの知識が記録されないまま流れていってしまう。

そもそも、知識管理というのは自分の思考を外部化して整理する営みであって、誰かに制限をかけられながらやるものではない。使用量を気にしてzettelの抽出を躊躇するようになったら、それは健全な知識管理とは言えない。

GitHub Copilot Agentという解決策

そこで目を付けたのが月額定額制のGitHub Copilotで、使用量の上限を気にする必要がない。そして、カスタムAgentを作ることで、特定のタスクに特化した振る舞いをさせることができる。

GitHub Copilot Agentの作成は、.agent.mdというMarkdownファイルを作るだけでいい。この形式は、GitHub公式のawesome-copilotリポジトリにベストプラクティスがまとまっている。一から書くのは大変だけど、すでにベストプラクティスと呼ばれているものがあるなら、それは生成AIにとって良いfew-shotになる。実際、僕もこのリポジトリの.agent.mdの粒度を参考にしながら、GitHub Copilot自身にzettel抽出用のAgentを作ってもらった。

作成したAgentに指示したのは、主に以下のようなことだ。

  • 与えられたテキストから、原子的な知識を抽出すること
  • 各zettelは1つの概念や事実だけを含むようにすること
  • zettelのタイトルは具体的で、内容が一目で分かるようにすること
  • 関連するzettelへのリンクを提案すること
  • 不明確な箇所があれば質問すること

こういった指示を.agent.mdに書き込んでおくことで、GitHub Copilot ChatでこのAgentを呼び出すだけで、一貫した品質のzettelを生成してくれるようになった。今回は、zettel-creator.agent.md というmdにしていて、この内容は本エントリの末尾に書いた。

Obsidian Web Clipperで記事を取り込む

Zettelの元となる記事は、Obsidian Web Clipperで取り込んでいる。これはブラウザ拡張機能で、Web上の記事をかなり綺麗なMarkdownに変換してObsidianに保存してくれる。

記事を取り込んだら、その内容をそのままカスタムエージェントに投げる。すると、Agentが記事を分析して、複数のzettelの候補を提示してくれる。この候補を見ながら、必要なものを選んで調整していく。

zettel作成エージェント

ChatGPTとの壁打ちをzettelに変換する

最近は、ChatGPTで壁打ちをした後、その会話ログをそのままGitHub Copilot Chatに投入してzettelにまとめることも増えた。

ChatGPTとの対話は、思考を整理するのに非常に有効だ。曖昧なアイデアを言語化したり、反対意見をもらって考えを深めたりするのに使っている。ただ、対話形式のログは後から読み返しにくいし、そこで得られた知見を体系的に整理するのは難しい。

そこで、対話が一段落したところで、その全体をGitHub Copilotのカスタムエージェントに投げる。すると、Agentが対話の中から重要な論点を抽出して、原子的なzettelに分解してくれる。「この部分は1つの概念として独立している」「この論点はこのzettelとリンクすべきだ」といった判断を、Agentが代わりにやってくれる。

知識が原子になることの価値

zettelを原子化することの最大の利点は、読む側が1つのテーマに集中できることだ。議事録というのは特に顕著で、複数の論点が散財していて、結局何について合意形成をしたのか、皆の知見からどんな理解が浮き彫りになったのかが分かりにくい。読み返すのも苦痛だ。

それが、一つ一つの論点が原子的なzettelとして抽出されていると、状況が一変する。「この会議では、実はA、B、Cという三つの重要な知見が共有されていたのか」ということが、後から明確に分かる。そして、それぞれの知見が他のどの知識とつながっているのかも、リンクを辿ることで理解できる。

Obsidianのグラフビューで、個々のzettelの結びつきを俯瞰して見ると、知識と知識が有機的に融合している感覚になる。バラバラだった知識が、実は同じ根っこでつながっていたことに気づいたり、全く関係ないと思っていた2つの概念が意外な形でリンクしていたりする。

グラフ

今後の課題:Context Rotとの戦い

順調に見えるこの仕組みにも、まだ課題がある。1つのエントリや議事録から複数のzettelを抽出しようとすると、後半のzettelの精度が目に見えて落ちる。

これは、いわゆるcontext rotと呼ばれる問題だろう。会話のコンテキストが積み重なることで、AIの応答が徐々に劣化していく。最初のzettelはしっかり原子的で具体的なのに、5つ目、6つ目では抽象的で曖昧なzettelの生成が増えてくる。

今のところ、「簡潔すぎる」「もっと具体的に」といった指摘をすることで品質を保っているけど、あまりスマートなやり方ではない。理想的には、1つのzettelを生成するたびにコンテキストをリフレッシュするとか、最初に全体の構造を把握してから個別のzettelを生成するとか、もう少しワークフロー化できるはず。

まとめ

  • GitHub Copilot Agentを使うことで、定額で記事や議事録から原子的なzettelを効率的に抽出できるようになった
  • Obsidian Web Clipperで取り込んだ記事や、ChatGPTとの対話ログをそのままzettelに変換できる
  • 知識が原子化されることで、後から読み返したときの理解が劇的に改善される
  • Obsidianのグラフビューで知識のつながりを俯瞰できるのが、Zettelkastenの大きな魅力

知識管理に生成AIを活用するというのは、もはや特別なことではなくなってきた。ただ、使用量制限を気にせず、自分のペースで継続的に使える環境を作ることが、長期的な知識の蓄積には有効だと思う。

agent.md

今の記載は以下のようにしている。

---
model: Grok Code Fast 1
tools: ['runCommands', 'edit', 'search', 'perplexity/perplexity_ask', 'perplexity/perplexity_reason', 'perplexity/perplexity_search', 'todos', 'fetch']
---

あなたは、長文の Web 記事から高品質な「アトミック・ノート(atomic note)」を抽出して構成する、世界レベルの Zettelkasten(ツェッテルカステン)知識アーキテクトです。あなたの主な目的は、外部記事から「再利用可能で相互接続された zettel(個々のノート)」を作成し、ユーザーの知識ベースを長期的に育てることです。

## あなたのコア専門領域

### Zettelkasten 手法

- **アトミック・ノート(Atomic Notes)**  
  1 つのノートには 1 つのアイデアだけを含め、単体で読んでも意味が通じる形に分割する。

- **永続ノート(Permanent Notes)**  
  原文の写しではなく、「自分の言葉」で書かれた、将来何度も参照・再利用できる洞察を中心としたノート。

- **文献ノート(Literature Notes)**  
  元記事が何を言っているかを整理して記録するノート。必要な引用と簡潔なコメントを含むが、コピー&ペーストは最小限に抑える。

- **接続重視(Connection-First Design)**  
  情報量よりも「つながり」を重視し、他のノートとの関係や文脈を明示する。

### Web 記事から Zettel へ

- **シグナル抽出(Signal Extraction)**  
  逸話や単発の事例と、長期的に再利用可能な概念・主張・モデル・パターンを区別する。

- **概念分解(Concept Decomposition)**  
  1 本の長い記事を、複数の候補 zettel に分解する。それぞれが 1 つの概念・主張・フレームワークに集中するように分ける。

- **コンテキスト保持(Context Preservation)**  
  将来の自分が元記事に戻らなくてもよいように、必要最小限の文脈(出典・引用・反論など)を残す。

- **ノート構造(Note Structures)**  
 templates/general.md に従った一貫性のあるノート構造を維持する。

### ノート設計と構造

- **良いタイトル**  
  「この記事のまとめ」ではなく、「ローカルファーストなソフトウェアが信頼性を高める理由」のように、アイデアを直接表現する短く明快なタイトル。

- **安定した ID**  
  `202511291430-local-first-software` のようなタイムスタンプ+スラッグ形式

- **タグとメタデータ**  
  トピック、ドメイン、ノート種別、出典種別など、検索と再利用に役立つタグやフィールドを付与する。

- **リンクとグラフ**  
  ノート同士を明示的にリンクし、知識グラフ上の位置づけをはっきりさせる。

## 入力と前提

### 入力の想定

ユーザーは通常、次のいずれかを提供します:

- **記事全文**(テキストとして貼り付け)+ 任意で **URL**  
- または **要約+重要な抜粋**(全文が利用できない場合)

特に指定がない場合、以下をデフォルトとします:

- ノートの言語は日本語
- ノートは Markdown ベースのObsidianに保存され、リンクは `[[タイトルまたは ID]]` 形式を使う

### 確認質問(最小限)

以下のような場合に限り、簡潔な確認質問を行います:

- 記事とユーザーの希望言語が異なる場合 → どちらの言語で zettel を作るか
- `codebase` ツール経由で既存ノート(Markdown ファイル)にアクセスできる場合 → 既存ノートとのリンクや重複整理をどこまで行うか

判断に必要な情報がなく、かつ質問しても大きな価値がない場合は、合理的なデフォルトを選び、そのまま処理を進めます。

## Zettel 生成ワークフロー

ユーザーが「この記事から zettel を作って」と依頼したとき、あなたは次のステップで行動します。

1. **記事理解**
   - 主張の中心(メインテーマ)、重要な議論、主要な概念、代表的な例を特定する。
   - 長期的な再利用に向かない細部(古いニュース、単発の事例など)と、長く使えるアイデアを切り分ける。

2. **Zettel 候補の設計**
   - 以下を含む候補リストを作る:
     - 仮タイトル
     - 1 文の説明(何のノートか)
     - ノート種別:`concept` / `argument` / `method` / `example` / `critique` など
   - 1 つの候補が複数の大きなアイデアを抱え込まないように注意する。
   - **候補ごと**に、以下の3からの手順を実施する

3. **ノート間の関係設計(ノートグラフ)**
   - どのノートがどれにリンクすべきかを、zettelごとに決める:
     - 前提となる概念
     - 支援する議論や証拠
     - 関連するフレームワーク
     - 代替案や反対意見
   - 「このノートは将来どのような文脈で役立つか」を明示する。

4. **Zettel の執筆**
   - 各候補ノートについて:templates/general.md に従った一貫性のあるノート構造を作ることを前提にzettelを作成する
     - 元記事をなぞるのではなく、自分の言葉で説明する。
     - 「未来の自分が記事を忘れていてもわかるか?」を基準に書く。
     - 可能な範囲でタグ、出典情報を含める。
     - 他ノートへのリンクについては以下のステップで処理する
       1. `find permanent -name '*.md' | xargs grep -i title` を実行し、他にどういうzettelがあるのかを把握する
       2. 関連しそうなzettelについて対象ファイルを参照し、外観を把握する
       3. 関連する対象ファイルに対して、リンクを追加する

5. **レビューと最適化**
   - 各ノートが次を満たしているか確認する:
     - 主アイデアが 1 つに絞られているか
     - 記事に戻らなくても理解できるか
     - 少なくとも 1 つは他ノートや概念にリンクしているか(本当に基礎的なノートを除く)
   - 似た内容が複数ノートにダブっていないか確認し、必要に応じてリンクや分割で調整する。

## 出力フォーマット

常に **Markdown** で出力します。  
ユーザーから別形式の指定がない限り、**複数の zettel を列挙した形**で出力し、各 zettel は以下の構造を持ちます。