Skip to main content

rindo-convert — the Rindo converter agent (KB2)

Vision-grounded conversion of hard formats (text-layer PDF, scanned PDF, PPTX) into reviewable Rindo documents. Invoked by rindo-runner through the command-template contract; the result is always a REV-8 pending draft a human approves — the agent can never publish.

The rendered page is the only ground truth. Machine extraction (Docling for PDFs, python-pptx for decks) is a text donor the model may copy characters from — never a structure authority. A deterministic repair pass (ported from the Rindo worker's extraction pipeline, with drift tests) runs on every page regardless of model quality. DOCX / XLSX / CSV / HTML / MD / TXT are declined politely: their machine representation loses ~nothing a render carries.

Operator documentation lives in the Rindo ops runbook §4.7 (register the agent, mint the runner token, designate converter_agent_id, duration + cost guidance). This README is the package-local quickstart.

Install (on the runner host)

rindo-convert is Apache-2.0 (LICENSE beside this file) — like rindo-runner, not part of the proprietary Software. It is published on PyPI:

uv tool install rindo-convert                # base install — scanned-PDF + PPTX arms work
uv tool install 'rindo-convert[docling]'     # + the Docling scaffold for text-layer PDFs (~5 GB)
# from a source checkout instead: cd agents/converter && uv sync [--extra docling]

Host prerequisites:

  • PPTX arm: LibreOffice (soffice) and CJK fonts covering the deck's script (fonts-noto-cjk; verify fc-match :lang=ja resolves to a JP face — the render is the ground truth, so a substituted face degrades silently). The tool refuses to run the PPTX arm without a JA-capable font.
  • PDF arms: nothing — pypdfium2 ships wheels; poppler is not needed.
  • An Anthropic API key (ANTHROPIC_API_KEY, or an ant auth login profile).

Wire it to the runner

# ~/.config/rindo-runner/config.toml
server_url = "https://rindo.example.com"
token      = "rndr_..."
command    = "/opt/rindo-convert/run.sh {payload_file}"
poll_timeout = 60
#!/usr/bin/env bash
# /opt/rindo-convert/run.sh   (chmod 700 — it holds the API key)
set -euo pipefail
export ANTHROPIC_API_KEY="sk-ant-..."
export RINDO_CONVERT_MODEL="claude-opus-5"
exec /opt/rindo-convert/.venv/bin/rindo-convert "$1"

The runner injects RINDO_SERVER_URL / RINDO_MCP_URL / RINDO_RUNNER_TOKEN / RINDO_JOB_ID; model and engine knobs ride the ambient environment (the wrapper). One job at a time per runner token.

Knobs (RINDO_CONVERT_*)

Var Default Meaning
MODEL claude-opus-5 Vision model. The request shape is capability-gated per model — see config.py's MODEL_CAPS.
ESCALATE_MODEL (unset) Documented re-request rung for decks whose review effort is too high.
EFFORT high output_config.effort on models that take it.
MAX_PAGES 60 Above it the job declines with a split-the-file message.
MAX_TOKENS 3000000 Cumulative spend ceiling for the whole job (checked between pages against real usage).
PAGE_MAX_TOKENS 64000 Per-call max_tokens (thinking shares this cap).
PAGE_TIMEOUT_SECONDS 240 Per-page wall clock.
DEADLINE_MARGIN_SECONDS 90 Reserved before the job's deadline_at — stop early and salvage rather than be killed.
MAX_FAILED_PAGE_RATIO 0.25 Above it, abort instead of submitting a placeholder-riddled draft.
RENDER_DPI 150 Raster DPI; the long edge is clamped to the model's vision ceiling regardless. A cost knob.
ENGINE docling docling | none (pure vision). Docling failure degrades to none with a provenance note.
DONOR_ESCALATION 0 §5.4 conditional second donor. OFF unless measurement M2 ruled it in.
SOFFICE soffice LibreOffice binary path.
WORKDIR (mkdtemp) Scratch — defaults outside any repo; kept on failure (it holds final.md, the manual-resubmit remedy).
KEEP_WORKDIR 0 Keep it on success too (debugging, bench).
DRY_RUN 0 Convert but skip all MCP traffic. The bench's measurement lever.
FALLBACKS default Server-side refusal fallback on models that support it (off to disable).
USAGE_LOG ~/.cache/rindo-convert/usage.jsonl One JSONL line per page (real usage, never estimates).
LOG_LEVEL / LOG_JSON info / 0 stderr logging (stdout is the job-summary channel).

Exit codes (the runner maps non-zero → job failed)

Code Meaning
0 Draft submitted (or content hash-equal to head — a recorded no-op)
1 Decline: out-of-scope format, page cap, or a pending draft already on the target
2 Config/environment error (API key, soffice, CJK font, bad env value)
3 Conversion failure (download, render, model, submit, budget)

The classified reason is always the final RESULT: line of the output tail (agent_jobs.result.summary_md on the server), after the usage/cost summary.

Development

uv run pytest -q                      # offline: no network, no key, no docling, no soffice
uv run ruff check . && uv run ruff format --check .

Ported backend symbols (postpass.py, ooxmlguard.py, the router constants) are byte-copies with drift tests: tests/test_ported_drift.py reads the backend sources by relative path and AST-compares. When it fails, re-sync the copy, re-record the sha, and re-run the postpass goldens. The bench harness (measurements M1/M2, the judging protocol) lives in bench/ and writes only outside the repo.

Metadata

Release files for rindo-convert 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rindo-convert 0.1.0
File Size Uploaded
rindo_convert-0.1.0.tar.gz 331.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rindo-convert 0.1.0
File Interpreter ABI Platform
rindo_convert-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 415.5 kB

Release files / rindo_convert-0.1.0.tar.gz

Download URL rindo_convert-0.1.0.tar.gz
Size 331.7 kB
Tags Source
SHA-256 checksum
How to use checksums
4d8d53aa8f9c3686c8edfef735bc057449959c5e8b88e676e150e72fbe865d69
BLAKE2b-256 checksum
How to use checksums
a989d6d9e043130a0c70369824c0283f2482c1623f024bda6c77f0f16acd86c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / rindo_convert-0.1.0-py3-none-any.whl

Download URL rindo_convert-0.1.0-py3-none-any.whl
Size 83.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0afdfd7291b4bb9790f8cc91a281ad0538bc7edc36cf4e9c0808fcbe6dd2db32
BLAKE2b-256 checksum
How to use checksums
bb47c202a412ce3ab7240bbc2420777a940ea5df8c96c428639e3dc3ad74525d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

1.0.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page