AI agent に作らせた設計メモや実装計画を、どこに置くかで少し悩んでいます。

普段は Superpowers の planning / docs 系のワークフローを使って、SDD likeに仕様や実装方針を文章に落としてから進めています。これは便利なのですが、生成された doc をそのまま repository に積み続けるのはあまり好きではありません。

コードはビルドやテストで壊れやすさが見えます。一方で、古い設計メモや実装計画はかなり簡単に stale になります。AI agent も、過去の doc を必ず丁寧に読んでくれるわけではありません。もちろん repository に置くのが正しい doc もありますが、全部を repository に残すと、あとから読むべき情報と一時的な作業ログが混ざっていきます。

なので、AI agent が読み書きしやすく、人間もあとから見られて、でも repository 本体とは少し距離を置ける場所が欲しいと思っていました。

その流れで docs-ssh という小さい OSS を作っています。

docs over SSH という発想

きっかけの 1 つは Supabase の Supabase Docs over SSH でした。

AI agent はファイル操作が得意です。であれば、ドキュメントを Web UI や専用 API だけで見せるのではなく、SSH 越しの filesystem として見せるのは相性がよさそうです。

ドキュメント検索にはいろいろな形があります。

  • 生のファイルを読む
  • grep / ripgrep で探す
  • RAG 用の index を作って検索する
  • agent に shell tool を渡して探索させる

RAG はもちろん便利ですが、「なぜその文章にたどり着かなかったのか」が見えにくい場面があります。個人的には、agent が findrgread-range を使い、探索ログを残しながら探してくれる形もかなり好きです。

docs-ssh はその方向の実験です。ドキュメントや作業メモを、AI agent にとっては shell-native な filesystem として、人間にとっては browser viewer で見られる場所として扱います。

docs-ssh とは何か

docs-ssh は、プロジェクトごとの docs / issues / tasks を SSH 越しに扱うためのローカルファーストなツールです。

ローカルで動かす場合は、だいたいこの流れです。

pnpm install
pnpm run build
npm link
pnpm run dev

デフォルトでは SSH server が 127.0.0.1:2222、viewer が http://127.0.0.1:3000 で起動します。

別の terminal からはこう確認できます。

docs-ssh status --json
ssh localhost -p 2222 bootstrap --json

agent 側に使わせる場合は、まず CLI で login します。

docs-ssh login --json

このコマンドは browser login を開き、ローカルに一時的な SSH identity を作り、viewer 側の CLI login API に公開鍵を渡して SSH session を作ります。戻り値には sshCommand, identityFile, username, server, project, expiresAt などが入るので、agent はそれを使って SSH できます。

プロジェクト設定を repository に置く場合は、.docs-ssh.toml を使います。

docs-ssh config init

中身はたとえばこうです。

host = "docs-ssh-local"
viewer_origin = "http://localhost:3000"
project = "docs-ssh"

host は SSH config の alias です。ローカル開発なら、たとえばこういう alias を置きます。

Host docs-ssh-local
  HostName localhost
  Port 2222

agent 向けの instructions も CLI から生成できます。

docs-ssh skill --output .agents/skills/docs-ssh/SKILL.md
docs-ssh agents --output AGENTS.md --append

ここまでやると、agent は「まず docs-ssh status --json を見る」「必要なら docs-ssh login --json する」「bootstrap --json を読んでから /projects/<slug>/issues/projects/<slug>/tasks に書く」という流れを覚えられます。

filesystem の見え方

最新の docs-ssh では、SSH session の中でだいたい次のような場所が見えます。

/README.md
/home
/projects/<slug>
/projects/<slug>/issues
/projects/<slug>/tasks
/tmp

/home は認証済み principal ごとの private な durable storage です。個人的なメモや下書きに使います。

/projects/<slug>/issues は project issue tracking 用です。何をやるのか、なぜやるのか、status、next action、関連する task result へのリンクを書きます。

/projects/<slug>/tasks は research や作業結果の置き場です。ログ、結論、検証結果、提案、生成物などを task ごとの directory に置きます。

たとえば agent にはこういう操作をさせます。ここでの <ssh-command> は、docs-ssh login --json が返す sshCommand のことです。

<ssh-command> bootstrap --json
<ssh-command> cat /README.md
<ssh-command> cat /projects/docs-ssh/README.md
<ssh-command> ls /projects/docs-ssh/issues
<ssh-command> "printf '%s\n' '# Example issue' 'status: open' > /projects/docs-ssh/issues/example-issue.md"
<ssh-command> mkdir -p /projects/docs-ssh/tasks/example-task/artifacts
<ssh-command> "printf '%s\n' '# Notes' '- item' > /projects/docs-ssh/tasks/example-task/notes.md"

大きいファイルを読むときは cat ではなく read-range を使えます。

<ssh-command> read-range -n /README.md 1 80

SSH round trip を減らしたいときは batch もあります。

printf '%s\n' \
  'find /projects/docs-ssh/tasks -maxdepth 1 -type f' \
  'read-range -n /README.md 1 40' \
  | <ssh-command> batch

これは 1 回の SSH exec で複数 command を実行し、1 command につき 1 JSON object を返します。agent にとってはかなり扱いやすい形です。

認証まわり

元になった Supabase Docs over SSH は公開 docs を読む用途なので、個人やチームの作業メモを置くには認証や project 境界が足りません。

docs-ssh では、今のところ次の要素を入れています。

  • browser viewer の OIDC login
  • tenant / principal / project の管理
  • SSH public key の登録
  • 一時的な SSH session
  • API token から SSH session を作る docs-ssh token login

通常の CLI login は、browser で承認して SSH session を作る流れです。

docs-ssh login --json

一方で、サーバー側の agent や自動実行では browser login が合わないことがあります。そのため、Bearer token を使って SSH session を作る flow も入れています。

docs-ssh token login \
  --token dssh_... \
  --host docs-ssh \
  --project default \
  --json

ただし、ここは「hosted service として完成している」というより、クラウド側の agent からも同じ filesystem に入れるようにするための土台です。自分の LAN や小さい server で使う分には十分ですが、ちゃんとサービスとして運用するにはまだ詰めるところがあります。

内部構成

実装は TypeScript / Node 24 です。

大きく分けると、次の部品でできています。

CLI
  |
  +-- SSH server
  |     |
  |     +-- ssh2
  |     +-- just-bash
  |     +-- bootstrap / batch / read-range
  |
  +-- viewer server
  |     |
  |     +-- browser file viewer
  |     +-- OIDC login
  |     +-- CLI login approval
  |     +-- API token / SSH session API
  |
  +-- auth store
  |     |
  |     +-- SQLite
  |     +-- tenants / principals / projects
  |     +-- SSH keys / SSH sessions / API tokens
  |
  +-- workspace layout
        |
        +-- /home
        +-- /projects/<slug>/issues
        +-- /projects/<slug>/tasks
        +-- /tmp

SSH server は ssh2 を使い、shell の中身は just-bash ベースです。通常の ssh で入れますが、実体は docs-ssh が用意した filesystem と command surface です。

bootstrap --json は session の manifest を返します。agent はまずこれを読んで、current project、使える path、scope を確認します。

read-range は巨大な file を一気に読ませないための command です。batch は SSH exec の回数を減らすための command です。この 2 つは、LLM agent が shell 越しに docs を読むときの実用性を上げるために入れています。

browser viewer は人間向けです。AI を経由しなくても、保存された issue や task result を browser で一覧できます。Markdown や text file を読む用途が中心です。

何が嬉しいのか

一番の目的は、agent の作業文脈を repository から少し切り離すことです。

たとえば、次のようなものを docs-ssh 側に置けます。

  • 実装前の調査メモ
  • 途中で捨てるかもしれない plan
  • issue 化する前の作業ログ
  • agent が参照する private な補助メモ
  • 作業後の検証結果や handoff

repository に入れるべき docs は repository に入れればいいと思います。README、運用手順、設計として残すべき ADR などはそのまま repository に置く方が自然です。

一方で、agent と何度も往復する中間生成物まで全部 repository に置くと、ノイズが増えます。docs-ssh はその中間領域を受ける場所です。

もう 1 つは、agentic search の観察しやすさです。

RAG の結果だけを見ると、なぜその候補が出たのか、なぜ別の候補が出なかったのかが追いにくいことがあります。SSH filesystem と shell command なら、agent がどの directory を見て、どの keyword で探して、どの file を読んだかが比較的見えます。

もちろん、SSH である必然性が絶対にあるわけではありません。HTTP API でも、MCP でも、ローカル filesystem でも似たことはできます。ただ SSH は既存の tool と agent の相性がよく、ls, find, rg, cat というごく普通の操作で扱えるのが強みです。

ベンチマーク

docs-ssh が本当に agentic search に向いているのかは、雰囲気だけでは判断できません。

そのため、repo には bench/multihop-rag という benchmark harness も入れています。

今回の対象は MultiHop-RAG で行いました。1 つの質問に答えるために複数 document にまたがる evidence が必要になるので、単純な single passage retrieval より docs-ssh の用途に近いと考えています。

今の harness では、fetch / normalize / materialize / run / score までを分けています。gold answer や supporting evidence は harness 側に置き、docs-ssh の project tree には readable corpus だけを置くようにしています。

ここで agent に見せている corpus は、完全な raw dump ではありません。事前にAIで file に title や metadata を持たせ、category/source/slugified-title__documentId.md のような folder layout に materialize しています。元ファイルに良い title や分類がない場合は、ここを AI で補ってから配置しています。つまり、embedding index に変換する代わりに、人間にも AI にも読めるファイル構造を先に整える、という前処理を入れています。

比較対象はこのあたりです。

  • BM25
  • dense retrieval
  • hybrid retrieval
  • hybrid rerank
  • docs-ssh direct retrieval
  • local vector search tool を持つ agent
  • docs-ssh 越しに filesystem を探索する agent

100 case で軽いベンチの結果が以下になります。 前述の通り対象は Hugging Face の yixuantt/MultiHopRAG、materialized documents は 609、agent model は gpt-5.4-mini、reasoning effort は low、top K は 5 です。

mode cases errors any@1 any@5 all@5 recall@5 MRR@10 avg latency p95 latency
BM25 100 0 0.790 0.960 0.450 0.741 0.861 7ms 14ms
Dense 100 0 0.560 0.900 0.370 0.646 0.699 850ms 1454ms
Hybrid 100 0 0.680 0.960 0.480 0.740 0.793 194ms 319ms
Hybrid + rerank 100 9 0.700 0.970 0.520 0.774 0.818 1726ms 2647ms
docs-ssh agent 100 0 0.910 0.990 0.730 0.884 0.947 87784ms 168823ms

この結果だけ見ると docs-ssh agent は retrieval quality では強いです。100 case 中 99 case で top 5 に少なくとも 1 つの gold evidence document を入れ、73 case では必要な gold evidence document をすべて top 5 に入れています。

ただし、RAG-style baselines と比べるとかなり遅いです。BM25 は平均 7ms、Hybrid は平均 194ms、Hybrid + rerank でも平均 1.7 秒程度でした。一方で docs-ssh agent は平均 latency が約 88 秒、p95 が約 169 秒です。retrieval quality は高いものの、interactive な検索 UI や request-time retrieval として見るには重すぎます。

ここでの遅さは「普通の local folder を rg で検索したら遅い」ということではないです。docs-ssh agent の run は、SSH 越しに just-bash ベースの filesystem / command surface を叩いています。つまり、docs-ssh 固有の shell 実装、mountable filesystem、SSH exec、agent の探索手順が全部乗った数字です。local filesystem 上で直接 rg する場合とは分けて見る必要があります。

さらに saved trace を見ると、context pressure もかなり大きいです。広い rgrg --files の出力が膨らみ、median tool output は約 75.7 KB、average は約 127.6 KB、p95 は約 368.5 KB でした。

docs-sshはvector index なしでも agent がかなり強い multi-document retrieval をできます。ただし latency と context 使用量は重い、ということもわかりました。

これをそのまま AI friendly と呼べるかは微妙です。ただ、embedding のように人間には見えにくい構造へ一度変換しなくても、人間と AI の両方にとって読みやすい構造を保ったまま、一定以上の検索精度を出せる方法としては良さそうです。

今後やりたいこと

まだ自分用の実験色が強いので、UX はかなり直したいです。

  • browser viewer の改善
  • hosted 前提の設定整理
  • API token / SSH session flow の運用整理
  • project / source 管理の UX 改善
  • agent 向け skill の改善
  • just-bash 上で重くなりやすい探索処理の改善
  • batchread-range を使った探索効率の改善

特に benchmark で見えた通り、広い rg や大量の file listing は latency と context 使用量に直撃します。just-bash の上で全部を素直に流すのではなく、出力上限、truncation、検索専用 helper、より軽い filesystem backend などは触りたいところです。

特に hosted service として出すなら、認証、project 権限、token の lifecycle、監査ログ、運用コストなどをもう少し詰める必要があります。

ただ、自分のローカルや LAN で使う小さい箱としては、すでに手応えがあります。

まとめ

docs-ssh は、AI agent が扱う project docs や作業メモを SSH filesystem として見せるためのツールです。

repository に残すほどではないけれど、agent と人間の両方からあとで参照したい。RAG だけではなく、agent に shell-native に探索させたい。そういう用途のために作っています。

まだひよっこのプロダクトですが、自分の開発ワークフローに合わせて少しずつ育てています。所詮自分のためのプロダクトではありますが何か琴線に触れた方がいたら、GitHub で star などいただけると嬉しいです。


この記事は Zenn にも転載しています。