はじめに
最近はやりのObsidianで外部脳を作ろうというkarpathyさんのアイデアをちょっと違う形でAI Agent向けの外部脳を作ってみました。私は、ClaudeCodeがメインでOpenCalw、kiro、Antigravity、OpenCladeなど。。。節操なく使ておりり、各エージェント事にコンテキストがバラバラという課題がありまして、これをNAS+Obsidianで効率的に共有できないかと考えました。 私はRedmineでプロジェクト管理しているので、Redmineをベースに、Obsidian Vaultを全AIエージェント共通の外部記憶として整備するプロジェクト「redobrain」を始めました。
何を作ったのか
一言で言うと、Redmineに書いた情報を自動的にObsidian Vaultに取り込み、AIが読みやすい形に統合するパイプラインです。基本的にはOpenClawのSKILLSで、スクリプトを実行させたりマージはLLMにやらせてます。この仕組み自体、私がアイデアを出しClaudeCodeで作成したものです。
人間 → Redmineにチケットを書く
↓ (自動同期)
Sources/Redmine/ に1チケット1ファイルで保存
↓ (ルールベース分類)
classify-state.json に分類結果を記録
↓ (OpenClawが直接マージ)
Merged/ に統合ドキュメントとして出力
↑
他のAI Agentが ENTRY.md 経由で参照
人間がやることは「Redmineにチケットを書く」だけ。あとは全自動です。
設計原則:Sourcesが唯一の真実
このシステムの核となる設計原則は:
Sources が唯一の真実。Merged はビルド成果物。
プログラマーなら馴染みのある考え方ですね。ソースコードとビルド成果物の関係と同じです。
Sources/= ソースコード(Redmineチケット、手動投入ドキュメント)Merged/= ビルド成果物(AIが読む統合ドキュメント)- いつでも
Sources/からMerged/を再生成できる
これにより「マージ済みだからスキップ」という判断が不要になります。ルールが変わった、情報が更新された → 再生成すればいい。シンプルです。
2フェーズ・アーキテクチャ
Phase 1: Classify(ルールベース、LLM不要)
分類はLLMを使いません。純粋なルールベースです。
- Redmineチケットの
parent_idを辿ってルートチケットを特定 - ルートチケット = コアドキュメント(統合先)
- 子チケットは親のコアドキュメントに分類される
def _find_root(self, ticket_id, parent_map):
"""parent_idチェーンを辿ってルートを見つける(循環検出付き)"""
visited = set()
current = ticket_id
while current in parent_map and parent_map[current] is not None:
if current in visited:
break
visited.add(current)
current = parent_map[current]
return current
最初は分類もOpenClawにやらせようと思ったのですが、いまいちだったのでRedmineのプロジェクトをベースにClaudeCodeで先に仕分けルールを作らせました。
Phase 2: Merge(OpenClawが直接実行)
SKILLS.mdでスクリプト実行とその結果で判断させ、マージの仕方を指示しています。
## マージ作業(あなたが直接行う — スクリプト不要)
**重要**: マージは2フェーズに分けて行う。1回の処理を小さく保つこと。
### 「マージして」と言われたら即座にこれを実行する
**⚠️ 絶対に聞き返さない。追加情報を求めない。以下をそのまま実行する。**
何をマージするか、どこにマージするかは聞かなくてよい。classify コマンドが自動判定する。
```bash
# Step 1: 分類(自動)— 何をマージすべきか自動判定される
cd ~/.openclaw/workspace/skills/redobrain
set -a; source systemd/openclaw.env; set +a
python3 -m scripts.main --config /mnt/share/Obsidian/_openclaw/config.yaml classify
```
```bash
# Step 2: 次のマージ対象を確認 — これが「何をマージするか」の答え
python3 -m scripts.main --config /mnt/share/Obsidian/_openclaw/config.yaml next-merge
```
**Step 2 の出力を見て、そこに書かれた core_doc と sources に従って作業する。**
ユーザーに何も聞く必要はない。
Step 3以降はあなたが直接ファイルを読み書きして行う:
**⚠️ 1回のセッションで処理するのは1コアドキュメントのみ。**
```
Step 3: next-merge の出力を確認 → core_doc と sources 一覧を把握する
Step 4: その core_doc に属する Sources を1件ずつ読む(一度に全部読まない)
Step 5: 内容を理解し、コアドキュメントを作成・更新する
- 既存ファイルがあれば先に Archive に退避
cp /mnt/share/Obsidian/Merged/xxx.md /mnt/share/Obsidian/Archive/Merged/xxx_YYYY-MM-DD_HHmm.md
- /mnt/share/Obsidian/Merged/{category}/{name}.md に書き込む
Step 6: マージ完了したら mark-merged で記録する
python3 -m scripts.main --config /mnt/share/Obsidian/_openclaw/config.yaml mark-merged "Merged/xxx/yyy.md"
Step 7: Discord に完了を報告する(例:「Merged/Trading/daytrade-bot.md をマージしました」)
Step 8: /mnt/share/Obsidian/00-Entry/ENTRY.md を更新する
- 統合ドキュメント一覧のパスは Obsidian wiki-link で記載する
- 例: `[[Merged/Trading/daytrade-bot]]` (.md は省略)
- テーブル形式: `| タイトル | [[Merged/Trading/daytrade-bot]] | 概要 | 日付 |`
Step 9: /mnt/share/Obsidian/_openclaw/logs/YYYY-MM-DD.md にログを記録する
```
Vault構造
/mnt/share/Obsidian/
├── 00-Entry/
│ └── ENTRY.md ← 全AIエージェントの入口
├── Sources/
│ ├── Redmine/ ← チケットごとに1ファイル
│ └── Other/ ← 手動投入ドキュメント
├── Merged/ ← 統合ドキュメント(カテゴリ別)
│ ├── Trading/
│ ├── Projects/
│ ├── Infrastructure/
│ └── ...
├── Archive/
│ └── Merged/ ← 過去バージョン(自動退避)
└── _openclaw/
├── config.yaml
├── merge_rules.yaml ← 分類ルール定義
├── classify-state.json ← 分類結果キャッシュ
└── logs/
ポイントは 00-Entry/ENTRY.md の存在です。どのAIエージェントも、このファイルを1つ読めば全情報にアクセスできる。設定ファイルに1行追加するだけ:
プロジェクト情報は /mnt/share/Obsidian/00-Entry/ENTRY.md を参照。
実装の工夫
増分処理
毎回全チケットを再分類するのは無駄なので、classified_at と last_synced を比較して変更があったものだけ処理します。
# 増分処理: 前回分類済みで変更なしならスキップ
existing = sources.get(source_path)
if existing and existing.get("classified_at", "") >= last_synced:
continue
アーカイブ自動退避
マージ前に既存の Merged/ ファイルがあれば、自動的に Archive/ にタイムスタンプ付きでコピーします。git的な発想ですが、Obsidianのプレーンマークダウンという制約の中では十分実用的です。
ロックファイル
NAS上のVaultに複数プロセスが同時アクセスしないよう、シンプルなロックファイル機構を実装しています。タイムアウト付きで、デッドロックも防止。
技術スタック
- Python 3.11+ — パイプラインスクリプト
- OpenClaw — LLMエージェント基盤(Qwen3.6-35b-a3b on Ollama)
- Redmine — 情報の入力元(人間が書く場所)
- Obsidian — 情報の出力先(AIが読む場所)
- Discord — 承認フロー・通知
- NAS (SMB/NFS) — Vault の物理ストレージ(複数マシンからアクセス可能)
技術スタック
利用環境
- Windows 11 (Claude Code/kiro/Antigravity) 普段使うPC
- Ubuntu Linux 24.04(Openclaw/Claude Code/kiro-cli) Openclawマシン
- Mac mini(まだ届いてない(笑))
現在の稼働状況
- Redmine sync: 稼働中(329チケット同期済み)
- Classify: 稼働中(273ソース分類済み → 157コアドキュメント)
- Merge: OpenClawによる実行が進行中
- systemdタイマーで15分ごとに自動実行
なぜObsidianなのか
「なぜNotionやConfluenceではなくObsidianか?」という疑問があるかもしれません。理由は明確です:
- プレーンマークダウン — APIもDBも不要。ファイルを読むだけ
- ローカルファイルシステム — AIエージェントが直接アクセスできる
- NASマウント — 複数マシン(Windows/Linux/Mac)から同じVaultにアクセス
- Obsidianのwiki-link — ドキュメント間のリンクが簡潔に書ける
- 人間も読める — Obsidianアプリで普通にブラウズ・編集できる
AIエージェントにとって最も低摩擦なインターフェースは「ファイルを読む」こと。それ以上でもそれ以下でもない。
今後の展望
- マージ品質の改善(現在はOpenClawの出力をそのまま使っているが、フォーマットの一貫性にばらつきがある)
- 定期的な全再マージ(ルール変更時に一括再生成)
- 他のAIエージェント(Claude Code、Kiro等)からの参照実績を積む
- Sources/Other/ への手動投入ワークフローの整備
まとめ
redobrainは「AIエージェントに長期記憶を持たせる」という課題に対する、実用的な解答です。
設計のポイントは:
- 人間はRedmineに書くだけ(既存ワークフローを変えない)
- 分類はルールベース(LLMの気まぐれに依存しない)
- 統合はLLMが直接実行(エージェントの強みを活かす)
- 出力はプレーンマークダウン(どのAIからも読める)
ぶっちゃけ、これClaude Codeに課金してやらせたら簡単に終わると思います。それをケチって(いや、実験として)OpenClaw + Ollamaで実行させるためには、JOBを細かく切るとかちょっとお馬鹿でも実行できるようにするとか一部、スクリプトを作るとかってことをしてる訳ですね。まぁ、不毛っちゃ不毛です(笑)
環境: OpenClaw v2026.5.4 / Ollama 0.20.5 / Qwen3.6-35b-a3b / RTX 3060 12GB / Ryzen 5600X / RAM 32GB / Obsidian on NAS (SMB)