doocus — local drive tree indexer
The document twin of meetus. Replicates a whole local drive tree into a
single index.json, preserving the folder hierarchy (no flattening). Every file
is a node; the original file is the artifact (what a QA/PM opens, what a
package links to). doocus only extracts text for the heavy formats
(docx/pdf/pptx/xlsx) — and that text is a search index only, never a
replacement for the document.
Extraction is deterministic and offline — no cloud AI touches the raw source. The raw source stays on disk; permitted services (Gemini web, NotebookLM) get the original (as a link once we have Drive URLs, or re-uploaded).
Quick start
# index a whole downloaded drive tree → docs-output/index.json
uv run make docs IN="/mnt/win/drive"
uv run make docs IN="..." DOC_EXTRA="--ocr" # OCR scanned pdfs
make docs-dry IN="..." # counts only, no writes
# or directly
uv run process_tree.py /mnt/win/drive --output docs-output
# one-off single file (older per-file model, still handy)
uv run process_doc.py notes.docx
Output contract
docs-output/
index.json whole tree; every file a node:
{ path, name, ext, family, mode, bytes,
modified, url:null } ◀ url = Drive link (later)
<mirrored path>/<file>.doocus/ sidecar — ONLY for extracted formats:
├── content.md extracted text — SEARCH INDEX ONLY
└── meta.json source/sha/dates/author/pages/... metadata
Node modes: extracted (docx/pdf/pptx/xlsx → text sidecar) · meeting
(mp4/mkv/... → belongs to meetus, not a doc) · link (everything else → original
is the artifact, nothing duplicated).
Supported types
| Family | Extensions | Notes |
|---|---|---|
| text | md, txt, yaml/yml, json | passthrough; json/yaml add a structure summary |
| tabular | csv | markdown table + row/col metadata (stdlib) |
| office | docx, pptx, xlsx | text + core properties (author, dates, title) |
text per page + info dict; --render for page-1 thumb |
||
| web | html/htm | visible text + title/meta tags |
| image | jpg/jpeg, png | EXIF (incl. capture date) + thumbnail; --ocr for text |
| media | mp4 | ffprobe metadata + thumbnail; delegates transcription to meetus |
Each extractor is isolated: a missing optional dependency or a corrupt file is
recorded as a warning in meta.json, never aborting a batch (same resilience as
ctrl/batch.sh).
Dependencies
Core text/tabular use only the stdlib. Everything else is a uv group in the
repo's pyproject.toml:
uv sync --group doocus # Pillow, PyYAML, python-docx, python-pptx,
# openpyxl, pypdf, beautifulsoup4, lxml
uv sync --group doocus --group ocr # + pytesseract (needs system `tesseract`)
mp4 uses system ffmpeg/ffprobe (shared with meetus). PDF page rendering
(--render) additionally needs the pdf-render group (pdf2image) + system
poppler.
Browser UI
ui/doocus-app/ (sibling of ui/meetus-app/, shares ui/framework/) reads
index.json and shows the full tree (folders preserved). Select a file →
detail view: for extracted docs, a split of the markdown-rendered extracted
text (clearly labelled "search index, not the document") beside the native
view of the original (pdf inline; docx/xlsx → download); for linked files the
original renders directly (image / html / text / markdown). A package builder
zips selected originals (+ the content.md for extracted ones) for a target
(Gemini web / NotebookLM), and will emit Drive links once nodes carry a url.
cd ui/doocus-app && npm install
DOOCUS_OUTPUT=/abs/path/to/docs-output npm run dev