Local semantic search over a project's docs/ folder, exposed as an MCP server. Install once per machine, query from any MCP client (Claude Code, Codex, Cursor, ...) across every project you own.
fat-docs indexes the markdown files in your repo's docs/ directory, generates embeddings with a local model (no API calls, nothing leaves your machine), and serves two MCP tools:
search_docs— semantic search with two-stage ranking (doc-level prefilter, then chunk-level ranking inside the top docs). Returns stitched excerpts around each hit. Supportspath_filter,tags, andgroupsas pre-filters.index_docs— builds or rebuilds the index for the current project.
It ships alongside a groupings skill for the major coding agents (Claude Code, Codex, Cursor) that helps you generate docs/groupings.md — a taxonomy your agents use when writing doc front matter and maintaining docs/guide.md.
The embedding model is ~275MB and takes a few seconds to load. Spawning a fresh MCP process per query would reload it every time. So fat-docs runs as a single long-lived service on 127.0.0.1:18800, loaded once, multi-tenanting every docs folder on your machine. Each MCP request sends an X-Docs-Dir header pointing at the docs folder it wants.
The service is installed via:
- macOS:
launchduser agent (~/Library/LaunchAgents/com.fat-docs.server.plist) - Linux:
systemd --userunit (~/.config/systemd/user/fat-docs.service) - Windows: Task Scheduler task at logon (
\fat-docs)
No admin privileges. Runs at login, restarts on crash.
# In your project
npx fat-docs initInteractive setup walks you through:
- Installing the background service (first time only; subsequent projects reuse it)
- Scaffolding the canonical
docs/structure (product/,technical/patterns/,technical/runbooks/with overview files) — existing files are never overwritten - Writing the
.mcp.jsonentry pointing at the service - Adding
docs/.fat-docs/to.gitignore - Appending a "docs search is available" block to
CLAUDE.mdand/orAGENTS.md(each opt-in) - Installing the
groupingsskill for Claude Code, Codex, and Cursor (each opt-in)
Then:
# In your agent: invoke the `groupings` skill to generate docs/groupings.md
# Then:
npx fat-docs indexRestart your MCP client and search_docs is available.
fat-docs is opinionated about a base layout every docs/ folder should have. On init, the following files are scaffolded (existing files are never overwritten):
docs/
├── product/
│ └── overview.md # product-level docs: what the thing does, who it's for
└── technical/
├── overview.md
├── patterns/
│ └── overview.md # code conventions, patterns, and rules
└── runbooks/
└── overview.md # operational how-tos (local dev, deploy, debug, onboarding)
Each overview.md describes its folder's purpose and serves as a mini-index of the docs within. Agents maintain these as docs are added (per the memory-file instructions).
Why opinionated? Generic engineering tooling — the /dev command in your agent, onboarding automation, agent-driven code review — benefits from a predictable place to find patterns and runbooks. Anyone landing in the repo should know where to look.
You're free to add other top-level folders (architecture/, business/, whatever) as needed; fat-docs only cares about the scaffolded ones.
┌───────────────────────────────────────────────────────────────┐
│ Your project │
│ │
│ docs/ │
│ outline.md ← maintained by your agent │
│ guide.md ← maintained by your agent │
│ groupings.md ← taxonomy (from skill) │
│ product/overview.md ← scaffolded by `init` │
│ technical/overview.md ← scaffolded by `init` │
│ technical/patterns/ ← scaffolded by `init` │
│ technical/runbooks/ ← scaffolded by `init` │
│ .fat-docs/docs.db ← search index (gitignored) │
│ │
│ .mcp.json ← points at the service │
│ CLAUDE.md / AGENTS.md ← "you can use search_docs" │
│ .claude/skills/groupings/ ← skill for Claude Code │
│ .codex/skills/groupings/ ← skill for Codex │
│ .cursor/rules/groupings.mdc ← skill for Cursor │
└───────────────────────────────────────────────────────────────┘
│
│ HTTP (X-Docs-Dir header)
▼
┌───────────────────────────────────────────────────────────────┐
│ fat-docs background service (one per machine) │
│ - loaded embedding model │
│ - serves every project concurrently │
│ - logs to ~/Library/Logs/fat-docs.{log,err} (macOS) │
└───────────────────────────────────────────────────────────────┘
When your agent edits docs, the instructions in CLAUDE.md / AGENTS.md tell it to keep outline.md and guide.md up to date and to tag new docs with groups: (keys from groupings.md). That's how the system stays coherent without you having to maintain it.
fat-docs init [--yes] # interactive setup for this project (--yes: accept all defaults)
fat-docs install # install + start the service (done automatically by init)
fat-docs uninstall # stop + remove the service
fat-docs start # start the service
fat-docs stop # stop the service (without uninstalling)
fat-docs restart # restart the service
fat-docs status # is it running? which port? uptime?
fat-docs logs [--follow] # tail the logs
fat-docs index [--force] # build/rebuild the index for the current repo
fat-docs search <query> [--limit N] [--path-filter PATH] [--tags a,b] [--groups a,b]
fat-docs serve # run the server in the foreground (debugging)
Non-interactive environments (CI, piped stdin) must pass --yes to accept all defaults; otherwise init errors out.
{
"mcpServers": {
"docs": {
"type": "http",
"url": "http://127.0.0.1:18800/mcp",
"headers": {
"X-Docs-Dir": "/absolute/path/to/project/docs"
}
}
}
}All fields optional. Used by search_docs as filters and by your agent when routing.
---
title: Agent Lifecycle
summary: How agents are created, paused, and retired.
groups: [agents, governance]
tags: [lifecycle, state-machine]
hidden: false
---groups— keys drawn fromdocs/groupings.md. Taxonomy-based; used byguide.mdrouting and thesearch_docsgroupsfilter.tags— free-form strings; used by thesearch_docstagsfilter.hidden: true— exclude from indexing.
Optional docs/.docignore, gitignore-style rules:
drafts/**
internal/*.md
!internal/public-stuff.md
Per-project (inside your repo):
docs/— your markdowndocs/.fat-docs/docs.db— SQLite index (initoffers to adddocs/.fat-docs/to.gitignore).mcp.json— MCP client configCLAUDE.md/AGENTS.md— memory-file blocks that teach agents the system (each opt-in atinittime).claude/skills/groupings/SKILL.md,.codex/skills/groupings/SKILL.md,.cursor/rules/groupings.mdc— groupings skill for each agent (each opt-in atinittime)
Per-machine:
~/.fat-docs/model-cache/— downloaded embedding model (~275MB, shared across projects)~/.fat-docs/server.port— port the service is listening on- Logs:
- macOS:
~/Library/Logs/fat-docs.{log,err} - Linux:
~/.local/state/fat-docs/fat-docs.{log,err} - Windows:
%LOCALAPPDATA%\fat-docs\logs\fat-docs.{log,err}
- macOS:
MIT