|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +wdoc is a production-grade RAG system for document summarization, searching, and querying across 20+ file types. It serves as both a CLI tool (via Google Fire) and a Python library (`from wdoc import wdoc`). All LLM calls go through LiteLLM (100+ providers). See `ARCHITECTURE.md` for detailed data flow and component diagrams. |
| 8 | + |
| 9 | +## Commands |
| 10 | + |
| 11 | +### Install |
| 12 | +```bash |
| 13 | +pip install -e .[full] |
| 14 | +``` |
| 15 | + |
| 16 | +### Test |
| 17 | +```bash |
| 18 | +# All tests |
| 19 | +pytest tests --quiet |
| 20 | + |
| 21 | +# By category (basic = no API keys needed, api = needs credentials) |
| 22 | +pytest -m basic tests/test_wdoc.py |
| 23 | +pytest -m api tests/test_wdoc.py |
| 24 | + |
| 25 | +# Single test |
| 26 | +pytest tests/test_wdoc.py::test_wdoc_version |
| 27 | + |
| 28 | +# Parallelized |
| 29 | +pytest -n auto -m basic tests/test_parsing.py |
| 30 | + |
| 31 | +# CLI integration tests |
| 32 | +cd tests && ./test_cli.sh api |
| 33 | +``` |
| 34 | + |
| 35 | +Test environment variables: `PYTEST_IS_TESTING_WDOC=true`, `WDOC_TYPECHECKING=crash`, `WDOC_DISABLE_EMBEDDINGS_CACHE=true`. |
| 36 | + |
| 37 | +### Lint / Format |
| 38 | +```bash |
| 39 | +ruff format wdoc/ |
| 40 | +pre-commit run --all-files # runs ruff-format + pytest (on pre-merge) |
| 41 | +``` |
| 42 | + |
| 43 | +## Architecture Essentials |
| 44 | + |
| 45 | +**Entry points**: `__main__.py` (CLI via Google Fire) → `wdoc.py` (main orchestration class, ~3000 lines). |
| 46 | + |
| 47 | +**Named AI personas** drive the RAG pipeline in sequence: |
| 48 | +- **Raphael** — rephrases user query into alternatives |
| 49 | +- **Eve** — evaluates chunk relevance (cheap eval model) |
| 50 | +- **Anna** — extracts answers from relevant chunks (main model) |
| 51 | +- **Carl** — combines intermediate answers hierarchically |
| 52 | +- **Sam** — summarizes chunks (summarization task) |
| 53 | + |
| 54 | +Each persona can be customized via `WDOC_{NAME}_INSTRUCTIONS` env vars. |
| 55 | + |
| 56 | +**Configuration**: `utils/env.py` defines `EnvDataclass` — a frozen dataclass loading 50+ `WDOC_*` environment variables. CLI args override env vars. |
| 57 | + |
| 58 | +**Document loading**: `utils/loaders/` has per-filetype loaders dispatched by `load_one_doc()`. PDF loading tries 15 parser backends and picks the best. URL loading has Jina → Playwright → Selenium fallback chain. |
| 59 | + |
| 60 | +**Caching**: four layers — LLM responses (SQLite), embeddings (CacheBackedEmbeddings), parsed documents (joblib.Memory), and document content hashing. |
| 61 | + |
| 62 | +**Type checking**: Beartype runtime checking, controlled by `WDOC_TYPECHECKING` env var (crash/warn/disabled). |
| 63 | + |
| 64 | +## Adding New Settings |
| 65 | + |
| 66 | +Any new setting (CLI argument or environment variable) **must** be documented in: |
| 67 | +- `wdoc/docs/help.md` — describe the setting, its type, default value, and accepted values. |
| 68 | +- `wdoc/docs/examples.md` — add usage examples where appropriate. |
| 69 | + |
| 70 | +New settings should be either: |
| 71 | +- A **CLI argument** (defined in `wdoc.py`'s main class), or |
| 72 | +- A **`WDOC_*` environment variable** (defined in `wdoc/utils/env.py`'s `EnvDataclass`). |
| 73 | + |
| 74 | +**Environment variables are re-read on every access, not just at declaration.** The `EnvDataclass.__getattribute__` method checks `os.environ` at access time when the dataclass is frozen, so changing an env var between wdoc instantiations (or even at runtime) takes effect without reimporting. |
| 75 | + |
| 76 | +## Variables in `wdoc/utils/misc.py` to Keep Updated |
| 77 | + |
| 78 | +When adding new CLI arguments or loader-specific parameters, update these dicts in `wdoc/utils/misc.py`: |
| 79 | +- `filetype_arg_types` — maps loader-specific argument names to their types (e.g. `"whisper_lang": str`). |
| 80 | +- `extra_args_types` — maps extra wdoc instantiation arguments to their types. It merges `filetype_arg_types` automatically. |
| 81 | +- `DocDict.allowed_keys` — derives from `filetype_arg_types` keys automatically, but verify new keys appear. |
| 82 | + |
| 83 | +## Adding Support for a New Filetype |
| 84 | + |
| 85 | +1. **Create a loader** in `wdoc/utils/loaders/` — add a file (e.g. `myformat.py`) containing a function `load_myformat(path, file_hash, ...) -> List[Document]`. Use the `@debug_return_empty` and `@optional_strip_unexp_args` decorators (see `txt.py` for a minimal example). |
| 86 | +2. **Register the filetype** — add `"myformat"` to the `LOADABLE_FILETYPE` list in `wdoc/utils/loaders/__init__.py`. |
| 87 | +3. **Add loader-specific args** (if any) to `filetype_arg_types` in `wdoc/utils/misc.py`. |
| 88 | +4. **Document it** — add the filetype and its arguments to `wdoc/docs/help.md`, and add examples to `wdoc/docs/examples.md`. |
| 89 | +5. **Auto-detection** (optional) — if the filetype corresponds to a file extension, add a mapping in the auto-detection logic so `--filetype=auto` can infer it. |
| 90 | + |
| 91 | +## Bumping the Default Models |
| 92 | + |
| 93 | +The two default LLM identifiers (`WDOC_DEFAULT_MODEL` and `WDOC_DEFAULT_QUERY_EVAL_MODEL`) are duplicated across `wdoc/utils/env.py`, `wdoc/docs/help.md`, `SKILL.md`, `README.md`, `ARCHITECTURE.md`, and `docker/env.example`. Use the repo-root helper instead of editing each file by hand: |
| 94 | + |
| 95 | +```bash |
| 96 | +./bump_default_models.sh <NEW_STRONG_MODEL> <NEW_EVAL_MODEL> # dry-run preview |
| 97 | +./bump_default_models.sh <NEW_STRONG_MODEL> <NEW_EVAL_MODEL> --apply # write |
| 98 | +``` |
| 99 | + |
| 100 | +`env.py` is the source of truth for the current values. The script replaces both the full id (`provider/path/name`) and the basename, and re-syncs the `KEY=VALUE` lines in `docker/env.example` independently (so it recovers from prior drift). It never commits; review with `git diff` and commit yourself. |
| 101 | + |
| 102 | +## Building Documentation |
| 103 | + |
| 104 | +To regenerate the Sphinx autodoc files, run from the repo root: |
| 105 | +```bash |
| 106 | +sphinx-apidoc -o docs/source/ wdoc --force |
| 107 | +``` |
| 108 | + |
| 109 | +## Key Conventions |
| 110 | + |
| 111 | +- `utils/misc.py` is a large utility module (~53KB) — search it before creating new helpers. |
| 112 | +- Piped input to CLI is auto-detected as JSON, TOML, URLs, or file paths (`__main__.py`). |
| 113 | +- `--private` / `WDOC_PRIVATE_MODE=true` blocks all outbound connections and redacts API keys. |
| 114 | +- Binary FAISS embeddings (`WDOC_FAISS_COMPRESSION`) give ~32x compression; implemented in `utils/customs/binary_faiss_vectorstore.py`. |
| 115 | +- Semantic batching clusters intermediate answers before combining (scipy hierarchical clustering). |
| 116 | +- Use `python` not `python3` in commands. |
0 commit comments