Keeps a documentation RAG in sync by detecting and updating only what changed.
Project description
DocForge
Keeps a documentation RAG knowledge base fresh by detecting exactly which pages changed โ instead of rebuilding everything.
Documentation sites change constantly. Most RAG pipelines handle updates the wasteful way: re-crawl the whole site and re-embed every page, even when only a handful changed. For a large docs site (1,000โ10,000+ pages) that means long refresh windows, wasted embedding cost, and stale answers in between.
DocForge takes the other path: on every run it detects exactly which pages changed (hashing normalized markdown, comparing against the last run) and touches only those โ deleting stale chunks and re-embedding just the new content. A re-sync of an unchanged site does nothing at all.
๐ Full documentation: Docs/ (architecture, complete CLI/MCP reference,
configuration, roadmap) ยท GUID.md (the design decision log โ the why).
Contents
- Why it exists
- Features
- How it works
- Install
- Quickstart
- CLI usage
- MCP server: connect an LLM to your docs
- Configuration
- Development
- Project status
- License
- Full documentation (
Docs/)
Why it exists
DocForge is the local, always-fresh knowledge base behind Legendary Dev Tool, a local-first AI coding assistant. A local LLM is only as good as the context it has โ if it doesn't know the current documentation for the libraries you're using, it hallucinates outdated or wrong APIs. DocForge keeps that context current, entirely on your own machine: no code or docs sent to a third party, no per-request cost.
It's equally usable standalone: point it at any documentation site and get a searchable, always-current knowledge base โ from the terminal, or as MCP tools an LLM client calls directly.
Features
- Change detection that actually skips work โ normalized-markdown hashing + an HTTP conditional-request (ETag/304) pre-check mean an unchanged page is never re-crawled or re-embedded, not just re-embedded.
- Multiple named knowledge bases โ sync as many docs sites as you want, each isolated in
its own manifest scope and vector-store collection (
--name, defaults to the site's host). - Local-first, three ways to run the vector store โ Docker container, embedded on-disk (no Docker, no server, like SQLite), or point at a remote/managed Qdrant Cloud cluster.
- Local embeddings โ fastembed (ONNX, no PyTorch),
with automatic GPU use when available (
--device auto|cpu|cuda). - Parallel, rate-limited crawling โ concurrent with a per-domain politeness delay,
configurable or disabled entirely (
--concurrency,--crawl-delay,--no-rate-limit). - Live progress with a self-correcting ETA โ no more wondering if a multi-thousand-page sync has hung.
- An MCP server (
docforge-mcp) โ exposes your knowledge bases as tools (list_docs,search_docs) any MCP-capable LLM client can call: Claude Code, Claude Desktop, LM Studio, or your own agent. stdio and HTTP transports, HTTP secured with an auto-generated bearer token by default. .envconfiguration โ set your Qdrant/DB/model settings once instead of repeating flags.
How it works
crawl (Crawl4AI) โ normalize markdown โ hash per page โ diff vs. last run
โ { new, changed, deleted, unchanged }
โ delete stale chunks โ chunk + embed only new/changed content โ upsert โ update stored hash
Two front doors onto that same core, adding no logic of their own:
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
a terminal โโโโถ โ docforge โ โโโโถ โ change โ โโโโถ vector store
(a human) โ (CLI) โ โ detection + โ (Qdrant)
โโโโโโโโโโโโโโโ โ RAG sync core โ
an LLM chat โโโโถ โโโโโโโโโโโโโโโ โโโโถ โ โ โโโโถ SQLite manifest
(MCP client) โ docforge-mcpโ โโโโโโโโโโโโโโโโโโโโ (page hashes)
โ (MCP tools)โ
โโโโโโโโโโโโโโโ
Full module-by-module breakdown: Docs/ARCHITECTURE.md.
Install
Requires Python 3.11+.
From PyPI โ to use the tool
pip install pydocforge # or: uv tool install pydocforge / pipx install pydocforge
Then, one-time, install the headless browser Crawl4AI needs to crawl:
python -m playwright install chromium
Both the docforge and docforge-mcp commands are now on your PATH:
docforge --help
Why
pydocforge, but the command isdocforge? The short namedocforgewas already taken on PyPI, so the install/distribution name ispydocforgeโ but the commands it installs aredocforgeanddocforge-mcp(likepip install python-dateutilgives youimport dateutil). Pick the install form that fits:uv add pydocforgeadds it as a dependency to a project;uv tool install pydocforge/pipx install pydocforgeinstall the CLI globally;uvx --from pydocforge docforge โฆruns it once without installing.
From source โ to develop it
Uses uv:
git clone https://github.com/PRABAKARAN32/docforge.git
cd docforge
uv sync # creates .venv, installs everything from uv.lock
uv run playwright install chromium # one-time: the headless browser Crawl4AI needs
Running the commands from source:
uv syncinstallsdocforgeanddocforge-mcpinto the project's.venv. Run them withuv run docforge โฆ(works from the project directory, nothing to activate), or activate the venv once (source .venv/bin/activate) and drop theuv runprefix. The copy-paste Quickstart below uses theuv runform; the reference listings further down show the baredocforgeโ that's also exactly what a PyPI install gives you.
Quickstart
1. Start a vector store โ pick one:
docker compose up -d # A) Qdrant in Docker on :6333 (persists to a named volume)
Or skip Docker entirely (option B, embedded on disk โ like SQLite, but for vectors): there's
nothing to start, just add --qdrant-path ./vectors to the sync/search commands below.
2. Build a knowledge base:
uv run docforge sync https://docs.python.org/3/
3. Search it:
uv run docforge search "how does async work"
4. Run it again later โ only pages that actually changed get re-crawled and re-embedded:
uv run docforge sync https://docs.python.org/3/ # unchanged pages: skipped entirely
CLI usage
docforge sync <url> [options] # crawl, detect changes, embed into the vector store
docforge diff <url> # preview what would change โ write nothing
docforge status # list knowledge bases and their page counts
docforge search "<query>" # search one KB (--name) or all of them (default)
docforge remove <name> # drop a knowledge base (or --all to wipe everything)
Common flags on sync/diff:
docforge sync <url> --name docker # explicit knowledge-base name
docforge sync <url> --bfs # no sitemap? crawl page-by-page instead
docforge sync <url> --dry-run # preview changes, write nothing
docforge sync <url> --max-pages 100 # cap pages processed
docforge sync <url> --concurrency 10 # crawl 10 pages in parallel
docforge sync <url> --crawl-delay 0.2 0.5 # tune the per-domain politeness delay
docforge sync <url> --device cuda # use a GPU for embedding
docforge sync <url> --force # ignore ETag/304, re-crawl every page
docforge sync <url> --qdrant-path ./vectors # embedded Qdrant, no Docker
docforge sync <url> --qdrant-url <cluster-url> # remote/Qdrant Cloud
Run docforge --help or docforge <command> --help for the full, grouped flag reference, or
see Docs/CLI.md for every command and flag in one page.
Multiple docs sites
Each site lives in its own named knowledge base โ isolated manifest scope and vector-store collection, independently searchable:
docforge sync https://docs.docker.com/ --name docker
docforge sync https://nginx.org/en/docs/ --name nginx --bfs
docforge search "<query>" --name docker # search just one
docforge search "<query>" # search all of them, merged by relevance
MCP server: connect an LLM to your docs
docforge-mcp exposes the knowledge bases you built with docforge sync as tools an LLM can
call mid-conversation โ list_docs() and search_docs(query, name=None). It adds no new
retrieval logic; it's a thin front door onto the exact same core the CLI uses.
For a client that launches the server itself (Claude Code, Claude Desktop) โ stdio, the default, no network involved at all:
claude mcp add docforge -- uv run --directory /path/to/docforge docforge-mcp
For a client that connects by URL (LM Studio, a custom agent) โ HTTP, secured by default with an auto-generated token (fresh every run, printed for you to copy โ the same idea as Jupyter Notebook's own auto-token):
uv run docforge-mcp --transport http --port 8000
DocForge MCP server (http) listening at http://127.0.0.1:8000/mcp
Auth token (generated fresh this run): 8c8JWYJyugjd2MaLgSTHOhkU_0B-HOl8B7IoithwNRA
Authorization header: Bearer 8c8JWYJyugjd2MaLgSTHOhkU_0B-HOl8B7IoithwNRA
Paste the URL + Authorization header into your client's MCP config. For a token that stays
stable across restarts instead of regenerating each time, set DOCFORGE_MCP_TOKEN in .env.
Run docforge-mcp --help for every flag (--transport stdio|http|both, --host, --port,
--token, --no-auth), or see Docs/MCP_SERVER.md for the full guide โ
client config examples (Claude Code, a generic mcp.json), both-transport setup, and
troubleshooting.
Configuration
Copy .env.example to .env to set these once instead of repeating flags. Precedence for
every setting: CLI flag > .env/environment variable > built-in default.
| Variable | Meaning | Default |
|---|---|---|
DOCFORGE_DB |
manifest database path | docforge.db |
QDRANT_URL |
Qdrant server (Docker/native/remote) | http://localhost:6333 |
QDRANT_PATH |
embedded Qdrant folder (no Docker) โ wins over QDRANT_URL |
unset |
QDRANT_API_KEY |
API key for a remote/managed Qdrant | unset |
DOCFORGE_EMBED_MODEL |
fastembed model โ must match what you synced with | BAAI/bge-small-en-v1.5 |
DOCFORGE_MCP_TRANSPORT |
docforge-mcp default transport |
stdio |
DOCFORGE_MCP_TOKEN |
stable HTTP auth token (else one is generated per run) | unset |
Full reference, including the three vector-store connection modes: Docs/CONFIGURATION.md.
Development
uv run ruff check . # lint
uv run pytest # fast tests (no network/browser required)
DOCFORGE_NETWORK_TESTS=1 uv run pytest # include live-crawl integration tests
CI runs lint + the fast test suite on every push and PR (.github/workflows/ci.yml).
Contributions are welcome โ open an issue to discuss a change before sending a large PR.
Project status
Change detection, RAG sync, the CLI, and the MCP server are all built and tested โ see
Docs/ROADMAP.md for what shipped in each milestone, and
GUID.md for the design reasoning behind each decision. Packaging the whole tool as
a Docker image is next.
License
Licensed under the Apache License 2.0.
Built on Crawl4AI (crawling, HTMLโMarkdown), Qdrant (vector store), fastembed (local embeddings), and the MCP Python SDK.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydocforge-0.1.0.tar.gz.
File metadata
- Download URL: pydocforge-0.1.0.tar.gz
- Upload date:
- Size: 347.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8fc3136e5b2e27f0813612867923a271da0f802defc0ed91453e6444921df53
|
|
| MD5 |
4b0b0de3551ac584bc7a19a62c693695
|
|
| BLAKE2b-256 |
a879a1a5448dca8bc7f7eaa4d1d9527a51d084b19275444b99ed75c3b6e53bee
|
File details
Details for the file pydocforge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pydocforge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 60.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb26d4af996e4617042113b7114680dcde07ce9f79ca3c02e40a782d016f2627
|
|
| MD5 |
ec789eeb823f3501e860c19578b1d37d
|
|
| BLAKE2b-256 |
ada88136c5ba30c8e48b1bee9ed631e239d9130095319bcf9a002ba7171c7a0c
|