|
| 1 | +# CLAUDE.md — working notes for AI-assisted sessions |
| 2 | + |
| 3 | +Rust port of [docling](https://github.com/docling-project/docling): document |
| 4 | +conversion (PDF/Office/HTML/audio/video/…) to Markdown / docling-JSON / DCLX, |
| 5 | +validated for byte-for-byte conformance against upstream Python docling. |
| 6 | + |
| 7 | +## Workflow rules |
| 8 | + |
| 9 | +- **Every commit must be signed off by the author.** End each commit message |
| 10 | + with `Signed-off-by: name <email>`. |
| 11 | +- Claude Web: **Never open pull requests on `artiz/docling.rs`.** Push a `claude/<topic>` |
| 12 | + branch and hand back a compare link |
| 13 | + (`https://github.com/docling-project/docling.rs/compare/master...artiz:docling.rs:<branch>?expand=1`); |
| 14 | + the maintainer opens/merges PRs themself (usually into the upstream |
| 15 | + `docling-project/docling.rs`; `artiz/docling.rs` is their working fork). |
| 16 | +- One feature = one branch off fresh `origin/master`. Don't stack unrelated |
| 17 | + work. |
| 18 | +- Issue numbers (`#80`, `#138`, …) refer to `docling-project/docling.rs` |
| 19 | + issues; reference them in commit messages (`Refs #NN`). |
| 20 | +- **Slack notifications** (when the Slack MCP connector is available): post to |
| 21 | + **#claude-code** (channel ID `C0BKAHN0BSM`) when (a) a question blocks the |
| 22 | + work and needs the maintainer's answer, (b) a long task finishes — include |
| 23 | + the outcome and the compare link, (c) idle/bored — the queue is empty; |
| 24 | + suggest what to pick up next. Keep it to these events; don't narrate |
| 25 | + routine progress there. |
| 26 | + |
| 27 | +## Workspace map |
| 28 | + |
| 29 | +| Crate | What it is | |
| 30 | +|---|---| |
| 31 | +| `crates/docling-core` | `DoclingDocument` model, Markdown/JSON/DCLX serializers, `MarkdownStreamer`, chunkers | |
| 32 | +| `crates/docling` | `DocumentConverter` (format routing), declarative backends (`src/backend/`), streaming (`src/stream.rs`), video (`src/video.rs`) | |
| 33 | +| `crates/docling-pdf` | ML pipeline: pdfium + RT-DETR layout + TableFormer + PP-OCRv3 + enrichment (`ml` feature); pure-Rust text-layer path compiles for wasm without it | |
| 34 | +| `crates/docling-asr` | Whisper ASR: symphonia decode (audio + video containers) → log-mel → ONNX encoder/decoder | |
| 35 | +| `crates/docling-cli` | `docling-rs` binary (also `serve` subcommand behind `--features serve`) | |
| 36 | +| `crates/docling-serve` | axum HTTP conversion API (+ Dockerfile with ffmpeg) | |
| 37 | +| `crates/docling-py` / `docling-node` / `docling-wasm` | pyo3 / napi-rs / wasm-bindgen bindings — **excluded from the workspace default-members; py and wasm build from their own directories** | |
| 38 | +| `crates/docling-rag` | RAG subsystem (embedder, store, web UI) | |
| 39 | + |
| 40 | +## Build & test |
| 41 | + |
| 42 | +```bash |
| 43 | +cargo test --lib --tests -p docling-core -p docling -p docling-asr -p docling-serve -p docling-pdf |
| 44 | +cargo clippy --lib --tests --bins <same -p list> # keep it warning-free |
| 45 | +cargo fmt --all |
| 46 | +cargo check -p docling --no-default-features # pdf-text/wasm path |
| 47 | +(cd crates/docling-py && cargo check) # pyo3 binding |
| 48 | +(cd crates/docling-wasm && cargo check) # wasm binding |
| 49 | +``` |
| 50 | + |
| 51 | +- Prefer `--lib --tests` over bare `cargo test`: it skips example binaries, |
| 52 | + each of which statically links onnxruntime (~0.3–5 GB of `target/` churn). |
| 53 | +- **Disk discipline (remote container!):** `target/debug` balloons past 15 GB. |
| 54 | + When "No space left on device" hits, delete `target/debug/examples`, |
| 55 | + `target/debug/incremental`, oldest `target/debug/deps` files — deletes work |
| 56 | + even at 0 free. `CARGO_INCREMENTAL=0` helps. Old rustup toolchains and |
| 57 | + `~/.cargo/registry/cache` are also safe to drop. |
| 58 | +- Tests run with CWD = the crate dir, but shared fixtures and runtime assets |
| 59 | + live at the **repo root**. Resolve fixtures via |
| 60 | + `Path::new(env!("CARGO_MANIFEST_DIR")).join("../..")` and gate asset-needing |
| 61 | + tests with a skip (see `crates/docling/tests/pages.rs::pdfium_ready`, |
| 62 | + `crates/docling/src/video.rs::asr_models_ready`) — CI without models/pdfium |
| 63 | + must stay green. |
| 64 | + |
| 65 | +## Runtime assets & env |
| 66 | + |
| 67 | +- `models/` (repo root): layout, TableFormer, OCR, ASR (`models/asr/`, |
| 68 | + presets in subdirs), enrichment, embedder. `.pdfium/lib/libpdfium.so` for |
| 69 | + page rendering. Fetch: `scripts/install/download_dependencies.sh`. |
| 70 | +- Resolution is CWD-relative with exe-dir fallback; env overrides: |
| 71 | + `PDFIUM_DYNAMIC_LIB_PATH`, `DOCLING_ASR_{ENCODER,DECODER,VOCAB}`, |
| 72 | + `DOCLING_FFMPEG` (video frames — ffmpeg is a runtime binary, never a build |
| 73 | + dep), `DOCLING_RS_PDF_WORKERS/_THREADS/_INTRA`, `DOCLING_RS_FP32`, |
| 74 | + `DOCLING_RS_EP` (GPU execution providers), `DOCLING_RS_ASR_LANG`, |
| 75 | + `DOCLING_CHUNK_TOKENIZER`. |
| 76 | + |
| 77 | +## Conformance & fixtures |
| 78 | + |
| 79 | +- `tests/data/<format>/sources/` + `groundtruth/` (+ `groundtruth_dclx/`, |
| 80 | + `-enriched/`): the corpus mirrored from upstream docling. Declarative |
| 81 | + formats must match Python docling **byte-for-byte**; the ML pipeline is |
| 82 | + pinned by deterministic snapshots (`tests/snapshots/`, |
| 83 | + `scripts/conformance/`, see `docs/PDF_CONFORMANCE.md`). |
| 84 | +- Output-regression suite: `crates/docling/tests/regression.rs` over |
| 85 | + `crates/docling/tests/data`; regenerate intentional changes with |
| 86 | + `DOCLING_RS_REGEN=1`. |
| 87 | +- When touching serializers, keep the streaming and buffered paths |
| 88 | + byte-identical — `MarkdownStreamer` tests assert exactly that. |
| 89 | + |
| 90 | +## Conventions that keep recurring |
| 91 | + |
| 92 | +- Options plumb through **every** surface in one PR: lib builder on |
| 93 | + `DocumentConverter` → CLI flag → serve option (multipart field + JSON body + |
| 94 | + query param) → Python kwarg → Node option struct. Grep `video_frames` or |
| 95 | + `page_range` for the full pattern. |
| 96 | +- Degradation over failure: a missing optional tool/model (ffmpeg, enrichment |
| 97 | + model) warns and degrades; only "nothing convertible at all" errors. |
| 98 | +- Docs live in `README.md` (user-facing) + `docs/MIGRATION.md` (parity table |
| 99 | + with real conformance numbers) — update both with behavior changes; |
| 100 | + `docs/PDF_CONFORMANCE.md` for pipeline/model changes. |
| 101 | +- Rust 1.96, edition 2021, `cargo fmt` + clippy clean; comments explain *why* |
| 102 | + (docling parity, perf tradeoffs), matching the existing dense doc-comment |
| 103 | + style. |
0 commit comments