@xberg-io/opencode-xberg 1.3.6 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.opencode/ai-rulez-bundle.json +51 -0
  2. package/.opencode/ai-rulez-content.js +167 -0
  3. package/.opencode/commands/xberg-extract.md +14 -0
  4. package/.opencode/commands/xberg-ocr.md +14 -0
  5. package/.opencode/plugins/xberg.js +75 -62
  6. package/.opencode/skills/batch-extraction/SKILL.md +168 -0
  7. package/.opencode/skills/chunking/SKILL.md +163 -0
  8. package/.opencode/skills/extracting-keywords/SKILL.md +171 -0
  9. package/.opencode/skills/extracting-tables/SKILL.md +156 -0
  10. package/.opencode/skills/extracting-with-ocr/SKILL.md +130 -0
  11. package/.opencode/skills/picking-a-format/SKILL.md +104 -0
  12. package/.opencode/skills/xberg/SKILL.md +427 -0
  13. package/.opencode/skills/xberg/references/advanced-features.md +628 -0
  14. package/.opencode/skills/xberg/references/cli-reference.md +462 -0
  15. package/.opencode/skills/xberg/references/configuration.md +587 -0
  16. package/.opencode/skills/xberg/references/nodejs-api.md +485 -0
  17. package/.opencode/skills/xberg/references/other-bindings.md +345 -0
  18. package/.opencode/skills/xberg/references/python-api.md +657 -0
  19. package/.opencode/skills/xberg/references/rust-api.md +412 -0
  20. package/.opencode/skills/xberg/references/supported-formats.md +252 -0
  21. package/.pi/prompts/xberg-extract.md +14 -0
  22. package/.pi/prompts/xberg-ocr.md +14 -0
  23. package/.pi/skills/batch-extraction/SKILL.md +168 -0
  24. package/.pi/skills/chunking/SKILL.md +163 -0
  25. package/.pi/skills/extracting-keywords/SKILL.md +171 -0
  26. package/.pi/skills/extracting-tables/SKILL.md +156 -0
  27. package/.pi/skills/extracting-with-ocr/SKILL.md +130 -0
  28. package/.pi/skills/picking-a-format/SKILL.md +104 -0
  29. package/.pi/skills/xberg/SKILL.md +427 -0
  30. package/.pi/skills/xberg/references/advanced-features.md +628 -0
  31. package/.pi/skills/xberg/references/cli-reference.md +462 -0
  32. package/.pi/skills/xberg/references/configuration.md +587 -0
  33. package/.pi/skills/xberg/references/nodejs-api.md +485 -0
  34. package/.pi/skills/xberg/references/other-bindings.md +345 -0
  35. package/.pi/skills/xberg/references/python-api.md +657 -0
  36. package/.pi/skills/xberg/references/rust-api.md +412 -0
  37. package/.pi/skills/xberg/references/supported-formats.md +252 -0
  38. package/README.md +40 -0
  39. package/package.json +69 -16
  40. package/scripts/mcp-launch.sh +188 -0
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: extracting-with-ocr
3
+ description: Use when extracting text from scanned PDFs, photographed pages, or images that have no embedded text layer. Covers OCR backends, language packs, force-OCR, and performance tuning.
4
+ ---
5
+
6
+ <!--
7
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
8
+ Content-Hash: blake3:3ec8b7cf60f56cbe5cc15a5a0b29d0c2f8e3cf4c3823503eb1128fb7f9ee11db
9
+ Source-Hash: blake3:3fca38eb564d0ed9c9194d070fd8dec96de727edc92e82954cb4b9af52cddbaf
10
+ Schema-Version: v1
11
+ -->
12
+
13
+ # Extracting with OCR
14
+
15
+ Use this when a document is image-based: scanned PDFs, photographed pages,
16
+ screenshots, JPEG/PNG/TIFF with text. Xberg auto-OCRs raster images and
17
+ auto-detects PDFs that lack a text layer. Force it on when extraction
18
+ returned empty/garbled text from a PDF that "looks" textual.
19
+
20
+ ## When to force OCR
21
+
22
+ - Extraction returned an empty `content` field, but the file opens visually.
23
+ - The PDF text layer is junk (copy-paste from a viewer produces gibberish).
24
+ - You want consistent output across mixed scanned + digital PDFs.
25
+
26
+ ```bash
27
+ xberg extract scan.pdf --force-ocr=true
28
+ xberg extract scan.pdf --ocr=true --ocr-language eng
29
+ ```
30
+
31
+ If a page has an unreliable text layer, `--force-ocr=true` re-rasterizes
32
+ and runs OCR on every page.
33
+
34
+ ## Backends
35
+
36
+ Tesseract is the default and ships with the CLI — no extra install. Other
37
+ backends are opt-in:
38
+
39
+ | Backend | Flag | Install | Notes |
40
+ | ------------- | ------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------- |
41
+ | Tesseract | `--ocr-backend tesseract` (default) | bundled | Best general-purpose, 100+ languages via tessdata. |
42
+ | PaddleOCR | `--ocr-backend paddle-ocr` | bundled (ONNX Runtime) | Strong on Asian scripts. Not available on WASM or Windows. |
43
+ | Candle VLM | `--ocr-backend candle-trocr` (and other `candle-*`) | bundled (Candle) | Local vision OCR models (`candle-trocr`, `candle-paddleocr-vl`, `candle-glm-ocr`, `candle-deepseek-ocr`). |
44
+ | VLM (hosted) | `--ocr-backend vlm` + `--vlm-model` | liter-llm provider (`--vlm-api-key`) | Multimodal LLM via liter-llm. Use when OCR fails on dense or handwritten layouts. |
45
+
46
+ Pick Tesseract first. Switch only when accuracy is unacceptable.
47
+
48
+ ## Language packs
49
+
50
+ Tesseract uses ISO 639-2 codes. Default is `eng`. Combine with `+`:
51
+
52
+ ```bash
53
+ xberg extract menu.jpg --ocr=true --ocr-language "eng+deu"
54
+ xberg extract bilingual.pdf --ocr-language "eng+jpn"
55
+ xberg extract any.pdf --ocr-language all # all installed packs
56
+ ```
57
+
58
+ Install missing packs at the OS level:
59
+
60
+ ```bash
61
+ # macOS
62
+ brew install tesseract-lang
63
+
64
+ # Debian/Ubuntu
65
+ sudo apt install tesseract-ocr-deu tesseract-ocr-jpn tesseract-ocr-fra
66
+
67
+ # Specific lang only
68
+ sudo apt install tesseract-ocr-<iso639-2>
69
+ ```
70
+
71
+ Xberg fails fast with a helpful error if you request a language pack
72
+ that is not installed. Read the error — it names the missing file.
73
+
74
+ ## Useful flags
75
+
76
+ - `--ocr=true` — enable OCR (auto-enabled for images and scanned PDFs).
77
+ - `--force-ocr=true` — OCR every page even if a text layer exists.
78
+ - `--disable-ocr=true` — never OCR (extract embedded text only or fail).
79
+ - `--ocr-language <lang>` — single code or `+`-joined list, or `all`.
80
+ - `--ocr-backend <tesseract|paddle-ocr|vlm|candle-trocr|candle-paddleocr-vl|candle-glm-ocr|candle-deepseek-ocr>` — pick backend.
81
+ - `--ocr-auto-rotate=true` — pre-rotate via the auto-rotate model.
82
+ - `--acceleration <cpu|coreml|cuda|tensorrt|auto>` — ONNX accelerator for
83
+ paddle-ocr / auto-rotate / layout models.
84
+
85
+ ## Performance tips
86
+
87
+ - Cache is on by default. Repeated extraction of the same file + config is
88
+ instant. Do not pass `--no-cache=true` unless you have a reason.
89
+ - For batch OCR, use `xberg batch *.pdf --ocr=true` — internal worker
90
+ pool parallelizes across CPU cores. Cap with `--max-concurrent N` if
91
+ memory is tight.
92
+ - Raise `--target-dpi` (default 300) only for low-resolution scans. Higher
93
+ DPI is slower; 200 is usually enough for printed text.
94
+ - Enable `--ocr-auto-rotate=true` only when pages may be rotated; the
95
+ classifier adds latency.
96
+ - On Apple Silicon, `--acceleration coreml` typically beats CPU for
97
+ paddle-ocr and layout detection.
98
+
99
+ ## Config file alternative
100
+
101
+ Long flag chains belong in `xberg.toml` — auto-discovered from cwd
102
+ upward.
103
+
104
+ ```toml
105
+ force_ocr = true
106
+ output_format = "markdown"
107
+
108
+ [ocr]
109
+ backend = "tesseract"
110
+ language = "eng+deu"
111
+ auto_rotate = true
112
+ ```
113
+
114
+ Then just run:
115
+
116
+ ```bash
117
+ xberg extract document.pdf
118
+ ```
119
+
120
+ ## Common failure modes
121
+
122
+ - **"missing tessdata"** — install the language pack at OS level (see above).
123
+ - **Empty content on a scanned PDF without `--force-ocr`** — the file has a
124
+ bogus zero-width text layer. Re-run with `--force-ocr=true`.
125
+ - **OCR on a rotated page** — add `--ocr-auto-rotate=true` or pre-rotate.
126
+ - **Garbled CJK output** — ensure the right language pack is installed and
127
+ passed via `--ocr-language`; consider `paddle-ocr` for Chinese/Japanese.
128
+
129
+ See `references/cli-reference.md` and `references/configuration.md` in the
130
+ sibling `xberg` skill for the full flag and config schema.
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: picking-a-format
3
+ description: Use when choosing an output format for extracted documents — plain text, markdown, djot, HTML, JSON, or DocTags. Maps consumer (LLM, parser, archive) to the right `--format` / `--content-format` pair.
4
+ ---
5
+
6
+ <!--
7
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
8
+ Content-Hash: blake3:bcdbffe958890e1c589f3ea44540c67c86540196a844e6de5c011faccdd345fc
9
+ Source-Hash: blake3:3fca38eb564d0ed9c9194d070fd8dec96de727edc92e82954cb4b9af52cddbaf
10
+ Schema-Version: v1
11
+ -->
12
+
13
+ # Picking a format
14
+
15
+ Xberg has two orthogonal format knobs. Get them right up front and the
16
+ downstream code stays simple.
17
+
18
+ | Knob | What it controls | Values | Default |
19
+ | ------------------- | ------------------------------------------------- | -------------------------------------- | ---------------- |
20
+ | `--format` | How the CLI prints the result | `text`, `json`, `toon` | `text` (`extract`), `json` (`batch`) |
21
+ | `--content-format` | How extracted content is rendered inside `result` | `plain`, `markdown`, `djot`, `html`, `json`, `doctags` | `plain` |
22
+ | `--token-reduction` | Strip whitespace / boilerplate for LLM contexts | `off`, `light`, `moderate`, `aggressive`, `maximum` | `off` |
23
+
24
+ `--format json` returns an envelope wrapping the `ExtractedDocument` — the
25
+ document lives under `.result` for `extract` and under `.results[]` for
26
+ `batch`, with `content`, `metadata`, `tables`, and `images` as fields of
27
+ that nested document. `--format text` prints just `content`.
28
+ `--content-format` is what shows up inside that `content` field.
29
+
30
+ ## Decision tree
31
+
32
+ ```text
33
+ Who consumes the output?
34
+ ├── LLM (Claude, GPT, Gemini, local) — embed/prompt context
35
+ │ --format text --content-format markdown
36
+ ├── Vector store / RAG indexer
37
+ │ --format json --content-format markdown
38
+ │ (markdown preserves structure for chunking)
39
+ ├── Downstream parser that expects machine-readable JSON
40
+ │ --format json --content-format plain
41
+ │ (cleanest text + structured metadata)
42
+ ├── Human review / archival
43
+ │ --format text --content-format markdown
44
+ ├── HTML re-rendering / web display
45
+ │ --format json --content-format html
46
+ ├── Lossless intermediate for pandoc / academic tooling
47
+ │ --format json --content-format djot
48
+ └── Token-budget-constrained pipeline
49
+ --format text --content-format plain
50
+ (drops markup; add --token-reduction moderate for further savings)
51
+ ```
52
+
53
+ ## Examples
54
+
55
+ Feed a PDF directly into an LLM:
56
+
57
+ ```bash
58
+ xberg extract paper.pdf --content-format markdown
59
+ ```
60
+
61
+ Index a corpus into a RAG store with tables and headings preserved:
62
+
63
+ ```bash
64
+ xberg batch docs/*.pdf --format json --content-format markdown \
65
+ | jq -c '.results[] | {content: .content, tables: .tables}'
66
+ ```
67
+
68
+ Strip a file to bare text for a token-tight summarizer:
69
+
70
+ ```bash
71
+ xberg extract long.pdf \
72
+ --content-format plain \
73
+ --token-reduction moderate
74
+ ```
75
+
76
+ Pull metadata only, ignore content:
77
+
78
+ ```bash
79
+ xberg extract file.pdf --format json | jq '.result.metadata'
80
+ ```
81
+
82
+ ## When in doubt
83
+
84
+ - **Default to `markdown`** as the content format. It is the best
85
+ compromise across LLMs, RAG, and human review, and Xberg has the
86
+ most faithful renderer for it.
87
+ - Reach for `plain` only when downstream cannot tolerate any markup.
88
+ - Reach for `djot` only if you're already in a djot/pandoc pipeline.
89
+ - Reach for `html` only when re-rendering for the web.
90
+ - Reach for `json` for a heading-driven content tree, or `doctags` for Docling-compatible output.
91
+
92
+ ## Token-reduction (orthogonal)
93
+
94
+ `--token-reduction` collapses whitespace, strips repeated headers/footers,
95
+ and trims boilerplate. It composes with any `--content-format`:
96
+
97
+ - `off` (default), `light`, `moderate`, `aggressive`, `maximum`.
98
+
99
+ Use `moderate` as a safe starting point for LLM context windows. `maximum`
100
+ is lossy — verify before relying on it.
101
+
102
+ See `references/cli-reference.md` for the full flag set and
103
+ `references/configuration.md` for the equivalent `output_format` and
104
+ `token_reduction` keys in `xberg.toml`.
@@ -0,0 +1,427 @@
1
+ ---
2
+ name: xberg
3
+ description: >-
4
+ Extract text, tables, metadata, and images from 107 document formats
5
+ (PDF, Office, images, HTML, email, archives, academic) using Xberg.
6
+ Use when writing code that calls Xberg APIs in Python, Node.js/TypeScript,
7
+ Rust, or CLI. Covers installation, extraction (sync/async), configuration
8
+ (OCR, chunking, output format), batch processing, error handling, and plugins.
9
+ license: Elastic-2.0
10
+ metadata:
11
+ author: xberg-io
12
+ version: "0.1.0"
13
+ repository: https://github.com/xberg-io/xberg
14
+ ---
15
+
16
+ <!--
17
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
18
+ Content-Hash: blake3:8d1ddd2c0fd7b6e9473737826178427138c3fac45cedd5b6c3d0b8a243739deb
19
+ Source-Hash: blake3:3fca38eb564d0ed9c9194d070fd8dec96de727edc92e82954cb4b9af52cddbaf
20
+ Schema-Version: v1
21
+ -->
22
+
23
+ # Xberg Document Extraction
24
+
25
+ Xberg is a document intelligence library with a Rust core and bindings for Python, TypeScript/Node.js, Ruby, PHP, Go, Java, C#, Elixir, WebAssembly, Dart, Kotlin Android, Swift, Zig, and C. It extracts text, tables, metadata, and images from 107 formats across 140 unique file extensions and accepts 53 compatibility MIME aliases, including PDF, Office documents, images, HTML, email, archives, and academic formats.
26
+
27
+ Use this skill when writing code that:
28
+
29
+ - Extracts text or metadata from documents
30
+ - Performs OCR on scanned documents or images
31
+ - Batch-processes multiple files
32
+ - Configures extraction options (output format, chunking, OCR, language detection)
33
+ - Implements custom plugins (post-processors, validators, OCR backends)
34
+
35
+ > If the `xberg` MCP server is registered in this session, prefer its tools over shelling out to the CLI — they expose the same extraction surface with structured arguments and results.
36
+
37
+ ## Installation
38
+
39
+ ### Python
40
+
41
+ ```bash
42
+ pip install xberg
43
+ ```
44
+
45
+ ### Node.js
46
+
47
+ ```bash
48
+ npm install @xberg-io/xberg
49
+ ```
50
+
51
+ ### Rust
52
+
53
+ ```bash
54
+ cargo add xberg
55
+ ```
56
+
57
+ ```toml
58
+ # Cargo.toml
59
+ [dependencies]
60
+ xberg = { version = "1.1.0", features = ["full"] }
61
+ tokio = { version = "1", features = ["full"] }
62
+ # feature flags: pdf, ocr, chunking, embeddings, language-detection, keywords, api, mcp
63
+ # (or "formats" / "full" aggregates); tokio-runtime is on by default
64
+ ```
65
+
66
+ ### CLI
67
+
68
+ ```bash
69
+ brew install xberg-io/tap/xberg
70
+ # or run without a persistent install (the CLI proxy package self-installs the binary):
71
+ npx @xberg-io/xberg-cli --help
72
+ uvx --from xberg-cli xberg --help
73
+ # or download a prebuilt binary from the latest GitHub release:
74
+ # https://github.com/xberg-io/xberg/releases/latest
75
+ # or build from source:
76
+ cargo install xberg-cli
77
+ ```
78
+
79
+ ## Quick Start
80
+
81
+ The library entry points are `extract(input, config)` and `extract_batch(inputs, config)`. Both return an `ExtractionResult` **envelope** — the extracted document(s) live in `result.results`, and per-document data (`content`, `tables`, `metadata`, …) is on each `result.results[i]`. Python and Node are async-only.
82
+
83
+ ### Python
84
+
85
+ ```python
86
+ import asyncio
87
+ from xberg import ExtractInput, extract, ExtractionConfig
88
+
89
+ async def main() -> None:
90
+ result = await extract(ExtractInput(uri="document.pdf"), ExtractionConfig())
91
+ doc = result.results[0]
92
+ print(doc.content) # extracted text
93
+ print(doc.metadata) # document metadata
94
+ print(doc.tables) # extracted tables
95
+
96
+ asyncio.run(main())
97
+ ```
98
+
99
+ ### Node.js
100
+
101
+ ```typescript
102
+ import { extract } from "@xberg-io/xberg";
103
+
104
+ const output = await extract({ kind: "uri", uri: "document.pdf" });
105
+ const doc = output.results[0];
106
+ console.log(doc.content);
107
+ console.log(doc.metadata);
108
+ console.log(doc.tables);
109
+ ```
110
+
111
+ ### Rust
112
+
113
+ ```rust
114
+ use xberg::{extract, ExtractInput, ExtractionConfig};
115
+
116
+ #[tokio::main]
117
+ async fn main() -> xberg::Result<()> {
118
+ let output = extract(ExtractInput::from_uri("document.pdf"), &ExtractionConfig::default()).await?;
119
+ println!("{}", output.results[0].content);
120
+ Ok(())
121
+ }
122
+ ```
123
+
124
+ ### CLI
125
+
126
+ ```bash
127
+ xberg extract document.pdf
128
+ xberg extract document.pdf --format json
129
+ xberg extract document.pdf --content-format markdown
130
+ ```
131
+
132
+ ## Configuration
133
+
134
+ All languages use the same configuration structure with language-appropriate naming conventions.
135
+
136
+ ### Python (snake_case)
137
+
138
+ ```python
139
+ from xberg import (
140
+ ExtractInput, extract,
141
+ ExtractionConfig, OcrConfig, TesseractConfig, PdfConfig, ChunkingConfig, OutputFormat,
142
+ )
143
+
144
+ config = ExtractionConfig(
145
+ ocr=OcrConfig(
146
+ backend="tesseract",
147
+ language=["eng"],
148
+ tesseract_config=TesseractConfig(psm=6, enable_table_detection=True),
149
+ ),
150
+ pdf_options=PdfConfig(passwords=["secret123"]),
151
+ chunking=ChunkingConfig(max_characters=1000, overlap=200),
152
+ output_format=OutputFormat("markdown"),
153
+ )
154
+
155
+ result = await extract(ExtractInput(uri="document.pdf"), config)
156
+ ```
157
+
158
+ ### Node.js (camelCase)
159
+
160
+ ```typescript
161
+ import { extract, type ExtractionConfig } from "@xberg-io/xberg";
162
+
163
+ const config: ExtractionConfig = {
164
+ ocr: { backend: "tesseract", language: ["eng"] },
165
+ pdfOptions: { passwords: ["secret123"] },
166
+ chunking: { maxCharacters: 1000, overlap: 200 },
167
+ outputFormat: "markdown",
168
+ };
169
+
170
+ const output = await extract({ kind: "uri", uri: "document.pdf" }, config);
171
+ ```
172
+
173
+ ### Rust (snake_case)
174
+
175
+ ```rust
176
+ use xberg::{extract, ExtractInput, ExtractionConfig, OcrConfig, ChunkingConfig, OutputFormat};
177
+
178
+ let config = ExtractionConfig {
179
+ ocr: Some(OcrConfig {
180
+ backend: "tesseract".into(),
181
+ language: vec!["eng".to_string()],
182
+ ..Default::default()
183
+ }),
184
+ chunking: Some(ChunkingConfig {
185
+ max_characters: 1000,
186
+ overlap: 200,
187
+ ..Default::default()
188
+ }),
189
+ output_format: OutputFormat::Markdown,
190
+ ..Default::default()
191
+ };
192
+
193
+ let output = extract(ExtractInput::from_uri("document.pdf"), &config).await?;
194
+ ```
195
+
196
+ ### Config File (TOML)
197
+
198
+ ```toml
199
+ output_format = "markdown"
200
+
201
+ [ocr]
202
+ backend = "tesseract"
203
+ language = "eng"
204
+
205
+ [chunking]
206
+ max_characters = 1000
207
+ overlap = 200
208
+
209
+ [pdf_options]
210
+ passwords = ["secret123"]
211
+ ```
212
+
213
+ ```bash
214
+ # CLI: auto-discovers xberg.toml/yaml/yml/json in current/parent directories
215
+ xberg extract doc.pdf
216
+ # or explicit:
217
+ xberg extract doc.pdf --config xberg.toml
218
+ xberg extract doc.pdf --config-json '{"ocr":{"backend":"tesseract","language":"deu"}}'
219
+ ```
220
+
221
+ ## Batch Processing
222
+
223
+ `extract_batch` takes a list of `ExtractInput`s and returns one envelope whose `results` array holds a document per input (in input order); per-input failures are reported in `result.errors`.
224
+
225
+ ### Python
226
+
227
+ ```python
228
+ from xberg import ExtractInput, extract_batch, ExtractionConfig
229
+
230
+ inputs = [
231
+ ExtractInput(uri="doc1.pdf"),
232
+ ExtractInput(uri="doc2.docx"),
233
+ ExtractInput(uri="doc3.xlsx"),
234
+ ]
235
+ output = await extract_batch(inputs, ExtractionConfig())
236
+
237
+ for doc in output.results:
238
+ print(f"{len(doc.content)} chars extracted")
239
+ ```
240
+
241
+ ### Node.js
242
+
243
+ ```typescript
244
+ import { extractBatch } from "@xberg-io/xberg";
245
+
246
+ const output = await extractBatch([
247
+ { kind: "uri", uri: "doc1.pdf" },
248
+ { kind: "uri", uri: "doc2.docx" },
249
+ ]);
250
+ for (const doc of output.results) {
251
+ console.log(`${doc.content.length} chars`);
252
+ }
253
+ ```
254
+
255
+ ### Rust
256
+
257
+ ```rust
258
+ use xberg::{extract_batch, ExtractInput, ExtractionConfig};
259
+
260
+ let config = ExtractionConfig::default();
261
+ let inputs = vec![ExtractInput::from_uri("doc1.pdf"), ExtractInput::from_uri("doc2.docx")];
262
+ let output = extract_batch(inputs, &config).await?;
263
+ ```
264
+
265
+ ### CLI
266
+
267
+ ```bash
268
+ xberg batch *.pdf --format json
269
+ xberg batch docs/*.docx --content-format markdown
270
+ ```
271
+
272
+ ## OCR
273
+
274
+ OCR runs automatically for images and scanned PDFs. Tesseract is the default backend (native binding, no external install required).
275
+
276
+ ### Backends
277
+
278
+ Select with `OcrConfig.backend`:
279
+
280
+ - **tesseract** (default): built-in native binding. All Tesseract languages supported.
281
+ - **paddleocr** (`"paddleocr"` / `"paddle-ocr"`): ONNX-based PaddleOCR.
282
+ - **vlm**: Vision-Language-Model OCR (configure via `OcrConfig.vlm_config`).
283
+
284
+ Custom backends can be registered in Python/Node via `register_ocr_backend` (see [Advanced Features](references/advanced-features.md)).
285
+
286
+ ### Language Codes
287
+
288
+ ```python
289
+ config = ExtractionConfig(ocr=OcrConfig(language=["eng"])) # English
290
+ config = ExtractionConfig(ocr=OcrConfig(language=["eng", "deu"])) # Multiple
291
+ # The single-string shorthand ("eng+deu") is only accepted in config files / --config-json,
292
+ # not in the OcrConfig constructor (Python takes a list, Node takes an array).
293
+ ```
294
+
295
+ ### Force OCR
296
+
297
+ ```python
298
+ config = ExtractionConfig(force_ocr=True) # OCR even if text is extractable
299
+ ```
300
+
301
+ ## Result Envelope and Document Fields
302
+
303
+ `extract` / `extract_batch` return an `ExtractionResult` envelope: `results` (list of documents), `errors` (per-input failures), and `summary` (counts). Per-document fields live on each document in `results` — bind `doc = result.results[0]` (Python/Node) or `&output.results[0]` (Rust) first.
304
+
305
+ | Field | Python (`doc.`) | Node.js (`doc.`) | Rust (`document.`) | Description |
306
+ | ------------ | ---------------------- | --------------------- | ----------------------- | --------------------------------------------- |
307
+ | Text content | `content` | `content` | `content` | Extracted text (str/String) |
308
+ | MIME type | `mime_type` | `mimeType` | `mime_type` | Input document MIME type |
309
+ | Metadata | `metadata` | `metadata` | `metadata` | Document metadata (flat mapping) |
310
+ | Tables | `tables` | `tables` | `tables` | Extracted tables with cells + markdown |
311
+ | Languages | `detected_languages` | `detectedLanguages` | `detected_languages` | Detected languages (if enabled) |
312
+ | Chunks | `chunks` | `chunks` | `chunks` | Text chunks (if chunking enabled) |
313
+ | Images | `images` | `images` | `images` | Extracted images (if enabled) |
314
+ | Elements | `elements` | `elements` | `elements` | Semantic elements (if element_based format) |
315
+ | Pages | `pages` | `pages` | `pages` | Per-page content (if page extraction enabled) |
316
+ | Keywords | `extracted_keywords` | `extractedKeywords` | `extracted_keywords` | Extracted keywords (if enabled) |
317
+
318
+ ## Error Handling
319
+
320
+ ### Python
321
+
322
+ `extract` / `extract_batch` raise a plain `RuntimeError` on failure — the typed `XbergError` subclasses are not raised by these entry points, so catch `RuntimeError`. Per-input failures during `extract_batch` are reported non-fatally in `result.errors`.
323
+
324
+ ```python
325
+ from xberg import ExtractInput, extract, ExtractionConfig
326
+
327
+ try:
328
+ result = await extract(ExtractInput(uri="file.pdf"), ExtractionConfig())
329
+ for err in result.errors:
330
+ print(f"Per-input error: {err}")
331
+ except RuntimeError as e:
332
+ print(f"Extraction failed: {e}")
333
+ ```
334
+
335
+ ### Node.js
336
+
337
+ The Node binding throws plain `Error` objects (it does not export typed error subclasses). Catch with `instanceof Error`, and inspect `output.errors` for non-fatal per-input failures.
338
+
339
+ ```typescript
340
+ import { extract } from "@xberg-io/xberg";
341
+
342
+ try {
343
+ const output = await extract({ kind: "uri", uri: "file.pdf" });
344
+ if (output.errors.length > 0) {
345
+ console.error("Per-input errors:", output.errors);
346
+ }
347
+ } catch (e) {
348
+ if (e instanceof Error) {
349
+ console.error(`Extraction failed: ${e.message}`);
350
+ }
351
+ }
352
+ ```
353
+
354
+ ### Rust
355
+
356
+ ```rust
357
+ use xberg::{extract, ExtractInput, ExtractionConfig, XbergError};
358
+
359
+ let config = ExtractionConfig::default();
360
+ match extract(ExtractInput::from_uri("file.pdf"), &config).await {
361
+ Ok(output) => println!("{}", output.results[0].content),
362
+ Err(XbergError::Parsing { message, .. }) => eprintln!("Parse error: {message}"),
363
+ Err(XbergError::Ocr { message, .. }) => eprintln!("OCR error: {message}"),
364
+ Err(XbergError::UnsupportedFormat(mime)) => eprintln!("Unsupported: {mime}"),
365
+ Err(e) => eprintln!("Error: {e}"),
366
+ }
367
+ ```
368
+
369
+ ## Common Pitfalls
370
+
371
+ 1. **Result is an envelope**: `extract` / `extract_batch` return `ExtractionResult` with `results`, `errors`, and `summary`. Per-document fields (`content`, `tables`, `chunks`, …) are on `result.results[i]`, NOT on the top-level return.
372
+ 2. **Async-only**: Python and Node have no sync variants — always `await extract(...)`. Rust `extract` is async; use `#[tokio::main]` or an async context.
373
+ 3. **Build the input**: pass an `ExtractInput`, not a bare path. Use `ExtractInput(uri=...)` / `ExtractInput::from_uri(...)` (Python/Rust) or `{ kind: "uri", uri: "..." }` (Node); for bytes use `kind="bytes"` with `bytes`/`mime_type`.
374
+ 4. **Python ChunkingConfig fields**: construct with `max_characters` and `overlap` (defaults 1000 / 200); these are also the readable attributes. When passing config as a dict/JSON, the `max_chars` / `max_overlap` aliases are also accepted. Node uses `maxCharacters` / `overlap`; Rust struct fields are `max_characters` / `overlap`.
375
+ 5. **Python errors**: `extract` / `extract_batch` raise a plain `RuntimeError` on failure, not typed `XbergError` subclasses — catch `RuntimeError`. Node throws plain `Error` (no typed error subclasses).
376
+ 6. **Rust extract signature**: `extract(input, &config)` — the config is a reference. Use `&ExtractionConfig::default()` for defaults.
377
+ 7. **CLI --format vs --content-format**: `--format` controls CLI output (`text`, `json`, or `toon`). `--content-format` controls content rendering (`plain`, `markdown`, `djot`, `html`, `json`, or `doctags`).
378
+ 8. **Config file field names**: Use snake_case in TOML/YAML/JSON config files — `[chunking]` fields are `max_characters` and `overlap`; other fields use names like `output_format`, `pdf_options`.
379
+
380
+ ## Supported Formats (Summary)
381
+
382
+ | Category | Extensions |
383
+ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
384
+ | **PDF** | `.pdf` |
385
+ | **Word** | `.docx`, `.docm`, `.doc`, `.dotx`, `.dotm`, `.dot`, `.odt`, `.pages`, `.wpd`, `.wp`, `.wp5`, `.wp6`, `.hwp`, `.hwpx` |
386
+ | **Spreadsheets** | `.xlsx`, `.xlsm`, `.xlsb`, `.xls`, `.xla`, `.xlam`, `.xltm`, `.xltx`, `.xlt`, `.ods`, `.numbers` |
387
+ | **Presentations** | `.pptx`, `.pptm`, `.ppt`, `.pps`, `.ppsx`, `.potx`, `.potm`, `.pot`, `.odp`, `.key` |
388
+ | **eBooks** | `.epub`, `.fb2` |
389
+ | **Images** | `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.bmp`, `.tiff`, `.tif`, `.jp2`, `.jpg2`, `.j2c`, `.j2k`, `.jpc`, `.jbig2`, `.jb2`, `.pnm`, `.pbm`, `.pgm`, `.ppm`, `.heic`, `.heics`, `.heif`, `.heifs`, `.hif`, `.avif`, `.avcs`, `.svg` |
390
+ | **Markup** | `.html`, `.htm`, `.xhtml`, `.xht`, `.xml`, `.kml` |
391
+ | **Data** | `.json`, `.geojson`, `.jsonl`, `.ndjson`, `.yaml`, `.yml`, `.toml`, `.csv`, `.tsv`, `.dbf`, `.sqlite`, `.sqlite3`, `.db`, `.gpkg`, `.gpkx` |
392
+ | **Text** | `.txt`, `.adoc`, `.asciidoc`, `.vtt`, `.md`, `.markdown`, `.commonmark`, `.qmd`, `.rmd`, `.mdx`, `.djot`, `.dj`, `.doctags`, `.rst`, `.org`, `.rtf` |
393
+ | **Email** | `.eml`, `.msg`, `.pst` |
394
+ | **Archives** | `.zip`, `.tar`, `.tgz`, `.gz`, `.7z` |
395
+ | **Audio/Video** | `.mp3`, `.mpga`, `.m4a`, `.wav`, `.webm`, `.mp4`, `.mpg4`, `.mp4v`, `.m4v`, `.mpeg`, `.mpg`, `.mpe`, `.m1v`, `.m2v` |
396
+ | **Academic** | `.bib`, `.ris`, `.nbib`, `.enw`, `.tex`, `.latex`, `.typ`, `.typst`, `.jats`, `.nxml`, `.ipynb`, `.docbook`, `.dbk`, `.docbook4`, `.docbook5`, `.opml` |
397
+
398
+ CSL JSON is supported through an explicit MIME type but does not have a registered file extension.
399
+
400
+ See [references/supported-formats.md](references/supported-formats.md) for the complete format reference with MIME types.
401
+
402
+ ## Additional Resources
403
+
404
+ Detailed reference files for specific topics:
405
+
406
+ - **[Python API Reference](references/python-api.md)** — All functions, config classes, plugin protocols, exact signatures
407
+ - **[Node.js API Reference](references/nodejs-api.md)** — All functions, TypeScript interfaces, worker pool APIs
408
+ - **[Rust API Reference](references/rust-api.md)** — All functions with feature gates, structs, Cargo.toml examples
409
+ - **[CLI Reference](references/cli-reference.md)** — All commands, flags, config precedence, exit codes
410
+ - **[Configuration Reference](references/configuration.md)** — TOML/YAML/JSON formats, auto-discovery, env vars, full schema
411
+ - **[Supported Formats](references/supported-formats.md)** — Format families, extensions, capabilities, and authoritative discovery commands
412
+ - **[Advanced Features](references/advanced-features.md)** — Plugins, embeddings, MCP server, API server, security limits
413
+ - **[Other Language Bindings](references/other-bindings.md)** — Go, Ruby, Java, C#, PHP, Elixir, WASM, Dart, Kotlin Android, Swift, Zig, C, and Docker
414
+
415
+ ## Related skills
416
+
417
+ Task-focused sibling skills go deeper than this overview:
418
+
419
+ - **extracting-with-ocr** — OCR backends, language packs, force-OCR, tuning.
420
+ - **extracting-tables** — layout-aware table detection and table models.
421
+ - **chunking** — chunk size/overlap, markdown/yaml/semantic chunkers, the `chunk` command.
422
+ - **extracting-keywords** — YAKE/RAKE keywords, language detection, the `embed` command.
423
+ - **batch-extraction** — the `batch` command, `--file-configs`, parallelism, error recovery.
424
+ - **picking-a-format** — choosing `--format` / `--content-format` per consumer.
425
+
426
+ Full documentation: <https://docs.xberg.io>
427
+ GitHub: <https://github.com/xberg-io/xberg>