Skip to main content

Keeps a documentation RAG in sync by detecting and updating only what changed.

Project description

DocForge

CI PyPI License: Apache 2.0 Python 3.11+

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

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.
  • .env configuration โ€” 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 is docforge? The short name docforge was already taken on PyPI, so the install/distribution name is pydocforge โ€” but the commands it installs are docforge and docforge-mcp (like pip install python-dateutil gives you import dateutil). Pick the install form that fits: uv add pydocforge adds it as a dependency to a project; uv tool install pydocforge / pipx install pydocforge install 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 sync installs docforge and docforge-mcp into the project's .venv. Run them with uv run docforge โ€ฆ (works from the project directory, nothing to activate), or activate the venv once (source .venv/bin/activate) and drop the uv run prefix. The copy-paste Quickstart below uses the uv run form; the reference listings further down show the bare docforge โ€” 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydocforge-0.1.0.tar.gz (347.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydocforge-0.1.0-py3-none-any.whl (60.1 kB view details)

Uploaded Python 3

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

Hashes for pydocforge-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e8fc3136e5b2e27f0813612867923a271da0f802defc0ed91453e6444921df53
MD5 4b0b0de3551ac584bc7a19a62c693695
BLAKE2b-256 a879a1a5448dca8bc7f7eaa4d1d9527a51d084b19275444b99ed75c3b6e53bee

See more details on using hashes here.

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

Hashes for pydocforge-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bb26d4af996e4617042113b7114680dcde07ce9f79ca3c02e40a782d016f2627
MD5 ec789eeb823f3501e860c19578b1d37d
BLAKE2b-256 ada88136c5ba30c8e48b1bee9ed631e239d9130095319bcf9a002ba7171c7a0c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page