技術 約9分で読めます

WUPHFのKarpathy流LLM wikiはエージェント記憶をMarkdownとGitに戻す

いけさん目次

Hacker Newsで WUPHF が伸びていた。 「Show HN: A Karpathy-style LLM wiki your agents maintain (Markdown and Git)」というタイトルで、235ポイント、110コメント。

WUPHF自体は「AI社員向けSlack」みたいなローカル実行のオフィスUIだ。 Claude Code、Codex、OpenClawを同じチャンネルに並べ、ブローカーが必要なエージェントを起こし、Web UIでやり取りを見せる。 ただHNで食いつかれていたのはチャットUIではなく、エージェントが仕事をするたびに生まれるデータ、つまり作業ログ、判断根拠、調べて分かった事実、ユーザーの好みをどう残して、どう探して、どう腐らせないかという共有記憶の設計だった。

かなチャットv2のHeartbeatメモリでは、1人のユーザーと1体のエージェントの間で、会話からプロフィール・今日の活動・タスクシグナルの3カテゴリを抽出してジョブのコンテキストに渡す仕組みを作った。 あれは蓄積項目に上限がある小さな記憶だ。 WUPHFはそれをチーム規模の共有wikiに拡張して、ClawsとCordの記事で触れたオーケストレーション層の「永続性」をMarkdownとGitという枯れた道具で組み立てている。

notebookからwikiへの昇格

WUPHFでは各エージェントが自分専用のnotebookを持ち、チーム全体でwikiを共有する。 READMEの「Memory: Notebooks and the Wiki」にある構造はこうなっている。

flowchart TD
    A["エージェントのnotebook<br/>作業中の観察や仮説"] --> B{"残す価値がある?"}
    B -->|Yes| C["wikiへ昇格"]
    C --> D["Markdown brief<br/>人間が読む記事"]
    C --> E["JSONL fact log<br/>append-onlyな事実列"]
    D --> F[("Git repo<br/>wuphf/wiki")]
    E --> F
    F --> G["SQLite<br/>構造化インデックス"]
    F --> H["Bleve<br/>BM25検索"]
    G --> I["lookup<br/>引用付き回答"]
    H --> I
    I --> J["他のエージェントが参照"]

エージェントはまずnotebookに作業中の文脈、観察、仮の結論を書く。 そこから繰り返し使えるplaybook、検証済みのfact、確認済みの嗜好のような長持ちする情報だけをwikiに昇格する。 READMEは「Nothing is promoted automatically」と明記している。

この昇格が自動ではない点が一番よかった。 かなチャットv2のHeartbeatは、Haikuが直近60件のユーザー発言から自動的にprofile・today・task_signalsを抽出する仕組みだ。 1対1の個人ツールなら自動抽出で回っている。 ただチーム規模の共有wikiに自動でfactを流し込んだら、「garbage facts in, garbage briefs out」になる。 HNコメントでもここは突かれていて、capture layerとpromotion layerを分け、trusted statusに上げる前に人間レビューか複数エージェントの収束を待つべきだ、という意見があった。

「何を残して何を捨てるか」はエージェント記憶の中心的な問題で、規模に関わらず出てくる。 このブログのCLAUDE.mdも同じ発想でMarkdownをGitに置いてエージェントの記憶にしているが、1ファイルはすぐ肥大化する。 WUPHFはwiki構造とfact log、インデックスでその限界を超えようとしている。

Markdownが正本

wikiの実体は ~/.wuphf/wiki/ に置かれるローカルGitリポジトリだ。 新規インストールでは markdown バックエンドがデフォルトで、catgrepgit loggit clone がそのまま使える。

wikiの中身はMarkdownのbriefとJSONLのfact logで、SQLiteとBleveがその上にインデックスを張る。 SQLiteやBleveは正本ではない。 docs/specs/WIKI-SCHEMA.md には、rm -rf .wuphf/index/ して再起動するとMarkdownからSQLiteとBleveを再構築でき、論理的に同じ結果になるべきだと書かれている。 検索インデックスはキャッシュで、正本はGit管理されたMarkdownとJSONLのfact logにある。

この割り切りは地味に大きい。 エージェント記憶システムは「どのベクトルDBに入っているか」「どのセッションIDに紐づくか」が実体になりがちだ。 WUPHFでは壊れたらインデックスを捨てて作り直す。 履歴を追いたければ git log。 フォークしたければGit repoごと持ち出す。

CLAUDE.mdを分離しても読まれない問題で経験した通り、Markdownを分割して増やしていくとエージェントは必要な情報を見つけられなくなる。 WUPHFはSQLiteとBleveのインデックスがそこを引き受ける。 インデックスが壊れたらMarkdownから作り直せばいいので、ファイルの分散とインデックスの集約が両立する。

Cloudflare Agent MemoryはDurable Objects、Vectorize、Workers AIでマネージドな記憶層を作っていた。 Cloudflare自身もAgents Week最終日にArtifactsを発表し、エージェント向けのGit互換ストレージを作っている。 WUPHFは逆で、最終的な信頼境界をファイルとGitに寄せている。 ArtifactsはDurable Objects上のクラウドマネージドだが、WUPHFはローカルの素のGitリポジトリだ。 プラットフォームに記憶を預けるか、エージェントが書いた記憶を普通のリポジトリとして監査するかの違いになる。

BM25を先に置く

HNではBM25-firstの設計にも反応があった。 「ほとんどのチームは測る前にvector DBへ飛びつく」というコメントがあり、分かる。

LLM wikiの検索で何でもベクトル検索に流せばいいわけではない。 「Acmeの請求先担当者」「pricing policy」「deployment checklist」のような短いlookupは、語彙が合っていればBM25が速くて強い。 逆に「先月の議論を踏まえると、この顧客で危ない前提は何か」のような問いは単語一致では足りず、引用付き合成が要る。

WUPHFのREADMEには /lookup のcited-answer retrievalがあり、SQLiteとBleveの再構築契約がschemaに書かれている。 短い検索と引用付き回答を同じ「検索」として潰さず、軽い経路と重い経路を分けようとしている。 Compresr Context Gatewayのtool discoveryと発想が近い。 エージェントに全部の道具と文脈を渡すとトークンも判断も膨らむから、短い問い合わせは短い経路で返し、長い合成だけ高い経路に送る。

PageIndexもベクトルDBなしでLLMの推論だけで文書ツリーインデックスを構築していた。 MintlifyはRAGを捨てて仮想ファイルシステムChromaFsに切り替え、ChromaDBの上にUNIXコマンド風のインターフェースを被せてgrepcatで文書を引く。 ただWUPHFの場合、wikiの記事構造がはっきりしているからBM25で足りるという前提がある。 非構造な文書を大量に放り込むケースとは条件が違う。

Wikipedia UIで記憶を見える化する

DESIGN-WIKI.md は癖が強い。 WUPHF wikiの見た目を「Wikipedia but for my company」として設計していて、serif本文、hatnote、infobox、TOC、Sources、Categories、page footerまでWikipediaの情報設計に寄せている。

レトロ趣味ではなく、エージェントが書いたものを「チャットログ」ではなく「参照資料」として読ませるための設計だ。 エージェント記憶はUIが軽視されがちで、DBに入っていてAPIで取れてプロンプトに挿せる、で終わりになりやすい。 でも人間が読めない記憶は監査できない。 監査できない記憶は、いずれ「なぜこの判断をしたのか」を追えなくなる。

かなチャットのHeartbeatメモリは heartbeat-memory.json に構造化して蓄積していて、中身はJSONで読める。 ただあれは1人のユーザーが自分のツールを覗く想定で、チームメンバーが共有知識として読む設計ではない。 NeuroValkey AgentsではValkeyのキースペースをダッシュボードに見せる設計がよかった。 NeuroValkeyが開発者向けの内部状態可視化なら、WUPHFはチームの共有知識としての可読性を狙っている。

RAGとの違い

手元で動くMarkdown + Git + 検索というだけなら、Obsidian vault、TiddlyWiki、NotebookLMクローンと同じ系統に見える。 HNでも「Obsidian vaultにpluginでよくないか」というコメントがあった。

近いが、WUPHFの中心は複数エージェントの共有作業場だ。 エージェントが作業中に得た事実をnotebookに置き、耐久性があるものをwikiへ昇格し、別エージェントがそれを参照する。 open-notebookをM1 MaxでローカルRAGとして動かした記事では、自分の記事をソースに入れてqwen3.6:35bに答えさせた。 あれは「既存資料を読ませる」システムで、WUPHF wikiは「エージェントが仕事しながら資料を増やす」システムだ。

更新主体がエージェントになると、検索精度だけでは片付かない問題が出る。 誰が書いたか、どの入力から抽出されたか、いつ正しかったか、古いfactをどう無効化するか、矛盾をどう扱うか。 WUPHFのschemaがfact ID、temporal validity、contradiction lint、redirect、slug不変性に細かく踏み込んでいるのはそのためだ。

まだ怖いところ

WUPHFはpre-1.0で、README自身も main は日々動くからrelease tagにpinしろと書いている。 今すぐ会社の記憶を全部預けるものではなく、ローカルで小さなチームwikiを作ってエージェントがどんな粒度で事実を残すかを観察する段階だろう。

一番気になるのは昇格の境界だ。 READMEは「Nothing is promoted automatically」と言うが、エージェントが自分で昇格判断するなら結局その判断基準の品質に依存する。 人間レビューを必須にするか、低リスクなplaybookだけ自動昇格にするか、複数エージェントの一致を待つか。

エージェントが書いたメモは初回はそれっぽく見える。 だが半年後に、過去の誤った記憶を別のエージェントが引用し、その引用がさらに新しいbriefに入ると、知識ベース全体が静かに濁る。 WUPHFはlintで矛盾、孤立、古いclaim、壊れたcross-referenceを検出する設計を持つが、「正しいが古くなった」「もっともらしいが根拠が薄い」までは拾えない。 AIエージェントのメモリ注入攻撃の記事では攻撃者がメモリを汚染する話を書いたが、WUPHFの問題はもっと日常的で、攻撃者がいなくてもエージェント自身の雑な昇格で記憶が汚れる。

逆の壊れ方もある。 AIコーディングツールのauto-compactionはコンテキストを自動圧縮して大事な記憶ごと消す。 AGENTS.mdの検証研究では、コンテキストファイルに情報を詰め込むほどタスク成功率が下がるという結果が出ていた。 少なすぎても多すぎても壊れる。

昇格操作はMCPツール群で実装されているので、ツール自体の安全性も無視できない。 オープンソースMCPサーバー50件のセキュリティスキャンでは61%で入力バリデーション欠如が見つかっている。

もうひとつは、ローカルGit repoという前提だ。 チームで使うなら同期先が欲しくなる。 顧客名、社内手順、営業メモ、認証まわりの断片が入ったwikiをどこへ置くのか。 HNでも「GitHubに敏感な業務文書を置くのは怖い」というコメントがあった。

参照