This is the full developer documentation for Kreuzberg # Kreuzberg > Document intelligence with a high-performance Rust core. Extract text, tables, and metadata from 97+ file formats — with optional OCR — from Python, TypeScript, Rust, Go, Java, C#, and more. Kreuzberg v4 LTS (legacy) This is the long-term-support line for Kreuzberg **v4**. Active development has moved to **[Xberg](https://github.com/xberg-io/xberg)** (v5+). v4 receives LTS fixes until the end of 2026 (best effort). See **[v4 LTS & Migration](/lts/)**. ## Why Kreuzberg [Section titled “Why Kreuzberg”](#why-kreuzberg) High performance Rust core with native PDFium, SIMD optimizations, and full parallelism. Process thousands of documents per minute without a GPU. 97+ file formats PDF, DOCX, XLSX, PPTX, images, HTML, XML, emails, archives, and academic formats — one API handles them all. Multi-engine OCR Tesseract and PaddleOCR work across all language bindings. EasyOCR is available for Python. 12 language bindings Native bindings for Python, TypeScript, Rust, Go, Java, C#, Ruby, PHP, Elixir, R, C, and WebAssembly. Code intelligence Extract functions, classes, imports, symbols, and docstrings from 248 programming languages, with semantic chunking. Flexible deployment Use as a library, CLI tool, REST API server, MCP server, or Docker container. Pick what fits your stack. [See all features →](/features/) ## Language support [Section titled “Language support”](#language-support) Precompiled binaries for Linux (x86\_64 & aarch64), macOS (Apple Silicon), and Windows (x64). | Language | Package | Docs | | ----------------------- | ------------------------------------------ | ------------------------------------------- | | **Python** | `pip install kreuzberg` | [API Reference](/reference/api-python/) | | **TypeScript (Native)** | `npm install @kreuzberg/node` | [API Reference](/reference/api-typescript/) | | **TypeScript (WASM)** | `npm install @kreuzberg/wasm` | [API Reference](/reference/api-wasm/) | | **Rust** | `cargo add kreuzberg` | [API Reference](/reference/api-rust/) | | **Go** | `go get .../kreuzberg-lts/v4` | [API Reference](/reference/api-go/) | | **Java** | Maven Central `dev.kreuzberg:kreuzberg` | [API Reference](/reference/api-java/) | | **C#** | `dotnet add package Kreuzberg` | [API Reference](/reference/api-csharp/) | | **Ruby** | `gem install kreuzberg` | [API Reference](/reference/api-ruby/) | | **PHP** | `composer require kreuzberg/kreuzberg` | [API Reference](/reference/api-php/) | | **Elixir** | `{:kreuzberg, "~> 4.0"}` | [API Reference](/reference/api-elixir/) | | **R** | r-universe `kreuzberg` | [API Reference](/reference/api-r/) | | **C (FFI)** | Shared library + header | [API Reference](/reference/api-c/) | | **CLI** | `brew install kreuzberg-dev/tap/kreuzberg` | [CLI Guide](/cli/usage/) | | **Docker** | `ghcr.io/kreuzberg-dev/kreuzberg-full` | [Docker Guide](/guides/docker/) | Choosing between TypeScript packages **`@kreuzberg/node`** — Use for Node.js servers and CLI tools. Native performance (100% speed). **`@kreuzberg/wasm`** — Use for browsers, Cloudflare Workers, Deno, Bun, and serverless environments (60–80% speed, cross-platform). ## Quick example [Section titled “Quick example”](#quick-example) * Python main.py ```python from kreuzberg import extract_file_sync result = extract_file_sync("document.pdf") print(result.content) ``` * TypeScript index.ts ```typescript import { extractFileSync } from "@kreuzberg/node"; const result = extractFileSync("document.pdf"); console.log(result.content); ``` * Rust src/main.rs ```rust use kreuzberg::{extract_file_sync, ExtractionConfig}; let config = ExtractionConfig::default(); let result = extract_file_sync("document.pdf", None, &config)?; println!("{}", result.content); ``` ## Part of Xberg.io [Section titled “Part of Xberg.io”](#part-of-xbergio) [Xberg](https://github.com/xberg-io/xberg)Document intelligence: text, tables, metadata from 91+ formats with optional OCR. [Xberg Enterprise](https://github.com/xberg-io/xberg-enterprise)Managed extraction API with SDKs, dashboards, and observability. [crawlberg](https://github.com/xberg-io/crawlberg)Web crawling and scraping with HTML→Markdown and headless-Chrome fallback. [html-to-markdown](https://github.com/xberg-io/html-to-markdown)Fast, lossless HTML→Markdown engine. [liter-llm](https://github.com/xberg-io/liter-llm)Universal LLM API client with native bindings for 14 languages and 143 providers. [tree-sitter-language-pack](https://github.com/xberg-io/tree-sitter-language-pack)Tree-sitter grammars and code-intelligence primitives. [alef](https://github.com/xberg-io/alef)The polyglot binding generator that produces every per-language binding across the 5 polyglot repos. ## Explore the docs [Section titled “Explore the docs”](#explore-the-docs) [Get Started](/getting-started/quickstart/)Install Kreuzberg and extract your first document in minutes. [Guides](/guides/extraction/)Configuration, OCR setup, Docker deployment, plugins, and more. [Concepts](/concepts/architecture/)Architecture, the extraction pipeline, MIME detection, and the plugin system. [Reference](/reference/api-python/)Per-language API docs, the configuration schema, type catalogue, and error matrix. [CLI & Servers](/cli/usage/)The Kreuzberg CLI, REST API server, and MCP server for AI agents. [v4 LTS & Migration](/lts/)The v4 support policy and how to migrate to Xberg (v5+). ## Getting help [Section titled “Getting help”](#getting-help) * **Bugs & feature requests** — [Open an issue on GitHub](https://github.com/kreuzberg-dev/kreuzberg-lts/issues) * **Community chat** — [Join the Discord](https://discord.gg/xt9WY3GnKR) * **Contributing** — [Read the contributor guide](/contributing/) # Changelog > Release history for Kreuzberg v4 LTS. All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). *** ## \[4.10.3] - 2026-09-05 [Section titled “\[4.10.3\] - 2026-09-05”](#4103---2026-09-05) ### Fixed [Section titled “Fixed”](#fixed) * **Legacy DOC piece-table lookup** now reads `fcClx`/`lcbClx` from the correct FIB pair, preventing compressed Windows-1252 text from falling back to UTF-16LE contiguous decoding. Thanks to [@NiekNijland](https://github.com/NiekNijland). * **The crate builds again from a fresh dependency resolution.** `ort` 2.0.0-rc.13 and `quick-xml` 0.42 were published after 4.10.2, and both are reachable through the caret requirements 4.10.2 shipped with. rc.13 moved the execution-provider re-exports behind per-provider cargo features, and quick-xml 0.42 changed its names API from bytes to `&str`; either one fails to compile against 4.10.2’s source. Both are now pinned exactly (`=2.0.0-rc.12`, `=0.41.0`), so a fresh `cargo add kreuzberg` resolves to a combination that builds. * **`tree-sitter-language-pack` 1.16 compatibility.** `ProcessConfig` gained `max_source_bytes` and `parse_timeout_ms`; both are left unset, preserving the previous unbounded, untimed behaviour. ### Changed [Section titled “Changed”](#changed) * Dependency refresh across every language package, including `liter-llm` 1.9 to 1.19, `html-to-markdown-rs` 3.8.3 to 3.12.0, `rmcp` 2.2 to 3.2, `base64` 0.22 to 0.23, and `tree-sitter-language-pack` 1.12.5 to 1.16.1. * `liter-llm`’s `tracing` feature is no longer requested: as of 1.19 tracing is a mandatory dependency of that crate, so the feature no longer exists. Tracing output is unaffected. ## \[4.10.0] - 2026-07-11 [Section titled “\[4.10.0\] - 2026-07-11”](#4100---2026-07-11) First release of the standalone **Kreuzberg v4 LTS** line. This is the long-term-support home for Kreuzberg v4; active development continues as [Xberg](https://github.com/xberg-io/xberg) (v5+). No behavioural changes to extraction — this release is a security, licensing, and packaging refresh. ### Security [Section titled “Security”](#security) * Upgraded core dependencies to their latest patched releases (`hf-hub`, `rmcp`, `lopdf`, `liter-llm`, `pyo3`, `comrak`, `calamine`, `quick-xml`, `text-splitter`, `tower-http`, and others). ### Changed [Section titled “Changed”](#changed-1) * **License is now MIT** (earlier v4 releases shipped under the Elastic License 2.0). * Repository moved to standalone **[`kreuzberg-dev/kreuzberg-lts`](https://github.com/kreuzberg-dev/kreuzberg-lts)**. New v4 Go releases publish under `github.com/kreuzberg-dev/kreuzberg-lts/v4`; existing `github.com/kreuzberg-dev/kreuzberg` pins keep resolving via the Go module proxy cache. ### Added [Section titled “Added”](#added) * LTS support policy and migration guide at [docs.kreuzberg.dev/lts](https://docs.kreuzberg.dev/lts/): v4 receives critical bug and security fixes until the end of 2026 on a best-effort basis. The **R binding remains exclusive to the v4 LTS line** (not part of Xberg v5). ## \[4.9.9] - 2026-06-05 [Section titled “\[4.9.9\] - 2026-06-05”](#499---2026-06-05) LTS patch release with PDF/OCR robustness fixes and selected stability backports from main. ### Fixed [Section titled “Fixed”](#fixed-1) * **OCR on wide, vector-heavy single-page PDFs**: uses a bounded render profile and retries at a lower cap instead of failing extraction with `PdfiumLibraryInternalError(Unknown)`. * **Embedded PDF image OCR**: unsupported image streams are re-extracted through Pdfium or skipped with a specific warning instead of repeated `image dimension probe failed` noise. * **RTF/MSG decompression**: cap the initial allocation hint so a crafted stream cannot request a multi-gigabyte allocation from an untrusted size header. * **Table row sorting** is now NaN-safe (no longer panics). * **FFI embedding preset symbols** are exported even when embeddings are disabled, preventing Java/native binding startup from failing with missing symbols. * **Chunking** now uses formatted content for non-plain output formats, preserves page metadata, and normalizes trailing-space page artifacts before boundary matching. * **UTF-16 email transcoding**: short binary inputs are no longer misclassified as UTF-16. * Returns a validation error when `extraction_timeout_secs` is set without `tokio-runtime`. ## \[4.9.8] - 2026-05-17 [Section titled “\[4.9.8\] - 2026-05-17”](#498---2026-05-17) LTS patch release. Four targeted bug fixes plus dependency pinning so the branch builds against current crates.io releases. ### Fixed [Section titled “Fixed”](#fixed-2) * **RTF hex escapes** now honor `\ansicpgNNNN`, so CP1251 Cyrillic decodes as readable text instead of Windows-1252 mojibake. * **Python `ExtractionConfig(cancel_token=…)`** no longer raises `TypeError`; the kwarg is accepted and threaded through to the underlying cancellation token. * **C# `OcrConfig`** gains the missing `VlmConfig` property and the previously-undefined `LlmConfig` type (`Model`, `ApiKey`, `BaseUrl`, `TimeoutSecs`, `MaxRetries`, `Temperature`, `MaxTokens`). * **musl CLI tarball** now bundles all transitive ONNX Runtime deps, fixing startup failure on any host. * **Build compatibility**: pinned `tokenizers` and `v_htmlescape` to versions compatible with the current API. ## \[4.9.7] - 2026-05-08 [Section titled “\[4.9.7\] - 2026-05-08”](#497---2026-05-08) LTS patch release. Publish-pipeline fixes only — no library code changes. * Maintenance release (internal changes only). ## \[4.9.6] - 2026-05-07 [Section titled “\[4.9.6\] - 2026-05-07”](#496---2026-05-07) LTS patch release. Bug fixes backported from `main` (v5 development). The `chore/v4.9-lts` branch is now the long-lived line for the 4.9.x series. ### Fixed [Section titled “Fixed”](#fixed-3) * **`max_images_per_page` cap** is now enforced in image extraction itself — previously PDFs with thousands of image objects per page hung indefinitely. Image decoding also moved off the async executor so `extraction_timeout_secs` can fire while images are processing. * **OCR elements** are now propagated through the extraction pipeline. * **`extraction_timeout_secs`** is now enforced in single-file extraction paths (previously only multi-file batch flows). * **PDF image data** no longer leaks into structured output when image extraction is disabled. * **Preset-only chunking config** no longer auto-injects an unwanted `EmbeddingConfig` on every chunk. * **PDF heading and image-placeholder classification** corrected. * On the **WASM target**, OCR PSM now defaults to `SINGLE_BLOCK` (native default unchanged). * **`HwpExtractor`** no longer claims the `application/haansofthwpx` MIME type (that format is ZIP-based XML, not CFB-based HWP). * **Email HTML body fallback**: HTML-only emails that the mail parser failed to surface now return content instead of empty output. * **Image decode pixel cap**: attacker-controlled image bytes above 64 MP are rejected with a clean error instead of triggering multi-GB allocations. * **CLI `--log-level`** no longer panics on malformed input (falls back to `info`). * **Markdown rendering**: collapse runs of 3+ consecutive newlines to exactly 2. * **MCP `file_configs` schema**: emits a schema form accepted by Moonshot AI / Kimi. ### API surface [Section titled “API surface”](#api-surface) * `extract_images_from_pdf`, `extract_images_from_pdf_with_password`, and `PdfImageExtractor::{extract_images, get_image_count, extract_images_from_page}` gain a required `max_images_per_page: Option` parameter. Pass `None` to preserve previous unbounded behaviour. ### Not backported from main [Section titled “Not backported from main”](#not-backported-from-main) The following fixes on `main` could not be applied to v4.9.x because they build on v5 architecture: * \#834 (DOCX `inject_placeholders`/OCR pipeline integration). * \#799 (Form XObject image extraction). * \#824 (image extraction across XObject references). *** ## \[4.9.5] - 2026-04-23 [Section titled “\[4.9.5\] - 2026-04-23”](#495---2026-04-23) ### Fixed [Section titled “Fixed”](#fixed-4) * **GPU acceleration**: kreuzberg now bundles CPU-only ONNX Runtime by default. When a GPU execution provider (`cuda`, `tensorrt`, `coreml`) is explicitly requested but unavailable, it returns an error with setup instructions instead of silently using CPU; `Auto` mode falls back to CPU with an info log. For GPU support, set `ORT_DYLIB_PATH` to a GPU-enabled ONNX Runtime. * **DOCX OCR extraction**: OCR now runs on embedded images and its text is injected into rendered output, instead of being discarded and replaced with placeholder text. * **PaddleOCR GPU (CUDA)**: `AccelerationConfig` is now propagated to all PaddleOCR ONNX sessions instead of silently falling back to CPU. * **`PaddleOcrConfig`** is now exposed in Python bindings (with `OcrConfig` backward compatibility). * **Ruby gem packaging**: excludes staged `libpdfium.dylib` from gem artifacts. *** ## \[4.9.2] - 2026-04-19 [Section titled “\[4.9.2\] - 2026-04-19”](#492---2026-04-19) ### Fixed [Section titled “Fixed”](#fixed-5) * Cancellation token is now checked in the WASM (non-tokio) path for Excel, DOC, PPT, Pages, Keynote, and Numbers extractors — cancellation was previously silently ignored in WASM builds. * Propagate the `Cancelled` error code (9) to all bindings (Go, C FFI, Python, TypeScript). *** ## \[4.9.1] - 2026-04-19 [Section titled “\[4.9.1\] - 2026-04-19”](#491---2026-04-19) ### Fixed [Section titled “Fixed”](#fixed-6) * Preserve the `_internal_bindings.pyi` type stub during wheel cleanup — published wheels now include inline type information for the core binding module. *** ## \[4.9.0] - 2026-04-18 [Section titled “\[4.9.0\] - 2026-04-18”](#490---2026-04-18) ### Fixed [Section titled “Fixed”](#fixed-7) * Suppress C23 glibc symbols in manylinux wheels to prevent incompatible symbols on glibc < 2.38 (Debian 12, Ubuntu 22.04). * Remove `kreuzberg-cli` from the Python wheel to fix `libonnxruntime.so.1` loading failure — the CLI is available as a standalone release. * **Cancellation token support**: cancelled extractions no longer block subsequent calls; wired across Python, Node.js, Ruby, WASM, and C FFI. * Fix `kreuzberg[easyocr]` extra silently installing nothing on Python 3.14+. * Fix \~1000x slowdown on Ghostscript-produced PDFs with structured output. * Fix `llm_usage` returning `None` when using VLM-based OCR. ### Added [Section titled “Added”](#added-1) * Cancellation token API available in all language bindings (`CancellationToken` in Python/Node/Ruby/WASM/FFI). ### Changed [Section titled “Changed”](#changed-2) * **Breaking**: `kreuzberg-cli` binary is no longer bundled in the Python wheel — install the standalone CLI from GitHub releases. *** ## \[4.9.4] - 2026-04-22 [Section titled “\[4.9.4\] - 2026-04-22”](#494---2026-04-22) ### Fixed [Section titled “Fixed”](#fixed-8) * **Ruby gem build failure** — missing `max_images_per_page` field in `ImageExtractionConfig` caused a compilation error on all platforms. * **PaddleOCR GPU (CUDA)**: now correctly used when `AccelerationConfig(provider="cuda")` is set — previously the execution provider was never applied and it silently fell back to CPU. *** ## \[4.9.3] - 2026-04-22 [Section titled “\[4.9.3\] - 2026-04-22”](#493---2026-04-22) ### Added [Section titled “Added”](#added-2) * **Layout detection regions on `PageContent`** — new `layout_regions` field exposes detected layout regions (class, confidence, bounding box, area fraction) from the RT-DETR model, enabling programmatic detection of diagrams, figures, tables, and other content types per page. Available across all 10 bindings. ### Fixed [Section titled “Fixed”](#fixed-9) * **`PaddleOcrConfig` in Python API**: exposed as a first-class class; `OcrConfig` accepts both objects and raw dictionaries. * **DOCX page extraction (`extract_pages=True`)**: `result.pages` and `get_page_count()` now work correctly instead of always returning `None`/`0`. (Tables spanning multiple pages remain a known limitation.) * **`serve`/`mcp` CLI subcommands** now apply `KREUZBERG_*` environment overrides (previously only `extract` honoured them). `MISTRAL_API_KEY` is now picked up for bare `mistral-*` model names. * **Tagged-PDF structure tree** no longer drops paragraph body text when a block has both text and children, and no longer emits malformed markdown for numbered section headings. * **Semantic chunker fallback** now respects `max_characters` instead of a hardcoded 4000-char ceiling; warns when `chunker_type='semantic'` is used without an `EmbeddingConfig`. * **OCR backend dispatch**: a non-default backend that errors no longer silently falls back to paddleocr; auto-fallback is limited to the default tesseract backend. * **EasyOCR on PDFs**: Rust’s renderer now handles page rendering, removing the implicit `pdf2image`/`pymupdf` requirement that was never declared in the `[easyocr]` extra. * **`OcrConfig.vlm_prompt`** is now honored in VLM OCR requests (previously documented but never forwarded). * **PDF image links** are no longer silently dropped from markdown output; respects `inject_placeholders`. * **PDF with large numbers of image fragments** no longer hangs — added `ImageExtractionConfig.max_images_per_page` (default `None`) and honored `extraction_timeout_secs` at inter-page checkpoints. * **PST extractor** now populates email attachments (name, filename, MIME type, size, data); entry IDs formatted as proper MAPI hex strings. ### Added [Section titled “Added”](#added-3) * `ImageExtractionConfig.max_images_per_page` — optional cap on images decoded per page; prevents hangs on PDFs with thousands of inline image fragments. *** ## \[4.8.6] - 2026-04-17 [Section titled “\[4.8.6\] - 2026-04-17”](#486---2026-04-17) ### Added [Section titled “Added”](#added-4) * **PST message EntryID in metadata** — the `entry_id` field from Outlook PST message entries is now included in the `metadata` of `EmailExtractionResult`, letting callers link extracted data back to its source message. * **AccelerationConfig wired through all ORT model loading** — CUDA/CoreML/TensorRT/Auto acceleration is now propagated to all ONNX Runtime sessions (layout detection, embeddings, document orientation, PaddleOCR); previously GPU acceleration was silently ignored. The `acceleration` field is added to `LayoutDetectionConfig` and `EmbeddingConfig` across all 11 bindings. * **Semantic chunker** (`ChunkerType::Semantic`) for topic-aware document splitting, with a `topic_threshold` config field. ### Fixed [Section titled “Fixed”](#fixed-10) * **Batch extraction crash on ARM64 Linux** (“Lazy instance has previously been poisoned”) — OCR backend init failures no longer poison a shared static and cascade to all concurrent batch tasks. * **PaddleOCR `model_tier` from TOML ignored by API server** — per-request `model_tier` is now honored. * **VLM OCR backend ignored when paddle-ocr feature enabled** — `vlm_config` is now propagated so configured VLM OCR is actually used. * **Doubled OCR content and corrupted page text in image extraction** — OCR content is no longer duplicated word-by-word into `content`/`pages`. * **Image OCR `pages[]` empty** — element output is now forced on for image extraction. * **`LlmConfig` missing `Default`** — the documented `..Default::default()` pattern now compiles. * **LLM embedding provider panics in server mode** — embedding no longer panics when called inside an existing tokio runtime (HTTP/MCP server). * **OCR table metadata serialized as strings instead of numbers** (`table_count`, `tables_detected`, `table_rows`, `table_cols`), which broke numeric comparisons in all bindings; also fixed a duplicate `output_format` metadata key. * **Ruby `structured_output`** was missing from the `Result` class and not serialized. * **DOCX tables assigned wrong page numbers** — now numbered by actual document position. * **`ocr.enabled=false` ignored** — OCR no longer runs when explicitly disabled; also fixed a dropped trailing newline in `--format text` output. ### Changed [Section titled “Changed”](#changed-3) * Updated dependencies including html-to-markdown-rs 3.1→3.2 and tokio 1.51→1.52. *** ## [4.8.5](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.8.5) - 2026-04-14 [Section titled “4.8.5 - 2026-04-14”](#485---2026-04-14) ### Added [Section titled “Added”](#added-5) * **LLM usage tracking** — new `llm_usage` field on `ExtractionResult` captures token counts, estimated cost (USD), model identifier, and finish reason for every LLM call (VLM OCR, structured extraction, LLM embeddings). Exposed across all bindings. ### Fixed [Section titled “Fixed”](#fixed-11) * **Markdown chunker** no longer duplicates a heading when `prepend_heading_context` is enabled and a chunk boundary aligns with a heading. * **Python wheel requires glibc ≥ 2.38 (breaks Debian 12, Ubuntu 22.04)** — downgraded to `manylinux_2_28` and suppressed C23 glibc symbol emission so wheels install on systems with glibc < 2.38. * **FFI memory leak** — `kreuzberg_free_result` now frees `djot_content_json`, `structured_output_json`, and `llm_usage_json`. *** ## [4.8.4](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.8.4) - 2026-04-13 [Section titled “4.8.4 - 2026-04-13”](#484---2026-04-13) ### Added [Section titled “Added”](#added-6) * **Helm chart for Kubernetes deployment** — minimal, security-hardened chart (Deployment, Service, Ingress, PVC, HPA, PDB, ServiceAccount), published to GHCR as an OCI artifact. ### Fixed [Section titled “Fixed”](#fixed-12) * **Comrak bridge panic on multi-byte UTF-8 boundaries** — annotation offsets landing inside multi-byte characters (e.g. Cyrillic) no longer cause panics. *** ## [4.8.3](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.8.3) - 2026-04-12 [Section titled “4.8.3 - 2026-04-12”](#483---2026-04-12) ### Fixed [Section titled “Fixed”](#fixed-13) * **ONNX session creation fails on Linux x86-64** (“graph\_optimization\_level is not valid”) — the Linux wheel bundled an incompatible ORT version. Switched to a portable optimization level and aligned all ORT versions to 1.24.2. ### Documentation [Section titled “Documentation”](#documentation) * **Documented AVX/AVX2 CPU requirement for ONNX Runtime features** — CPUs without AVX (e.g. Intel Atom, Celeron N5105) cannot use PaddleOCR, layout detection, or embeddings. *** ## [4.8.2](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.8.2) - 2026-04-10 [Section titled “4.8.2 - 2026-04-10”](#482---2026-04-10) ### Added [Section titled “Added”](#added-7) * **`HtmlOutputConfig` typed in all bindings** — the `html_output` config field (themes, CSS classes, embed CSS, custom CSS, class prefix) is now fully typed in Python, TypeScript/Node, Go, Ruby, Elixir, PHP, Java, C#, R, and FFI (previously Rust-only). ### Fixed [Section titled “Fixed”](#fixed-14) * **PDF: legitimate repeated content stripped regardless of `strip_repeating_text`** — page-merge deduplication ran unconditionally, removing legitimately repeated brand names and other content even when content filtering was disabled. Both dedup passes are now gated behind the flag. *** ## [4.8.1](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.8.1) - 2026-04-09 [Section titled “4.8.1 - 2026-04-09”](#481---2026-04-09) ### Added [Section titled “Added”](#added-8) * **Styled HTML output** — new `HtmlOutputConfig` on `ExtractionConfig` with 5 built-in themes (`default`, `github`, `dark`, `light`, `unstyled`), semantic `kb-*` CSS class hooks, CSS custom properties, custom CSS injection, and configurable class prefix. The existing `Html` output format is upgraded in-place when `html_output` is set. * 5 new CLI flags: `--html-theme`, `--html-css`, `--html-css-file`, `--html-class-prefix`, `--html-no-embed-css` — any implicitly sets `--content-format html`. ### Changed [Section titled “Changed”](#changed-4) * **Vendored yake-rust 1.0.3** into core — fixes a `BacktrackLimitExceeded` panic on large files (10+ MB) and expands YAKE stopwords from 34 to 64 languages. ### Fixed [Section titled “Fixed”](#fixed-15) * **PPTX**: panic on non-char-boundary during page boundary recomputation (multi-byte UTF-8 characters). * **PDF**: `include_headers`/`include_footers` flags were ignored by layout-model furniture stripping; they now correctly preserve those regions. * **PDF**: heuristic table detector no longer misclassifies body text as tables on slide-like PDFs (rejects ≤3-row tables spanning >50% of page height). * **PPTX/DOCX/HTML/DocBook/LaTeX/RST**: `ImageExtractionConfig.inject_placeholders=false` now correctly suppresses image references. *** ## [4.8.0](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.8.0) - 2026-04-08 [Section titled “4.8.0 - 2026-04-08”](#480---2026-04-08) ### Added [Section titled “Added”](#added-9) * **Cross-extractor content filtering** — new `ContentFilterConfig` on `ExtractionConfig` with `include_headers`, `include_footers`, `strip_repeating_text`, and `include_watermarks` flags across PDF, DOCX, RTF, ODT, HTML, EPUB, and PPT extractors. Typed in all bindings. * **Local LLM support** via liter-llm 1.2 — use Ollama, LM Studio, vLLM, llama.cpp, LocalAI, or llamafile as VLM OCR, embedding, or structured-extraction backends with zero API key configuration. * **LLM-powered document intelligence** — integrates with 146 LLM providers for three capabilities: **VLM OCR** (vision models as OCR backend for low-quality scans, handwriting, Arabic/Farsi, complex layouts, via `ocr.backend = "vlm"`), **structured extraction** (JSON-schema-constrained extraction), and **VLM embeddings** (provider-hosted embedding models). * **New CLI command** `kreuzberg extract-structured`, **API endpoint** `POST /extract-structured`, and **MCP tool** `extract_structured` for schema-guided LLM extraction. * **Minijinja template engine** for customizable LLM prompts. * **5 new environment variables**: `KREUZBERG_LLM_MODEL`, `KREUZBERG_LLM_API_KEY`, `KREUZBERG_LLM_BASE_URL`, `KREUZBERG_VLM_OCR_MODEL`, `KREUZBERG_VLM_EMBEDDING_MODEL`. * `LlmConfig` and `StructuredExtractionConfig` types, `structured_output` field on `ExtractionResult`, and `EmbeddingModelType::Llm` variant across bindings. * **Standalone text embedding API** with `/embed` endpoint, `embed_text` MCP tool, and `embed` CLI command. ### Changed [Section titled “Changed”](#changed-5) * **License changed from MIT to Elastic License 2.0 (ELv2)** — copyright holder changed to Kreuzberg, Inc. Forked crates retain their original MIT licenses. * API returns 501 Not Implemented (instead of 500) when the liter-llm feature is disabled. * JSON schema `additionalProperties` automatically stripped for non-OpenAI providers. ### Fixed [Section titled “Fixed”](#fixed-16) * **PDF: brand names stripped by repeating-text detection** — `strip_repeating_text = false` now disables the removal that incorrectly stripped brand names from PowerPoint-exported decks. * **PPTX: slide order scrambled for decks with 10+ slides** — fixed lexicographic sort (`slide10.xml` before `slide2.xml`) to use numeric ordering. * **UTF-8 panic in arXiv watermark stripping** when a multi-byte character spans the search limit. * **DOC: garbled text from old Word files** — CP1252 text misread as UTF-16LE; added heuristic to detect and re-decode. * **WASM: table extraction returns empty array** when `pageNumber` is null (now defaults to page 0). *** ## [4.7.4](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.4) - 2026-04-06 [Section titled “4.7.4 - 2026-04-06”](#474---2026-04-06) ### Added [Section titled “Added”](#added-10) * Re-added the `--layout` boolean CLI flag for easy layout detection enablement (`--layout` to enable with model defaults, `--layout false` to disable). * arXiv watermark/sidebar noise filtering for academic PDFs. * Second-tier cross-page repeating-text detection for conference headers and journal running titles outside the margin zone. * Figure/picture text suppression — text inside layout-detected Picture regions is excluded from body output. ### Fixed [Section titled “Fixed”](#fixed-17) * **Figure-internal text leaking into body output** — diagram labels and axis text are no longer included (sometimes promoted to headings) in extracted body content. * **Empty image references in PDF markdown/HTML output** — PDFs with embedded images no longer produce empty `![]()` / ``; actual image pixel data is now extracted, producing proper `![](image_N.png)` references. * **WASM build failure with `extern "C-unwind"`** — added a macro that uses `extern "C-unwind"` natively and `extern "C"` on WASM. * **Go module tag format** — tags now use the correct `packages/go/v4/vX.Y.Z` format matching the module path. ### Changed [Section titled “Changed”](#changed-6) * CLI documentation updated with missing extraction override flags (`--layout-table-model`, `--disable-ocr`, `--cache-namespace`, `--cache-ttl-secs`). *** ## [4.7.3](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.3) - 2026-04-05 [Section titled “4.7.3 - 2026-04-05”](#473---2026-04-05) ### Fixed [Section titled “Fixed”](#fixed-18) * **Archive extraction SIGBUS crash on macOS ARM64** — ZIP, 7Z, TAR, and GZIP extraction crashed in release builds due to miscompilation under `opt-level=3`; reduced to level 2 for the affected crates. * **Native-text PDF extraction fails when OCR backend unavailable** — PDFs with extractable native text no longer hard-fail with `All OCR pipeline backends failed`; the OCR quality-enhancement pass now falls back to the native result with a warning. * **Rust cannot catch foreign exceptions crash** — C++ exceptions from Tesseract or Leptonica (e.g. on corrupted images) no longer abort the process; they now unwind safely and convert to recoverable errors. *** ## [4.7.2](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.2) - 2026-04-04 [Section titled “4.7.2 - 2026-04-04”](#472---2026-04-04) ### Changed [Section titled “Changed”](#changed-7) * **Global model cache** — models now download to a platform-appropriate global cache (`~/.cache/kreuzberg/` on Linux, `~/Library/Caches/kreuzberg/` on macOS, `%LOCALAPPDATA%/kreuzberg/` on Windows) instead of per-directory `.kreuzberg/` folders. Override with `KREUZBERG_CACHE_DIR`. ### Fixed [Section titled “Fixed”](#fixed-19) * **Embedded HTML in PDF text layers** — raw HTML in a PDF text layer (`

`, `
`, ``) that previously produced escaped garbage is now converted to clean markdown. * **Code classification false positives** — regular prose is no longer misclassified as Code blocks. * **PageBreak rendering as `-----` separators** — PageBreak elements no longer pollute output with `-----` / `


`; treated as structural metadata. * **Leptonica DPI crash** — images with 0 DPI no longer trigger an uncatchable C++ exception; DPI is validated and fixed to 72 before preprocessing. * **Node.js `ExtractionResult.children` missing at runtime** in the published v4.7.1 binary. * **Node.js `disable_ocr` config not respected** — `disableOcr: true` no longer produces OCR content for images. * **PaddleOCR angle classification crash** — fixed input dimensions to match the v2 angle classifier model. * **Chunk page numbers missing** — chunks produced with `first_page`/`last_page` null when chunking was configured without explicit `pages` config; page tracking is now auto-enabled. *** ## [4.7.1](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.1) - 2026-04-03 [Section titled “4.7.1 - 2026-04-03”](#471---2026-04-03) ### Added [Section titled “Added”](#added-11) * **Tree-sitter grammar management CLI** — new `kreuzberg tree-sitter` subcommand with `download`, `list`, `cache-dir`, and `clean` for managing grammar parsers (by language, group, or all); reads `[tree_sitter]` config from `kreuzberg.toml`. * **Tree-sitter grammar management API** — new REST endpoints `POST /grammars/download`, `GET /grammars/list`, `GET /grammars/cache`, `DELETE /grammars/cache`. * **Tree-sitter grammar management MCP tools** — `download_grammars`, `list_grammars`, `grammar_cache_info`, `clean_grammar_cache`. * **Tree-sitter config startup initialization** — API and MCP servers auto-download grammars on startup when `[tree_sitter]` specifies `languages` or `groups`. ### Changed [Section titled “Changed”](#changed-8) * **Normalized OCR+layout pipeline** — the Tesseract+layout path now follows the same architecture as pdfium+layout, fixing destroyed paragraph structure and reading order. * **Elixir NIF crash protection** — extraction and batch NIFs are wrapped so native-library panics (pdfium, tesseract) return `{:error, reason}` instead of crashing the BEAM VM. ### Fixed [Section titled “Fixed”](#fixed-20) * **hOCR parser depth tracking** — content after inner word spans is no longer silently dropped due to premature paragraph termination. * **hOCR multi-page content loss** — content on pages 2+ is no longer dropped due to a per-page filter on per-page hOCR documents. * **OCR batch parallelization** — page processing now scales with available CPUs (capped at 8) instead of a hardcoded 4, speeding up multi-page documents. * **Chunking page boundary regression** — page boundaries are recomputed from rendered per-page content, fixing null `first_page`/`last_page` and a validation warning. * **HF Hub environment variables** — respects `HF_HOME`/`HF_ENDPOINT`, fixing permission errors on Kubernetes when running as non-root. * **PDF bridge tracing panic on multibyte characters** — no longer panics on multibyte UTF-8 (e.g. `•`). * **Go FFI struct layout** — vendored C header was missing `children_json`, shifting all subsequent fields and reading wrong memory. * **Java FFI struct layout** — `CExtractionResult` was missing `code_intelligence_json`, causing all Java extractions to return `success=false`. * **PHP `__get` magic method bypass** — `elements`, `djotContent`, `document`, `ocrElements`, `children`, and `uris` returned raw JSON strings instead of deserialized arrays. * **Ruby `disable_ocr` config** — the keyword was not parsed, so OCR ran even when explicitly disabled. * **Node.js `ExtractionResult` parity** — `document`, `djotContent`, and `ocrElements` were omitted from JS objects when `None`; now default to `null`. * **Node.js `convertChunk` missing `chunkType`** — the converter did not forward `chunk_type`. * **ODT caption text extraction** — text inside `draw:text-box` (e.g. image captions) was not extracted. * **Italian/European PDF ligature corruption** — repairs `tt`, `ti`, `tti` ligatures (e.g. `Dire*ore` → `Direttore`). * **WASM Rayon thread pool panic** — parallel iteration now falls back to sequential on `wasm32` instead of panicking. *** ## [4.7.0](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.0) - 2026-03-30 [Section titled “4.7.0 - 2026-03-30”](#470---2026-03-30) ### Added [Section titled “Added”](#added-12) * **Semantic chunk labeling**: chunks now include a `chunk_type` field identifying the semantic nature of the content (e.g. `paragraph`, `heading`, `list_item`, `table_cell`, `code_block`), across all 11 language bindings. * **Image extraction across 8 formats**: embedded images extracted as `ExtractedImage` (binary data, format, dimensions, alt text) for DOCX, PPTX, PDF, EPUB, ODT, HTML, RTF, and Markdown/MDX/Jupyter. Markdown output renders as `![alt](image_N.ext)` with binary data in `ExtractionResult.images`. * **Recursive OCR on embedded images**: extracted images from EPUB, ODT, HTML, and RTF are OCR’d, producing nested `ExtractionResult` in `ExtractedImage.ocr_result`. * **PDF watermark artifact filtering** using pdfium’s `/Artifact` content marks. * **Vertical table header reconstruction**: fixes rotated PDF table column headers extracted as reversed spaced characters. * **Pages API for PDF extraction**: per-page content is now available via `result.pages` for PDF documents. * **TOON wire format**: token-efficient (\~30-50% fewer tokens) JSON alternative across CLI (`--format toon`), API (`Accept: application/toon`), MCP (`response_format: "toon"`), and all 11 language bindings; losslessly convertible to/from JSON. * **Renderer registry**: trait-based `Renderer`/`RendererRegistry` lets external crates register custom output-format plugins via `register_renderer()`. * **URI extraction**: new `Uri` type with `UriKind` classification (Hyperlink, Image, Anchor, Citation, Reference, Email) extracted from 20+ formats, deduplicated, in `ExtractionResult.uris`. * **Recursive email attachment extraction**: EML/MSG/PST attachments and nested `message/rfc822` parts extracted as `ArchiveEntry` children, respecting `max_archive_depth`. * **PDF embedded file extraction**: PDF file attachments (portfolios) extracted as children (with filename sanitization, size limits, depth guards). * **PDF bookmark/outline extraction**: document outlines extracted as URIs (page destinations as anchors, external links as hyperlinks). * **DOCX/PPTX embedded object extraction**: OLE objects and embedded files extracted as children. * **PPTX hyperlink extraction** from slide XML, resolved via relationship files. * **Image path resolution for markup formats**: relative image paths in Markdown, MDX, LaTeX, RST, OrgMode, Typst, Djot, and DocBook are resolved from the filesystem (with path-traversal prevention) and extracted. * **FictionBook image and link extraction** (base64 `` images and `` hyperlinks). * **Apple iWork improvements**: Numbers outputs tables, Keynote has improved slide structure, Pages has heading detection; all three extract metadata. * **`code_intelligence` field on `ExtractionResult`**: top-level access to tree-sitter results (structure, imports, exports, chunks, symbols, diagnostics, docstrings). * **`CodeContentMode` config**: control code extraction mode — `chunks` (default), `raw`, or `structure`. * **TSLP semantic chunking for code**: code files use function/class-aware chunks with semantic types and heading context. ### Code Intelligence [Section titled “Code Intelligence”](#code-intelligence) * **Tree-sitter integration** for 248 programming languages: extract functions, classes, imports, exports, symbols, docstrings, diagnostics; syntax-aware chunking; language detection from extension/shebang; dynamic grammar download (native) / 30-language static subset (WASM); new `tree-sitter` and `tree-sitter-wasm` feature flags (in `full` and `wasm-target`); `TreeSitterConfig`/`TreeSitterProcessConfig` in `ExtractionConfig`. ### Typed Metadata [Section titled “Typed Metadata”](#typed-metadata) * New `FormatMetadata` variants: `Code`, `Csv`, `Bibtex`, `Citation`, `FictionBook`, `Dbf`, `Jats`, `Epub`, `Pst`; `PptxMetadata` extended with `image_count`/`table_count`; typed fields across all 11 bindings. ### Breaking Changes [Section titled “Breaking Changes”](#breaking-changes) * **Layout detection preset removed**: the `preset` field on `LayoutDetectionConfig` and the `--layout-preset` CLI flag are removed; layout detection now uses the RT-DETR v2 model unconditionally. Old configs with `"preset"` are silently ignored. * **Table model config typed**: `table_model` on `LayoutDetectionConfig` changed from `Option` to a `TableModel` enum (`tatr`, `slanet_wired`, `slanet_wireless`, `slanet_plus`, `slanet_auto`, `disabled`), defaulting to `tatr`. String values still accepted in JSON/TOML. ### Fixed [Section titled “Fixed”](#fixed-21) * **PDF table rendering**: populate `Table.cells` from the TATR/SLANeXT grid so tables render as proper Table nodes. * **LaTeX extraction**: convert `\href`, `\emph`, `\textbf`, `\verb`, `\sout`, blockquotes, lists, special characters, and ligatures to markdown. * **XLSX/XLS**: emit a `## SheetName` heading before each sheet’s table. * **OPML/IPYNB/JATS/RST/ORG headings** improved (outline headings, notebook ATX headings and cell outputs, JATS abstract/references, RST title levels and code-block hints, ORG source/example blocks). * **ODT formula extraction**: embedded MathML formulas extracted as formula content instead of empty image placeholders. * **PPTX slide titles** detected via OOXML placeholder type and emitted as H2 headings; bulleted/numbered lists extracted properly. * **RTF formatting**: bold/italic/strikethrough use exact byte offsets (fixes formatting bleeding across paragraphs); hidden text suppressed; hyperlink parsing, strikethrough, and multi-row table rendering fixed. * **HTML preprocessing**: navigation, forms, and sidebars are now stripped by default, removing page chrome from output. * **PDF table detection**: rejects false tables where >70% of cells are single-word fragments (justified prose). * **DocBook root element handling**: XML fragments without a root element are wrapped automatically. * **PDF image FlateDecode fallback**: images that fail `decode_flate_to_png()` (FlateDecode, CCITT, JBIG2) are re-extracted via pdfium, producing valid PNG instead of unusable bytes. * **Metadata standardization**: PPTX, Excel, ODT, RST, OrgMode, Typst, RTF, JATS, DOC, PPT, HTML, Email, BibTeX, and Citation metadata now map to standard `Metadata` fields (title, authors, dates, keywords, language) instead of only the `additional` map. * **MDX/RST/LaTeX/OrgMode/BibTeX/JATS link, URL, and classification fixes** (heading and list-item links, RST hyperlinks, `\url{}` extraction, more image extensions, correct BibTeX URL classification, JATS title field). * **Tesseract C++ exception crash**: fixed a fatal runtime error where Tesseract C++ exceptions unwound through Rust FFI; Tesseract is now compiled with `-fno-exceptions`. * **`ExtractionConfig` rejects unknown fields**: `deny_unknown_fields` added, so typos/invalid fields (e.g. `layout_analysis`) are no longer silently ignored. * **PPTX markdown mode** derived from `output_format` instead of hardcoded plain text, so tables/lists render correctly. * **DOCX merged cells** (gridSpan/vMerge) repeat content across spans; added `source_path` to `ExtractedImage` for DOCX image paths. * **Python wheel `__isoc23_strtoll` error on older Linux** — downgraded manylinux target to `manylinux_2_28` for glibc < 2.39 compatibility (Ubuntu 20.04/22.04, Debian 11/12). * **Go macOS link failure** — added missing `-framework Foundation` to CGO LDFLAGS for ORT’s CoreML provider. * **Windows GNU ORT linking** — uses dynamic linking with pre-downloaded Microsoft ORT; documented the ONNX Runtime DLL requirement for Go, Elixir, and C/C++ on Windows. ### Changed [Section titled “Changed”](#changed-9) * **PDF text extraction**: full rewrite to `page.text().all()` + char-indexed font metadata, producing cleaner text with correct word spacing. * **CLI format flags**: `--format` (`-f`) now supports `text`, `json`, and `toon`; `--output-format` renamed to `--content-format` (deprecated alias kept with warning). ### Removed [Section titled “Removed”](#removed) * **`max_upload_mb` server config field** and `KREUZBERG_MAX_UPLOAD_SIZE_MB` env var — use `max_multipart_field_bytes` / `KREUZBERG_MAX_MULTIPART_FIELD_BYTES` instead. * **`metadata.additional` legacy insertions**: pipeline features no longer insert error/status keys — errors are in `processing_warnings`, keywords in `extracted_keywords`. *** ## [4.6.3](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.6.3) - 2026-03-27 [Section titled “4.6.3 - 2026-03-27”](#463---2026-03-27) ### Added [Section titled “Added”](#added-13) * **Tower service layer** (`service` module): Composable `ExtractionService` with configurable middleware (tracing, metrics, timeout, concurrency limit) behind a new `tower-service` feature, auto-enabled by `api`/`mcp`. * **Semantic OpenTelemetry conventions**: Formal `kreuzberg.*` attribute namespace with span attributes, metric names, and operation/stage constants for extraction, pipeline, OCR, and model inference telemetry. * **Extraction metrics**: 11 OTel instruments covering extraction totals, durations, cache hits/misses, pipeline stages, OCR, and concurrency (feature-gated behind `otel`). ### Improved [Section titled “Improved”](#improved) * **Deeper instrumentation**: Pipeline post-processing stages, individual processors, OCR, and layout model inference now emit semantic spans and duration metrics. * **API and MCP servers route extractions through the Tower service stack**, gaining unified tracing, metrics, and middleware. * **API server hardening**: Added response compression (gzip/brotli/zstd), panic recovery, request-ID correlation, and sensitive-header redaction. ### Changed [Section titled “Changed”](#changed-10) * **Span attribute names migrated to `kreuzberg.*` namespace** (e.g. `extraction.filename` -> `kreuzberg.document.filename`). ### Fixed [Section titled “Fixed”](#fixed-22) * **EPUB spine handling**: Preserves manifest fallback chains, guide references, and non-linear spine items; strips navigation chrome; malformed guide references now warn instead of hard-failing. * **DOCX images with high-quality settings not extracted**: `` elements with child elements are now handled. * **OCR tables discarded on default output format**: Layout detection was skipped for the `Plain` format, dropping tables from the OCR pipeline; both paths now propagate tables. * **Missing binding fields**: Exposed `chunker_type`, `sizing_cache_dir`, and `prepend_heading_context` across Python, TypeScript/WASM, Go, C#, and PHP. * **Full API parity across all 10 bindings**: Added `max_archive_depth` everywhere, `acceleration`/`email` to Ruby/R, `layout` to PHP, and 7 missing fields to WASM. * **Windows install failure for the Node package**: Replaced bash-specific prepare-script fallback with a cross-platform equivalent. *** ## [4.6.2](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.6.2) - 2026-03-26 [Section titled “4.6.2 - 2026-03-26”](#462---2026-03-26) ### Added [Section titled “Added”](#added-14) * **PDF page rendering API**: New `render_pdf_page` function and `PdfPageIterator` render individual PDF pages as PNG images across all 11 bindings, with idiomatic patterns per language. Default 150 DPI, configurable per call. ### Fixed [Section titled “Fixed”](#fixed-23) * **Zero tables found on scanned PDFs**: Layout bboxes (640x640 model space) are now scaled to OCR render resolution before table recognition. * **OCR elements reported `page_number: 1` for all pages**: Page numbers are now correctly stamped after OCR in the batch loop. * **Ruby gem missing ONNX Runtime**: Added bundled ORT so OCR/layout/embeddings work out of the box. ### Improved [Section titled “Improved”](#improved-1) * **`version:sync` also syncs Go C header, version constant, and Docker tags**, preventing version drift across bindings. *** ## [4.6.1](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.6.1) - 2026-03-25 [Section titled “4.6.1 - 2026-03-25”](#461---2026-03-25) ### Added [Section titled “Added”](#added-15) * **Per-file batch extraction timeouts**: New `extraction_timeout_secs` (batch default) and `timeout_secs` (per-file override), plus a `KreuzbergError::Timeout` variant with elapsed/limit fields. All bindings updated. * **Page-level OCR overrides**: New `force_ocr_pages` (1-indexed) enables selective OCR on specific pages of mixed-quality PDFs while preserving native text on others. * **PST extraction support**: Extract emails from Microsoft Outlook PST archives, feature-gated under `email`. * **JSONL/NDJSON extraction**: Native `.jsonl`/`.ndjson` extraction registered as `application/x-ndjson`. ### Fixed [Section titled “Fixed”](#fixed-24) * **OCR elements now propagated to `ExtractionResult`** with geometry data and coordinate-bearing narrative blocks. * **OOM crash on multi-page scanned PDFs**: PDF pages are now rendered and OCR’d in bounded batches instead of all at once. * **OCR memory usage reduced 60-78%**: One page is rendered and encoded at a time; a 98-page scanned PDF dropped from 4.6GB to 1.9GB peak RSS. Batch size adapts to available memory on Linux/macOS. * **PDF control-character artifacts**: Broken ToUnicode mappings that produced control characters where hyphens belong are fixed (e.g. `re\x02labelling` -> `re-labelling`). * **Missing headings for PDFs**: Heading nodes are now inserted for structured PDFs, and markdown heading markers in fallback paragraphs create heading groups. * **Empty tables on scanned PDFs**: Three bugs that always returned `[]` tables for scanned/image PDFs are fixed so all paths propagate tables. * **Table recognition coordinate mismatch on scanned PDFs**: Bounding boxes are now scaled from layout-model resolution to actual OCR render resolution, fixing zero recognized tables. * **OCR elements reported `page_number: 1` for all pages**: Correct 1-indexed page numbers are now stamped per batch page. * **PDF layout engine crash on malformed input**: Layout-engine init failure now returns a descriptive error instead of crashing the host process via FFI. *** ## [4.6.0](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.6.0) - 2026-03-24 [Section titled “4.6.0 - 2026-03-24”](#460---2026-03-24) ### Added [Section titled “Added”](#added-16) * **Recursive archive extraction**: ZIP/TAR/7Z/GZIP archives now recursively extract every processable file, each with its own `ExtractionResult`. New `ArchiveEntry` type; configurable `max_archive_depth` (default 3, 0 for legacy single-text behavior). * **YAML/JSON section chunker**: New `ChunkerType::Yaml` splits structured files by keys with full hierarchy paths, auto-inferred for YAML/JSON. * **Unified `DocumentStructure` DTO**: 7 new node types, 4 new annotation kinds, and a format-specific `attributes` bag on every node. * **Unified rendering module**: `render_to_markdown()` and `render_to_plain()` walk a `DocumentStructure` tree for consistent output with inline annotations, table escaping, and nested lists. * **DocumentStructure support for all 35 formats**: Every extractor natively produces a `DocumentStructure` when `include_document_structure` is enabled, including Office, markup, books, scientific, data, email, and image formats. * **DocBook/JATS inline annotations**: Semantic emphasis, bold, code, links, and sub/superscript for academic documents. * **Document-level OCR**: `OcrBackend` supports whole-file `process_document()`, up to 30% faster on multi-page documents. ### Changed [Section titled “Changed”](#changed-11) * **CSV extraction for embedding quality**: Emits `Row N: Header: Value` format when a header row is detected; the `tables` field is unchanged. * **XML extraction for embedding quality**: Indented hierarchical output preserving the element tree with inline attributes and `xmlns:*` filtering. ### Improved [Section titled “Improved”](#improved-2) * **Zero-copy file I/O**: Automatic memory-mapping for files >1MB with SIMD-accelerated UTF-8 validation; measurable speedup for large PDFs and archives (WASM falls back to heap allocation). * **Unified concurrency management**: Centralized thread budget for Rayon, ONNX, and PaddleOCR via configurable `ConcurrencyConfig`; PDF OCR batched to reduce memory on large documents. ### Fixed [Section titled “Fixed”](#fixed-25) * **Incorrect page numbers in element-based output**: Element-based output now auto-enables page extraction, fixing all elements reporting `page_number=1`. * **MSG extraction misses compressed RTF bodies**: Added compressed-RTF fallback so `.msg` files that store the body only in compressed RTF are extracted. * **Indexed-colour PDF images returned as raw bytes**: Palette-based PDF images now decode to valid PNG output. * **ODT extraction robustness**: Replaced unwraps with safe fallbacks in ODT parsing. *** ## [4.5.4](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.5.4) - 2026-03-23 [Section titled “4.5.4 - 2026-03-23”](#454---2026-03-23) ### Added [Section titled “Added”](#added-17) * **Document-level OCR optimization**: `OcrBackend` supports native whole-file `process_document()`, avoiding per-page PDF rasterization when the backend supports it. * **PST (Outlook Personal Folders) extraction**: New `PstExtractor` extracts subject, sender, recipients, body, and date from every message, enabled via the `email` feature (MIME `application/vnd.ms-outlook-pst`). * **`prepend_heading_context` chunking option**: When set with the Markdown chunker, prepends the heading hierarchy path to each chunk for self-contained RAG context. Available across all 10 bindings, CLI, and WASM. ### Fixed [Section titled “Fixed”](#fixed-26) * **PDF image extraction panic on mismatched buffer lengths**: Malformed PDF images are now skipped instead of panicking (regression from 4.5.0). * **`pdf` feature failed to compile without `layout-detection`**: Feature-gated the offending `config.layout` reference. * **Ruby binding missing `table_model` field**: Added `table_model` parsing to the layout config. * **WASM fails to load in Supabase/Deno edge functions**: Added explicit package exports and Deno detection with clear error messaging for restricted edge runtimes. * **Build failures on some toolchains and WASM/CI**: Pinned `zip` below 7.4 and vendored HWP text extraction to drop a transitive `zip 2.x` dependency. *** ## [4.5.3](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.5.3) - 2026-03-22 [Section titled “4.5.3 - 2026-03-22”](#453---2026-03-22) ### Added [Section titled “Added”](#added-18) * **Apple iWork format support**: Native parsing of modern `.pages`, `.numbers`, and `.key` files via a new `iwork` feature. * **SLANeXT table structure recognition models**: New `table_model` field on `LayoutDetectionConfig` selects the backend (`tatr` default, `slanet_wired`, `slanet_wireless`, `slanet_plus`, `slanet_auto`). Available across all 12 bindings and CLI (`--layout-table-model`). * **PP-LCNet table classifier**: Automatic wired/wireless table detection for SLANeXT auto mode. * **CLI `cache warm --all-table-models`**: Opt-in download of SLANeXT model variants (\~730MB); default warm downloads only RT-DETR + TATR. *** ## [4.5.2](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.5.2) - 2026-03-21 [Section titled “4.5.2 - 2026-03-21”](#452---2026-03-21) ### Fixed [Section titled “Fixed”](#fixed-27) * **PDF word splitting in extracted text**: Spurious mid-word spaces (e.g. `"s hall a b e active"`) are fixed via selective page-level respacing using character-level gap analysis. * **Markdown underscore escaping removed**: Identifiers like `CTC_ARP_01` are no longer mangled into `CTC\_ARP\_01`. * **Page header/footer leakage**: Running headers and copyright footers are now detected via fuzzy alphanumeric matching and stripped from the body. * **R batch functions failed with a spurious NULL argument**: Removed the extra positional `NULL` that broke all batch operations. * **Elixir OCR/layout/embeddings failed on Windows**: ONNX Runtime DLL is now staged where the BEAM VM loads NIFs. ### Added [Section titled “Added”](#added-19) * **General extraction result caching**: All file types (not just OCR) are now cached; repeat extractions with the same config return instantly. * **Cache namespace isolation**: New `cache_namespace` (and `--cache-namespace`) enables multi-tenant cache isolation on shared filesystems, with per-namespace deletion and stats. * **Per-request cache TTL**: New `cache_ttl_secs` overrides the global TTL per extraction (0 skips cache). * **Bundled `eng.traineddata`**: English OCR works out of the box with zero runtime configuration (\~4MB bundled). * **Tessdata in `cache warm`/`cache manifest`**: `cache warm` downloads all \~120 tessdata\_fast language files, giving full Tesseract language support without system packages; `KREUZBERG_CACHE_DIR/tessdata` is now resolved. * **CLI `embed` command**: Generate vector embeddings from text (feature-gated on `embeddings`). * **CLI `chunk` command**: Split text into chunks with configurable size, overlap, chunker type, and tokenizer. * **CLI `completions` command**: Generate shell completions for bash, zsh, fish, and powershell. * **CLI `--log-level` global flag**: Override `RUST_LOG` per invocation. * **CLI extraction overrides**: 27 new flags including `--layout-preset`, `--acceleration`, `--extract-images`, `--target-dpi`, `--token-reduction`, `--max-concurrent`, and more. * **CLI colored output**: Colored headers and labels, respecting `NO_COLOR`. * **API `POST /detect`, `GET /version`, `GET /cache/manifest`, `POST /cache/warm`**: New MIME detection, version, model manifest, and eager-download endpoints. * **MCP `get_version`, `cache_manifest`, `cache_warm`, `embed_text`, `chunk_text` tools**. * **TATR model availability check**: Layout detection now errors when table regions are detected but the TATR model is unavailable, instead of silently degrading. ### Changed [Section titled “Changed”](#changed-12) * **CLI batch flags**: The batch command now supports all extraction override flags, matching the extract command. ### Improved [Section titled “Improved”](#improved-3) * **CLI/API/MCP input validation**: OCR backend names, chunk sizes/overlap, DPI range, layout confidence, embedding preset names, and chunk bounds are now validated. * **Chunk overlap auto-clamping**: Overlap is clamped to `size/4` when `--chunk-size` is smaller than the default overlap, instead of erroring. *** ## [4.5.1](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.5.1) - 2026-03-20 [Section titled “4.5.1 - 2026-03-20”](#451---2026-03-20) * **Java batch extraction failed with memory access errors**: Fixed swapped `count`/`results` fields in the `CBatchResult` Panama FFM layout. * **Go bindings read fields at wrong offsets**: Synced the Go C header struct field order with the Rust `#[repr(C)]` layout, fixing corrupted `pages_json`. * **FFI failed to compile without `layout-detection`**: Feature-gated `LayoutDetectionConfig` and the layout setter. * **Python wheel builds failed on Linux aarch64**: The OpenSSL path is now detected via `uname -m` instead of being hardcoded to x86\_64. * **R batch functions errored**: Added the missing `file_configs` parameter that broke all batch operations. * **R package failed to load with ONNX Runtime**: Now links against ORT when `ORT_LIB_LOCATION` is set, fixing `undefined symbol: OrtGetApiBase`. *** ## [4.5.0](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.5.0) - 2026-03-20 [Section titled “4.5.0 - 2026-03-20”](#450---2026-03-20) ### Added [Section titled “Added”](#added-20) * **ONNX-based document layout detection**: New `layout` config field runs RT-DETR v2 (17 element classes) with `"fast"`/`"accurate"` presets and auto-downloaded models, across all bindings. * **SLANet table structure recognition**: Detected table regions produce markdown tables with colspan/rowspan support, now on all pages. * **Layout-enhanced heading detection**: Layout SectionHeader/Title regions guide heading detection and can override font-size classification. * **Multi-backend OCR pipeline**: New `OcrPipelineConfig` enables quality-based fallback across OCR backends (e.g. Tesseract then PaddleOCR). * **OCR quality thresholds**: New `OcrQualityThresholds` with 16 tunable parameters for output quality assessment and fallback. * **OCR auto-rotate**: New `OcrConfig.auto_rotate` (default false) detects 0/90/180/270-degree page rotations. * **PaddleOCR v2 model tier system**: New `model_tier` field with `"mobile"` (default, fast) and `"server"` (highest accuracy), unified multilingual models, across all bindings. * **`AccelerationConfig` for GPU/execution-provider control**: Fine-grained control over ONNX providers (CPU, CoreML, CUDA, TensorRT), typed across all bindings. * **`ConcurrencyConfig` for thread limiting**: New `max_threads` caps Rayon, ONNX intra-op threads, and batch concurrency, typed across all bindings. * **`EmailConfig` for MSG fallback codepage**: Configurable fallback codepage for MSG files lacking one (default windows-1252), typed across all bindings. * **Per-file extraction configuration (`FileExtractionConfig`)**: Each file in a batch can specify its own OCR, chunking, and output settings, via CLI `--file-configs` and MCP `file_configs`. * **Opt-in single-column pseudo tables**: New `allow_single_column_tables` on `PdfConfig` (default false) emits glossaries and itemized lists as tables. * **CLI `cache warm` and `cache manifest` commands**: Eagerly download all OCR/layout models, or output a JSON manifest with SHA256 checksums and source URLs. * **ChunkSizing configuration**: `sizing_type`, `sizing_model`, and `sizing_cache_dir` exposed across all bindings. * **Chunk heading context**: New `HeadingContext` in `ChunkMetadata` with heading level and text. * **`ModelManifestEntry` type with `manifest()` / `ensure_all_models()`**: Public API for querying and eagerly downloading model caches. ### Changed [Section titled “Changed”](#changed-13) * **Layout preset default changed from `"fast"` to `"accurate"`**: The `Fast` variant is removed; the `"fast"` string is still accepted. * **PaddleOCR default model tier changed from `"server"` to `"mobile"`**: Mobile is 3-5x faster with equivalent quality on standard documents; server remains available. * **PaddleOCR v2 models**: All models updated to v2 generation with unified multilingual recognition; V1 models remain for older versions. * **Batch API unification**: `_with_configs` batch functions removed; per-file `FileExtractionConfig` is now an optional parameter on the unified batch functions. * **Embedding `embed()` now takes `&self`**: Enables parallel embedding generation. * **`padding` field in `PaddleOcrConfig`**: Now exposed across Python, TypeScript, Ruby, and Go. * **Language-agnostic section pattern recognition**: Headings ending with a period are allowed when matching structural patterns, improving heading detection for legal/academic/multilingual documents. * **Strong typing across bindings**: Replaced weak `Dictionary`/`Map`/`array` config types with strongly typed classes in C#, Java, and PHP, and added missing config types to other bindings. ### Removed [Section titled “Removed”](#removed-1) * **`fastembed` dependency**: Replaced by a vendored embedding engine using ONNX Runtime directly. * **`EmbeddingModelType::FastEmbed` variant**: Use `Preset` or `Custom` instead. ### Fixed [Section titled “Fixed”](#fixed-28) * **C# library completely broken in 4.4.6**: Fixed the `CExtractionResult` struct layout mismatch that caused deserialization failures and overflow exceptions. * **PDF `force_ocr` without explicit OCR config silently ignored**: Now unconditionally triggers OCR with default settings. * **PDF image extraction returned raw compressed data**: Extracted images are now decoded and re-encoded as PNG/JPEG. * **Node.js `extractFileInWorker` dropped mime\_type**: MIME type is now forwarded to extraction instead of injected into the PDF password config. * **DOCX/XML parser compilation failure**: Resolved type ambiguity introduced by `zip` 8.2.0. * **Python type stubs missing from sdist**: `py.typed` and `.pyi` files are now included in wheel and sdist. * **PDF broken CMap word spacing**: Geometric validation vetoes false word boundaries (e.g. `"co mputer"` -> `"computer"`). * **PDF structure-tree headings rejected**: H1-H6 tags are now trusted as author intent instead of being rejected by font-size validation. * **Slow PDF structure-tree extraction**: Text and style maps are built in a single pass, eliminating multi-second extraction on complex pages. * **OCR Picture regions suppressed text**: Embedded text in Picture regions is preserved as paragraphs instead of dropped. * **Unstable reading order**: Spatial sorts use discrete row buckets, ensuring correct and stable ordering. * **Page furniture over-stripping**: Added guards to prevent removal of legitimate content. * **`KREUZBERG_CACHE_DIR` not respected by all caches**: Embeddings, OCR, and extraction caches now honor the variable. * **MSG ANSI string decoding**: MSG files now decode ANSI properties using the declared code page instead of lossy UTF-8. * **SLANet-Plus inference failures on macOS CoreML**: Re-exported the ONNX model with a shape fix, resolving silent table-extraction failures. * **TATR model crash in batch processing**: Model unavailability in parallel closures now falls back gracefully instead of crashing FFI callers. * **Docker musl builds failed**: Alpine/musl images now link the system ONNX Runtime; all features work in musl CLI images. * **C#/Java FFI batch functions rejected NULL**: They now accept NULL for per-file config JSON. ### Known Issues [Section titled “Known Issues”](#known-issues) * **PHP PIE Windows package temporarily unavailable**: Disabled due to a transitive dependency conflict on the Windows target; Linux and macOS are unaffected. * **WASM: no layout detection, acceleration, or email config**: ONNX Runtime is unavailable on WASM, so RT-DETR layout detection, hardware acceleration, and concurrency config are unavailable; Tesseract WASM OCR and embeddings are supported. *** ## [4.4.6](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.4.6) [Section titled “4.4.6”](#446) ### Added [Section titled “Added”](#added-21) * **dBASE (.dbf) format support**: Extract table data from dBASE files as markdown tables with field type support. * **Hangul Word Processor (.hwp/.hwpx) support**: Extract text from HWP 5.0 documents. * **Office template/macro format variants**: Added `.docm`, `.dotx`, `.dotm`, `.dot`, `.potx`, `.potm`, `.pot`, `.xltx`, and `.xlt` support. ### Fixed [Section titled “Fixed”](#fixed-29) * **DOCX image placeholders missing with `extract_images=True`**: The default plain-text path stripped image references; image extraction now forces markdown output so placeholders appear. ### Changed [Section titled “Changed”](#changed-14) * **Format count updated to 91+** (from 75+) across docs and manifests. ## [4.4.5](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.4.5) [Section titled “4.4.5”](#445) ### Fixed [Section titled “Fixed”](#fixed-30) * **PDF markdown garbled positioned text**: Line breaks in positioned/tabular text (CVs, addresses, tables) are preserved by splitting short lines into separate paragraphs when few lines reach the right margin. * **Node worker pool password bug**: `extractFileInWorker` passed `password` as `mime_type`, so passwords were never applied; it now injects into `config.pdf_options.passwords`. * **WASM document structure returned empty results**: JS camelCase config keys are now transformed to snake\_case for deserialization. * **PHP 8.5 array coercion on macOS**: A wrapper transparently converts coerced array return values back to objects. * **PHP 8.5 support**: Upgraded ext-php-rs to 0.15.6. ### Added [Section titled “Added”](#added-22) * **CLI `--pdf-password` flag**: New option on `extract`/`batch` for encrypted PDFs (repeatable). * **MCP `pdf_password` parameter**: Added to `extract_file`, `extract_bytes`, and `batch_extract_files`. * **API `pdf_password` multipart field**: The extract endpoint now accepts encrypted-PDF passwords. ## [4.4.4](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.4.4) [Section titled “4.4.4”](#444) * Maintenance release (internal changes only). ## [4.4.3](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.4.3) [Section titled “4.4.3”](#443) ### Added [Section titled “Added”](#added-23) * **PDF image placeholder toggle**: New `inject_placeholders` on `ImageExtractionConfig` (default true); set false to extract image data without injecting `![image](...)` references. ### Fixed [Section titled “Fixed”](#fixed-31) * **Token reduction not applied**: Config was accepted but never executed; the pipeline now applies `reduce_tokens()` when configured. * **Nested HTML table extraction**: Nested tables now extract correctly with proper cell data and markdown rendering. * **hOCR plain text output**: hOCR now produces plain text when requested instead of falling back to Markdown. * **PDF garbled positioned/tabular text**: Spaces are now inserted when the X-position gap between characters exceeds `0.8 × avg_font_size`. * **Chunk page metadata drift with overlap**: Byte offsets are computed via pointer arithmetic, fixing incorrect page numbers when overlap is enabled. * **Node.js metadata casing**: Standardized `Metadata`/`EmailMetadata` fields to camelCase (e.g. `pageCount`, `creationDate`) and corrected `authors`/`keywords` pluralization. ## [4.4.2](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.4.2) [Section titled “4.4.2”](#442) ### Fixed [Section titled “Fixed”](#fixed-32) * **WASM OCR blocked the event loop**: `ocrRecognize()` ran synchronously on the main thread; it now runs in a worker thread, keeping the runtime responsive and letting timeouts fire. * **JPEG 2000 / JBIG2 OCR decode failure**: JP2/JPX/JPM/MJ2 and JBIG2 images failed with “format could not be determined”; a shared loader now detects them by magic bytes and uses the correct decoders across all OCR backends, including `ocr-wasm`. * **WASM PDF returned empty content**: `initWasm()` now awaits PDFium initialization, fixing a race where extraction started before PDFium was ready. ### Added [Section titled “Added”](#added-24) * **OMML-to-LaTeX math conversion for DOCX**: DOCX equations are now converted to LaTeX (fractions, radicals, n-ary operators, matrices, etc.) with `$$...$$`/`$...$` in markdown and raw LaTeX in plain text, instead of concatenated Unicode. * **Plain text output paths for all extractors**: DOCX, PPTX, ODT, FB2, DocBook, RTF, and Jupyter now produce clean plain text (no `#`, `**`, `|`, image placeholders) when plain/structured output is requested, instead of always emitting markdown. ### Changed [Section titled “Changed”](#changed-15) * **CLI now built with the `full` feature set** (the `cli` feature group is removed), ensuring the CLI supports all formats including archives (7z, tar, gz, zip). ### Fixed [Section titled “Fixed”](#fixed-33) * **Alpine/musl CLI Docker image “Dynamic loading not supported”**: The CLI binary is now dynamically linked against musl libc, enabling runtime loading for PDF processing. * **R package Windows installation**: Improved Python detection (`py` launcher, `RETICULATE_PYTHON`) and graceful handling of symlink extraction errors. * **PHP 8.5 precompiled binaries**: Added PHP 8.5 support alongside PHP 8.4. * **OCR DPI normalization**: Images are normalized to the target DPI before Tesseract, eliminating the resolution-estimate warning and improving accuracy on non-standard DPI. * **HTML metadata missing with Plain output**: HTML headers, links, images, and structured data are now collected even for the default plain output. * **PPTX text run spacing**: Adjacent runs are joined with smart spacing (“HelloWorld” -> “Hello World”). * **CSV Shift-JIS/cp932 detection**: Shift-JIS CSVs are decoded correctly instead of producing mojibake, with fallback encoding detection. * **EML multipart body extraction**: All text/html parts and nested `message/rfc822` parts are now extracted, not just index 0. * **EPUB media tag leakage**: `