I have been thinking about where to put design notes and implementation plans generated by AI agents.
I often use Superpowers-style planning and docs workflows: before implementing something, I write down the spec and implementation direction in an SDD-like document. That workflow is useful, but I do not really like keeping every generated document in the repository forever.
Code has builds and tests, so breakage is easier to see. Old design notes and implementation plans are different. They become stale very easily, and an AI agent will not always read older documents carefully. Some docs absolutely belong in the repository, but if everything stays there, durable project knowledge and temporary work logs start to mix together.
I wanted a place that AI agents can read and write easily, humans can still browse later, and the main repository can keep some distance from.
That led me to build a small OSS project called docs-ssh.
Docs over SSH
One of the inspirations was Supabase Docs over SSH.
AI agents are good at file operations. If that is true, showing documentation as a filesystem over SSH may fit better than exposing it only through a web UI or a custom API.
There are many ways to search documents:
- read raw files
- search with grep or ripgrep
- build an index for RAG
- give an agent shell tools and let it explore
RAG is useful, of course. But there are cases where it is hard to see why a piece of text was not retrieved. Personally, I also like the pattern where an agent uses find, rg, and read-range, then leaves behind a trace of how it searched.
docs-ssh is an experiment in that direction. It treats docs and work notes as a shell-native filesystem for AI agents, while keeping a browser viewer for humans.
What docs-ssh is
docs-ssh is a local-first tool for working with project docs, issues, and tasks over SSH.
When running it locally, the flow is roughly:
pnpm install
pnpm run build
npm link
pnpm run dev
By default, the SSH server runs on 127.0.0.1:2222, and the viewer runs at http://127.0.0.1:3000.
From another terminal, you can check it with:
docs-ssh status --json
ssh localhost -p 2222 bootstrap --json
If you want an agent to use it, start with CLI login:
docs-ssh login --json
This command opens browser login, creates a temporary SSH identity locally, sends the public key to the viewer's CLI login API, and creates an SSH session. The response includes fields such as sshCommand, identityFile, username, server, project, and expiresAt, so the agent can use that information to connect over SSH.
For repository-level project settings, docs-ssh uses .docs-ssh.toml.
docs-ssh config init
An example looks like this:
host = "docs-ssh-local"
viewer_origin = "http://localhost:3000"
project = "docs-ssh"
host is an SSH config alias. For local development, you might define it like this:
Host docs-ssh-local
HostName localhost
Port 2222
You can also generate agent-facing instructions from the CLI:
docs-ssh skill --output .agents/skills/docs-ssh/SKILL.md
docs-ssh agents --output AGENTS.md --append
At that point, an agent can learn the basic flow: check docs-ssh status --json, run docs-ssh login --json if needed, read bootstrap --json, then write to places such as /projects/<slug>/issues and /projects/<slug>/tasks.
What the filesystem looks like
In the current version of docs-ssh, an SSH session exposes paths like these:
/README.md
/home
/projects/<slug>
/projects/<slug>/issues
/projects/<slug>/tasks
/tmp
/home is private durable storage for the authenticated principal. I use it for personal notes and drafts.
/projects/<slug>/issues is for project issue tracking. It stores what needs to be done, why it matters, status, next actions, and links to related task results.
/projects/<slug>/tasks is a place for research and work results. Logs, conclusions, verification results, proposals, and artifacts can be stored under a directory for each task.
For example, I might ask an agent to run commands like these. Here, <ssh-command> is the sshCommand returned by docs-ssh login --json.
<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"
For larger files, the agent can use read-range instead of cat.
<ssh-command> read-range -n /README.md 1 80
There is also batch for reducing SSH round trips:
printf '%s\n' \
'find /projects/docs-ssh/tasks -maxdepth 1 -type f' \
'read-range -n /README.md 1 40' \
| <ssh-command> batch
This executes multiple commands in a single SSH exec and returns one JSON object per command. That shape is fairly convenient for agents.
Authentication
Supabase Docs over SSH was built for reading public docs. For personal or team work notes, I needed authentication and project boundaries.
docs-ssh currently includes:
- OIDC login for the browser viewer
- tenant, principal, and project management
- SSH public key registration
- temporary SSH sessions
-
docs-ssh token loginfor creating SSH sessions from API tokens
The normal CLI login flow uses the browser to approve an SSH session:
docs-ssh login --json
For server-side agents and automated jobs, browser login is not always a good fit. So docs-ssh also has a flow that creates an SSH session from a bearer token:
docs-ssh token login \
--token dssh_... \
--host docs-ssh \
--project default \
--json
This is still more of a foundation than a finished hosted service. It is enough for my own LAN or a small server, but a real service would need more work around operations, permissions, and lifecycle management.
Internal structure
The implementation is TypeScript on Node 24.
At a high level, it is made of these parts:
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
The SSH server uses ssh2, and the shell is based on just-bash. You connect with normal ssh, but what you get is the filesystem and command surface provided by docs-ssh.
bootstrap --json returns the session manifest. An agent should read this first to understand the current project, available paths, and scope.
read-range prevents agents from reading a huge file all at once. batch reduces the number of SSH execs. These two commands exist because LLM agents become much more practical when they can inspect docs through a shell without flooding the context window.
The browser viewer is for humans. Even without going through an AI agent, you can browse saved issues and task results in the browser. The primary use case is reading Markdown and text files.
Why this is useful
The main goal is to keep agent work context slightly separate from the repository.
For example, docs-ssh can hold:
- research notes before implementation
- plans that may be thrown away
- work logs before they become issues
- private helper notes for agents
- verification results and handoff notes after work
Docs that belong in the repository should stay in the repository. README files, operational runbooks, and ADRs that should remain as durable design records are better kept there.
But if every intermediate artifact from agent collaboration goes into the repository, the repository becomes noisy. docs-ssh is meant to absorb that middle layer.
Another benefit is observability for agentic search.
When you only see a RAG result, it can be hard to tell why that candidate appeared or why another candidate was missed. With an SSH filesystem and shell commands, it is easier to inspect which directories the agent visited, which keywords it tried, and which files it actually read.
SSH is not the only possible interface. You could build a similar system with an HTTP API, MCP, or a local filesystem. But SSH already works well with existing tools and with agents. ls, find, rg, and cat are ordinary operations that agents already know how to use.
Benchmark
I do not want to judge whether docs-ssh is good for agentic search based on vibes alone.
So the repository includes a benchmark harness under bench/multihop-rag.
The first target is MultiHop-RAG. Answering one question often requires evidence across multiple documents, which is closer to the docs-ssh use case than simple single-passage retrieval.
The current harness splits the flow into fetch, normalize, materialize, run, and score steps. Gold answers and supporting evidence stay in the harness, while the docs-ssh project tree only contains the readable corpus.
The corpus shown to the agent is not a raw dump. Before materializing it, I use AI to add titles and metadata to files, then place them in a layout like category/source/slugified-title__documentId.md. When the original source does not have a useful title or classification, AI fills that in before placement. In other words, instead of converting the corpus into an embedding index, I first shape it into a file structure that both humans and AI agents can read.
The comparisons I care about are roughly:
- BM25
- dense retrieval
- hybrid retrieval
- hybrid rerank
- docs-ssh direct retrieval
- an agent with a local vector search tool
- an agent exploring the filesystem through docs-ssh
Here are early results from a light 100-case benchmark. The dataset is Hugging Face yixuantt/MultiHopRAG, the materialized corpus has 609 documents, the agent model is gpt-5.4-mini, reasoning effort is low, and top K is 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 |
Looking only at retrieval quality, the docs-ssh agent is strong. In 99 out of 100 cases, it placed at least one gold evidence document in the top 5. In 73 cases, it placed all required gold evidence documents in the top 5.
But compared with the RAG-style baselines, it is very slow. BM25 averaged 7ms, Hybrid averaged 194ms, and even Hybrid + rerank averaged about 1.7 seconds. The docs-ssh agent averaged about 88 seconds, with a p95 of about 169 seconds. The retrieval quality is high, but this is far too heavy for an interactive search UI or request-time retrieval.
The important caveat is that this does not mean "searching a local folder with rg is slow." The docs-ssh agent run goes through a just-bash-based filesystem and command surface over SSH. The number includes docs-ssh's shell implementation, the mountable filesystem layer, SSH exec overhead, and the agent's own exploration strategy. It should be interpreted separately from running rg directly on a local filesystem.
The saved traces also show heavy context pressure. Broad rg and rg --files output can get large. In these runs, median tool output was about 75.7 KB, average output was about 127.6 KB, and p95 output was about 368.5 KB.
The result is that a docs-ssh-style corpus can let an agent do strong multi-document retrieval without a vector index. But the latency and context usage are heavy.
I am not sure I would call that straightforwardly "AI-friendly." Still, it looks like a useful direction: instead of first converting documents into an embedding structure that humans cannot inspect directly, you can keep a structure that is readable to both humans and AI agents while still maintaining decent retrieval quality.
What I want to improve next
This is still mostly a personal experiment, so the UX needs a lot of work.
- improve the browser viewer
- clean up settings for hosted use
- make the API token and SSH session flow easier to operate
- improve project and source management UX
- improve the agent-facing skill
- speed up exploration paths that become heavy on top of just-bash
- improve search efficiency with
batchandread-range
The benchmark makes one issue very clear: broad rg and large file listings directly affect latency and context usage. I want to avoid naively streaming everything through just-bash. Output limits, truncation, search-specific helpers, and a lighter filesystem backend are all worth exploring.
If this becomes a hosted service, authentication, project permissions, token lifecycle, audit logs, and operating cost also need more work.
But as a small box for my local machine or LAN, it already feels useful.
Summary
docs-ssh is a tool for exposing project docs and work notes to AI agents as an SSH filesystem.
It is for things that may not belong in the repository but should still be available later to both agents and humans. It is also for cases where I want agents to search shell-natively instead of relying only on RAG.
It is still a young project, and I am growing it around my own development workflow. If this resonates with you, the project is on GitHub.
Top comments (1)
The benchmark is the best part of this. Both pain points, the 88s latency and the 368KB p95 tool output, trace back to the agent walking the whole tree. Have you tried a cheap BM25 first pass (7ms, already 0.74 recall) to shrink the candidate set, then let the agent run its rg/read-range exploration only inside that subset? You'd cap the context it wades through and keep the "I can see why a doc did or didn't surface" property, but I wonder if the prefilter would clip exactly the multi-hop jumps where the full walk earns its keep.