Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when extracting from many files at once with shared config, bounded parallelism, per-file overrides, and error recovery. Covers the `batch` command, `--file-configs`, `--max-concurrent`, and output layout.
.claude/skills/xberg-io-batch-extraction/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -12% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -33% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 18% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 108% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 29% | 0% |
Use this when processing a directory or glob of documents in one pass. xberg batch shares one extraction config across every file, runs extractions concurrently, and returns one structured array — failures on individual files do not abort the run.
bash# Glob expands to many paths; results come back as a JSON array (default) xberg batch *.pdf # Mixed formats, markdown content for LLM ingestion xberg batch docs/*.docx --content-format markdown # Recurse with the shell, then extract xberg batch $(find ./corpus -name '*.pdf')
batch defaults to --format json (vs --format text for single extract). Each array entry is a full extraction result, so downstream code can index by position into the input path list.
bashxberg batch reports/*.pdf \ | jq '.[] | {chars: (.content | length), mime: .mime_type}'
--max-concurrent caps how many files extract at once. When omitted, the scheduler derives document concurrency from the total thread budget. Lower it on memory-constrained hosts or when OCR/ML models are active, since each in-flight extraction holds its own buffers. Layout-heavy batches are further limited (1 concurrent extraction for all-PDF-layout batches, 2 for mixed layout):
bash# Cap at 4 concurrent extractions xberg batch scans/*.pdf --ocr true --max-concurrent 4
--max-threads additionally caps total internal threads (Rayon, ONNX intra-op, the batch semaphore) for tightly constrained environments:
bashxberg batch *.pdf --max-concurrent 2 --max-threads 4
A single shared config does not always fit. --file-configs points at a JSON file mapping each path to its own override object, merged on top of the shared config for that file only:
json{ "scan.pdf": { "force_ocr": true }, "report.pdf": { "output_format": "markdown" }, "data.xlsx": { "output_format": "json" } }
bashxberg batch scan.pdf report.pdf data.xlsx --file-configs overrides.json
Keys are file paths (matching the paths passed on the command line); values are per-file extraction config objects in snake_case, the same shape as a config file.
For text/toon output with image extraction, --output-dir controls where referenced image files (e.g. image_0.png) are written; the directory must already exist. JSON output embeds image bytes inline and ignores --output-dir.
bashmkdir -p out/images xberg batch slides/*.pptx --extract-images true --output-dir out/images --format text
Batch extraction is fault-tolerant per file: one unreadable or corrupt document does not stop the rest. Inspect results for partial content and surfaced errors rather than relying on the process exit code alone. Pair with --max-concurrent to avoid exhausting memory when a few large files sit in a big batch.
Every extract flag also applies to batch (OCR, chunking, layout, content format, etc.) and is shared across all files unless a --file-configs entry overrides it:
bashxberg batch invoices/*.pdf \ --layout --layout-table-model slanet_wireless \ --content-format markdown --max-concurrent 8
A config file works too and auto-discovers from the cwd upward:
tomloutput_format = "markdown" [ocr] backend = "tesseract" language = "eng"
bashxberg batch corpus/*.pdf --config xberg.toml
From Python, extract_batch takes a list of ExtractInputs and returns one envelope whose results array holds a document per input:
pythonfrom xberg import ExtractInput, extract_batch, ExtractionConfig config = ExtractionConfig(output_format="markdown") inputs = [ExtractInput(uri=p) for p in ["a.pdf", "b.docx", "c.xlsx"]] output = await extract_batch(inputs, config) for doc in output.results: print(len(doc.content))
Per-input overrides go on ExtractInput.config (a FileExtractionConfig). Node.js mirrors this with extractBatch; Rust uses extract_batch(inputs, &config). See references/python-api.md, references/nodejs-api.md, and references/rust-api.md in the sibling xberg skill.
When the xberg MCP server is registered, prefer the extract_batch tool over shelling out — it takes an array of input objects and a config object and returns structured results directly.
batch defaults to --format json,extract to --format text. Set --format explicitly if a script depends on one shape.
--output-dir must exist — the CLI does not create it.--max-concurrent ceiling.
--file-configs path keys — must match the paths as passed on thecommand line, not absolute-resolved variants.
See references/cli-reference.md for the full batch flag set.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 47,287 | 7,039 | -85% | 1 | 1 | 0% | 2,810 | 2,483 | -12% | 0 | 0 | — |
case-02 | fail→pass | 18,566 | 5,838 | -69% | 1 | 1 | 0% | 3,487 | 2,345 | -33% | 0 | 0 | — |
case-03 | fail→pass | 12,224 | 6,980 | -43% | 1 | 1 | 0% | 2,281 | 2,697 | +18% | 0 | 0 | — |
case-04 | fail→pass | 5,996 | 6,852 | +14% | 1 | 1 | 0% | 1,127 | 2,344 | +108% | 0 | 0 | — |
case-05 | fail→pass | 7,792 | 3,062 | -61% | 1 | 1 | 0% | 1,383 | 1,783 | +29% | 0 | 0 | — |
case-06 | pass→pass | 27,632 | 5,102 | -82% | 1 | 1 | 0% | 3,991 | 2,176 | -45% | 0 | 0 | — |
case-07 | fail→pass | 14,312 | 11,935 | -17% | 1 | 1 | 0% | 2,657 | 3,333 | +25% | 0 | 0 | — |
case-08 | fail→fail | 8,667 | 7,270 | -16% | 1 | 1 | 0% | 1,532 | 2,491 | +63% | 0 | 0 | — |
case-09 | pass→pass | 3,632 | 3,369 | -7% | 1 | 1 | 0% | 647 | 1,771 | +174% | 0 | 0 | — |
case-10 | pass→pass | 7,308 | 6,088 | -17% | 1 | 1 | 0% | 1,313 | 2,338 | +78% | 0 | 0 | — |
case-11 | fail→pass | 13,015 | 8,473 | -35% | 1 | 1 | 0% | 2,173 | 2,492 | +15% | 0 | 0 | — |
case-12 | fail→pass | 10,419 | 4,303 | -59% | 1 | 1 | 0% | 1,739 | 2,028 | +17% | 0 | 0 | — |
case-13 | fail→pass | 7,118 | 3,306 | -54% | 1 | 1 | 0% | 1,167 | 1,650 | +41% | 0 | 0 | — |
case-14 | fail→pass | 7,410 | 3,902 | -47% | 1 | 1 | 0% | 1,290 | 2,015 | +56% | 0 | 0 | — |
case-15 | fail→pass | 22,697 | 2,749 | -88% | 1 | 1 | 0% | 1,339 | 1,757 | +31% | 0 | 0 | — |
case-16 | fail→pass | 12,885 | 6,109 | -53% | 1 | 1 | 0% | 2,026 | 2,310 | +14% | 0 | 0 | — |
case-17 | fail→pass | 14,076 | 4,318 | -69% | 1 | 1 | 0% | 2,298 | 2,119 | -8% | 0 | 0 | — |
case-18 | pass→pass | 10,166 | 5,836 | -43% | 1 | 1 | 0% | 1,449 | 2,087 | +44% | 0 | 0 | — |
case-19 | fail→fail | 13,817 | 6,714 | -51% | 1 | 1 | 0% | 1,849 | 2,158 | +17% | 0 | 0 | — |
case-20 | fail→pass | 15,985 | 2,831 | -82% | 1 | 1 | 0% | 2,233 | 1,788 | -20% | 0 | 0 | — |
case-21 | fail→pass | 16,187 | 2,918 | -82% | 1 | 1 | 0% | 2,757 | 1,748 | -37% | 0 | 0 | — |
case-22 | fail→pass | 11,859 | 3,540 | -70% | 1 | 1 | 0% | 2,171 | 1,830 | -16% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +73 percentage points is the difference between those two pass rates over the 21 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/17/2026 | +64% |
| gemini-3.6-flash | verified | 8/11/2026 | +50% |
Other measured skills in the registry, with their headline benchmark lift.