Skip to content

Mark1708/convertr

Repository files navigation

convertr

Русская версия

Universal file-format converter CLI — convert 50+ registered formats with one binary.

CI Go Reference Go Report Card License: MIT

convertr wraps pandoc, ffmpeg, LibreOffice, ImageMagick, jq, yq, Tesseract and a dozen more tools behind a single convertr FILE -o OUT interface. It finds the shortest conversion path automatically — you never need to remember which binary handles which format.

Documents: MD · DOCX · PDF · ODT · HTML · EPUB · RST · TeX · PPTX
Images: JPG · PNG · WebP · SVG · AVIF · HEIC · GIF
Video: MP4 · MKV · WebM · AVI · MOV
Audio: MP3 · FLAC · AAC · WAV · OGG
Data: JSON · YAML · TOML · CSV · XLSX
OCR: image → text via Tesseract


At a glance

Area Details
Runtime Go 1.25+
Interface CLI, watch mode, TUI, built-in Web UI, REST API
Format registry 50+ registered format IDs in internal/formats/known.go; inspect locally with convertr formats
Routing Dijkstra search over installed backend capabilities, with speed/quality route policies
Backend tooling pandoc, ffmpeg, LibreOffice, ImageMagick, jq, yq, Tesseract, csvkit, AsciiDoctor, Calibre, pdfcpu, and plugin backends
Contributor checks make build, make test, make lint; CI also runs go vet, race-enabled tests, go build ./..., and govulncheck

Useful next reads: CONTRIBUTING.md, SECURITY.md, docs/api.md, docs/docker.md, and docs/remediation-audit.md.


Why convertr?

Most conversions need a different tool: pandoc for documents, ffmpeg for video, convert for images. convertr wraps them all — just specify source and target format, and it picks the right backend automatically, even chaining multiple tools when no direct route exists.

  • Zero format memorisation — just specify source and target
  • Batch conversion with parallel workers and retry policies
  • Watch mode: auto-convert on file save
  • Plugin protocol for custom backends

Table of contents


Install

go install

go install github.com/Mark1708/convertr/cmd/convertr@latest

Requires Go 1.25+.

Homebrew

brew install mark1708/tap/convertr

From source

git clone https://github.com/Mark1708/convertr.git
cd convertr
go build -o ~/.local/bin/convertr ./cmd/convertr

Install backend dependencies

# macOS
./scripts/install-deps-macos.sh

# Debian / Ubuntu
./scripts/install-deps-linux.sh

Verify

convertr version
convertr doctor

doctor checks every backend binary, prints the detected version, and suggests brew install / apt-get install commands for anything missing.


Docker

Use ghcr.io/mark1708/convertr for the full-backends image with the Web UI, REST API, and CLI. See docs/docker.md for run commands, tags, volumes, health checks, and image caveats.


Quick start

# Convert a single file — format is inferred from the extension.
convertr report.docx -o report.md

# Specify target format explicitly.
convertr notes.md --to pdf -o notes.pdf

# Batch: convert a whole directory, one Markdown per DOCX.
convertr -r ./docs/ -o ./out/ --to md

# Parallel batch with 4 workers.
convertr -r ./inbox/ -o ./outbox/ --to pdf -j 4

# Stdin → stdout (pipe-friendly).
cat data.json | convertr - --from json --to yaml -o -

# Dry run — print the planned conversions without executing.
convertr -r ./docs/ -o ./out/ --to md --dry-run

# Prefer higher-quality routes when several chains are available.
convertr source.docx -o out.pdf --route-policy quality

# Avoid lossy edges when a lossless route exists.
convertr image.png -o out.webp --avoid-lossy

# Restrict route search to short chains.
convertr source.md -o out.pdf --max-hops 2

# Watch a directory and convert on every change.
convertr watch ./inbox -o ./outbox --to md

# Show all known formats and the conversion graph.
convertr formats
convertr formats --dot | dot -Tsvg > /tmp/formats.svg

Config — config.toml

Lives at ~/.config/convertr/config.toml or wherever --config points.

Create a default file:

convertr config init

Full example

# ~/.config/convertr/config.toml

[defaults]
quality     = 85       # 0–100; backend-specific interpretation
workers     = 0        # 0 = GOMAXPROCS; > 0 = fixed count
on_error    = "skip"   # skip | stop | retry
on_conflict = "overwrite" # overwrite | skip | rename | error

# Fonts used by PDF-producing backends (pandoc with xelatex/lualatex).
# `convertr config init` seeds these with OS-appropriate defaults; any empty
# field falls back to the built-in platform default.
[fonts]
mainfont = "PT Serif"
monofont = "Menlo"
sansfont = "Helvetica Neue"

# Extra arguments forwarded to individual backends.
[backend.pandoc]
extra_args = ["--wrap=none", "--variable=lang:ru"]

[backend.ffmpeg]
extra_args = ["-preset", "fast"]

[backend.tesseract]
extra_args = ["--dpi", "300"]

# Named profiles — activate with --profile NAME.
[profile.hi-res]
quality = 100

[profile.ci]
workers     = 4
on_error    = "stop"
on_conflict = "error"

[profile.ocr]
quality = 95

Defaults

Field Type Default Description
quality int 85 Conversion quality hint (0–100)
workers int 0 Parallel workers; 0 = GOMAXPROCS
on_error string skip What to do when a job fails
on_conflict string overwrite What to do when output already exists

Environment overrides

Variable Overrides
CONVERTR_QUALITY defaults.quality
CONVERTR_WORKERS defaults.workers
CONVERTR_ON_ERROR defaults.on_error
CONVERTR_ON_CONFLICT defaults.on_conflict

Priority order

hardcoded defaults → config file → environment variables → CLI flags

CLI flags always win. A missing config file is not an error — defaults are used.


CLI reference

Global flags

Available on every subcommand:

Flag Short Default Description
--config ~/.config/convertr/config.toml Path to config file
--profile Activate a named profile
--lang Language override (en, ru)
--verbose -v 0 Increase log verbosity (repeatable: -vvv)
--quiet -q false Silence all output except errors
--json false Emit structured JSON logs
--no-color false Disable ANSI color

Convert (default command)

convertr FILE [FILE...] -o OUTPUT [flags]

When no subcommand is given, convertr treats arguments as input files and runs the conversion pipeline.

Flags:

Flag Short Default Description
--output -o Output file, directory, or - for stdout
--to Target format ID (e.g. md, pdf, mp3)
--from Source format override (auto-detected if omitted)
--dry-run false Print planned conversions without running them
--workers -j 1 Parallel workers
--on-error skip Error policy: skip | stop | retry
--on-conflict overwrite Conflict policy: overwrite | skip | rename | error
--recursive -r false Recurse into directories
--mkdir false Create output directory if it does not exist
--named Backend-specific named option (backend.key=value, repeatable)
--strip-meta false Request metadata stripping when the selected backend supports it
--route-policy speed Route selection policy: speed | quality
--avoid-lossy false Exclude routes containing lossy conversion edges
--max-hops 4 effective Maximum conversion route hops. Omit or pass 0 to use the default.

Input types:

convertr file.md -o out.pdf              # single file
convertr a.md b.md -o out/ --mkdir       # multiple files → output directory (created if absent)
convertr "src/**/*.md" -o out/ --to pdf  # glob
convertr -r ./src/ -o ./out/ --to html   # directory (recursive)
convertr - --from json --to yaml -o -    # stdin → stdout

Output directory resolution:

When multiple input files are given, the output path is always treated as a directory — even if no trailing / is present. If the directory does not yet exist, convertr will:

  • ask interactively Create it? [y/N] when running in a TTY, or
  • return an error with a hint to use --mkdir in non-interactive mode.
# Auto-create the output directory:
convertr -r ./docs/ -o ./out --to md --mkdir

# TTY prompt (no --mkdir needed):
convertr -r ./docs/ -o ./out --to md
# Output directory does not exist: ./out
# Create it? [y/N]

Error policies:

Policy Behaviour
skip Record error, continue with remaining jobs
stop Abort all remaining jobs on first error
retry Retry with exponential backoff (max 3 attempts)

Conflict policies:

Policy Behaviour
overwrite Replace existing output file
skip Leave existing output file unchanged
rename Append numeric suffix (.1, .2, …)
error Fail if output file exists

Route policies:

Route policy flags affect the route that actual conversions execute. Route previews from the HTTP API use the same policy semantics.

Option Behaviour Use when
--route-policy speed Default. Minimise route cost. You want the shortest or cheapest available chain.
--route-policy quality Prefer the route with the best bottleneck quality, then use cost as the tie-breaker. You care more about preserving fidelity than picking the cheapest path.
--avoid-lossy Exclude lossy conversion edges before route selection. You only want lossless routes. If every route is lossy, conversion reports no route.
--max-hops N Limit the number of conversion steps. You want to reject long chains, even if a longer route exists.

doctor

convertr doctor

Checks every backend binary: detects the installed version, shows the full path, and prints an install hint for anything missing.


backends

convertr backends list
convertr backends status [BACKEND_ID...]
convertr backends install [BACKEND_ID...] [--missing] [--dry-run] [-y]

Backend management commands use the bundled install manifests:

  • list prints known backend IDs, display names, installed/missing status, and install hints.
  • status prints detailed status for all backends or selected backend IDs.
  • install prints an install plan and runs the detected package manager unless --dry-run is set.

Install flags:

Flag Short Default Description
--dry-run false Print the install plan without executing it
--missing false Install every missing backend
--yes -y false Skip confirmation prompts

formats

convertr formats
convertr formats --dot | dot -Tsvg > graph.svg

--dot emits a Graphviz DOT graph of all available conversion edges (coloured by format category).


watch

convertr watch SRC -o DST --to FORMAT [flags]

Watches SRC recursively and converts every new or modified file to DST.

Flags:

Flag Default Description
--output / -o Output directory (required)
--to Target format (required)
--from Source format override
--debounce 300ms Wait after last event before converting
--on-delete keep What to do when source is deleted: keep | remove | archive

See Watch mode for details.


config

convertr config print      # Show active config with value sources
convertr config init       # Create default config file
convertr config validate   # Validate TOML syntax

config print shows each field, its current value, and where it came from (default / file / env / flag).


plugins

convertr plugins list   # List convertr-* executables in PATH
convertr plugins test   # Probe each plugin's capabilities subcommand

See Plugins for the protocol.


pdf

convertr pdf merge -o out.pdf a.pdf b.pdf [c.pdf ...]
convertr pdf split -o out-dir in.pdf
convertr pdf rotate in.pdf -a 90 [-o out.pdf]
convertr pdf crop in.pdf -d "0 0 100 100" [-o out.pdf]
convertr pdf optimize in.pdf [-o out.pdf]
convertr pdf encrypt in.pdf -p PASSWORD [-o out.pdf]
convertr pdf decrypt in.pdf [-p PASSWORD] [-o out.pdf]
convertr pdf watermark in.pdf -d "text:CONFIDENTIAL" [-o out.pdf]
convertr pdf stamp in.pdf -d "text:DRAFT" [-o out.pdf]
convertr pdf nup -o out.pdf -n 4 in.pdf [more.pdf ...]
convertr pdf booklet -o out.pdf -n 4 in.pdf [more.pdf ...]
convertr pdf extract in.pdf -o out-dir
convertr pdf validate in.pdf
convertr pdf info in.pdf

PDF commands are processor operations backed by pdfcpu; they do not add format-conversion routes.

Common flags:

Flag Short Used by Description
--output -o most operations Output file or directory
--angle -a rotate Rotation angle: 90, 180, 270, or -90
--desc -d crop, watermark, stamp Operation description passed to pdfcpu
--password -p encrypt, decrypt PDF password
--mode -m encrypt Encryption mode
--n -n nup, booklet Grid size

info

convertr info FILE

Detects the file format, then probes metadata using the first available tool: ffprobe (audio/video), exiftool (images/documents), file (fallback).


version

convertr version

serve

convertr serve [--addr ADDR] [--api-only]

Starts the HTTP API and, by default, the built-in Web UI.

Flag Default Description
--addr :8080 HTTP listen address
--api-only false Serve only the REST API, without the browser UI

tui

convertr tui

Starts the interactive terminal UI. See TUI.


Backends

Each backend is an init()-registered plugin that bridges one or more external binaries to the router.

convertr probes $PATH at startup and excludes capabilities whose binaries are missing from the conversion graph. If two backends declare the same edge, Dijkstra automatically picks the available one — e.g. xlsx → csv prefers csvkit when in2csv/xlsx2csv are installed and falls back to libreoffice otherwise. Run convertr doctor to see which binaries are detected and which are missing.

Pandoc

Binary: pandoc · brew install pandoc / apt install pandoc

From To
md html docx odt pdf rst epub tex txt typst ipynb pptx mediawiki jira opml
html md docx pdf txt
docx md html pdf odt txt rst
odt md docx html txt
rst md html pdf txt
epub md html txt
tex md html pdf
org md html pdf
typst md pdf
ipynb md html pdf
rtf md (then any markup via a pandoc chain)
fb2 md html epub
mediawiki dokuwiki jira textile docbook opml md
bibtexcsljson (bibliography)

PDF output picks xelatexlualatexpdflatex in order of capability; when a fontspec-aware engine is chosen, convertr injects -V mainfont / -V monofont / -V sansfont from the [fonts] section (with OS-appropriate defaults) and -V geometry:margin=2cm. Any variable you set explicitly via --named pandoc.mainfont=... or a -V … entry in extra_args disables the matching default — user values always win.

Config: [backend.pandoc] extra_args = ["--wrap=none"]


FFmpeg

Binary: ffmpeg · brew install ffmpeg / apt install ffmpeg

From To
mp4 mkv webm mov avi (all video formats, bidirectional)
mp3 flac aac ogg wav m4a opus (all audio formats, bidirectional)
video formats gif (two-pass palette)
video formats audio formats (extract audio)

Quality hint → CRF (video) or bitrate (audio).

Config: [backend.ffmpeg] extra_args = ["-preset", "fast"]


ImageMagick

Binary: magick (IM7) or convert (IM6) · brew install imagemagick

From To
jpg png webp gif tiff bmp (all raster formats, bidirectional)
avif raster formats (and vice versa)
svg raster formats, avif
heic raster formats

Quality hint → -quality N.


LibreOffice

Binary: soffice · brew install --cask libreoffice / apt install libreoffice

From To
doc docx odt rtf odt docx pdf txt
xlsx ods csv ods xlsx
pptx odp odp pptx pdf

Each conversion runs with an isolated -env:UserInstallation directory to allow safe parallel execution.


jq

Binary: jq · brew install jq

From To Notes
json json pretty-print, minify, or transform

Named options: jq.minify=true (compact output), jq.filter=EXPR (custom expression).


yq

Binary: yq · brew install yq

From To
yaml json toml
json yaml toml
toml yaml json

Tesseract (OCR)

Binary: tesseract · brew install tesseract tesseract-lang

From To
jpg png tiff txt

Default language: rus+eng. Override: [backend.tesseract] extra_args = ["-l", "eng"].


CSVKit

Binary: in2csv / xlsx2csv (fallback) · pip install csvkit

From To
xlsx csv
csv json
xlsx json

AsciiDoctor

Binary: asciidoctor · gem install asciidoctor asciidoctor-pdf

From To
adoc html
adoc pdf (requires asciidoctor-pdf)

Calibre

Binary: ebook-convert · brew install --cask calibre / apt install calibre

From To
epub mobi pdf txt fb2
mobi epub pdf txt
fb2 epub mobi pdf txt
azw3 lit epub mobi pdf
odt docx rtf epub
html epub mobi

Named options include calibre.title, calibre.authors, calibre.language, and calibre.pdf_page_numbers.


libjxl

Binaries: cjxl / djxl · brew install jpeg-xl

From To
jpg png jxl
jxl jpg png

Encoding to jxl requires cjxl; decoding from jxl requires djxl. Named options include libjxl.distance, libjxl.effort, and libjxl.jpeg_quality.


resvg

Binary: resvg · brew install resvg

From To
svg png

Named options include resvg.dpi, resvg.zoom, resvg.width, and resvg.height.


pdfcpu

Binary: pdfcpu · brew install pdfcpu

pdfcpu is registered for discovery and doctor output, but it exposes processor operations rather than format-conversion routes. Use convertr pdf ... or the Web UI Tools page for merge, split, rotate, crop, optimize, encrypt, decrypt, watermark, stamp, n-up, booklet, extract, validate, and info operations.


Figlet (ASCII art)

Binary: figlet · brew install figlet

From To
txt ascii

textutil (macOS only)

Binary: textutil (bundled with macOS)

From To
doc rtf txt html

Available only on macOS; compiled out on other platforms via build tag.


Watch mode

convertr watch ./inbox -o ./outbox --to md
convertr watch ./raw   -o ./web   --to html --debounce 500ms --on-delete archive

How it works:

  1. Recursively watches SRC using fsnotify.
  2. Debounces rapid edits — waits --debounce (default 300 ms) after the last event before triggering.
  3. Detects the format of the changed file, finds a route, converts, writes to DST.
  4. New subdirectories are watched automatically.

Delete policies:

Policy What happens when source is deleted
keep Output file is left as-is (default)
remove Output file is deleted
archive Output file is moved to DST/.archive/

Graceful shutdown: Press Ctrl+C (SIGINT / SIGTERM). convertr drains in-flight conversions and exits 0.


Plugins

convertr supports external plugins — any executable named convertr-* found in PATH.

Plugin protocol

A plugin must implement capabilities and can implement conversion and process subcommands for the operations it advertises.

convertr-NAME capabilities

Protocol v2 writes a JSON manifest to stdout and exits 0:

{
  "protocol_version": 2,
  "version": "1.2.3",
  "diagnostics": [
    {
      "level": "warning",
      "code": "missing-optional-tool",
      "message": "zopfli not installed; using default encoder"
    }
  ],
  "capabilities": [
    {
      "from": "wasm",
      "to": "wat",
      "cost": 2,
      "quality": 95,
      "lossy": false,
      "metadata": { "engine": "wasm-tools" }
    }
  ],
  "operations": [
    {
      "name": "pdf.merge",
      "description": "Merge PDF files",
      "params": { "pages": "optional page selection" }
    }
  ]
}

Manifest fields:

  • protocol_version — plugin protocol version. convertr supports v1 and v2; explicit future versions greater than 2 are rejected with a clear discovery error so incompatible plugins are not silently accepted. If an object omits this field, convertr treats it as v2.
  • version — optional plugin version string for diagnostics and support.
  • diagnostics — optional manifest-level list of {level, code, message} entries. Use it for actionable status such as missing optional tools or degraded quality.
  • capabilities — conversion edges.
  • operations — process operations supported by the process subcommand.

Capability fields:

  • from / to — format IDs (must match convertr's registry or be new IDs)
  • cost — routing cost (1–10; lower = preferred over built-in backends); defaults to 5 when omitted or non-positive
  • quality — optional quality hint (0–100); higher is better for quality-aware routing
  • lossy — optional boolean telling convertr whether this edge loses information
  • metadata — optional string map for plugin-specific edge metadata

Operation fields:

  • name — operation ID, for example pdf.merge or image.resize
  • description — optional human-readable summary
  • params — optional parameter name to description map

v1 compatibility

The v1 bare JSON array remains supported exactly for conversion-only plugins:

[
  { "from": "wasm", "to": "wat",  "cost": 2 },
  { "from": "wat",  "to": "wasm", "cost": 2 }
]

v1 has no manifest-level version, diagnostics, quality, lossy, metadata, or operations. Use v2 for new plugins.

convertr-NAME convert

convertr-NAME convert \
  --from FROM \
  --to   TO   \
  --input  /tmp/in.wat  \
  --output /tmp/out.wasm \
  [--opt key=value ...]

Exit 0 on success. On failure: exit non-zero, write a single error line to stderr.

convertr-NAME process

Plugins that advertise operations must implement process:

convertr-NAME process \
  --operation OP \
  --input /tmp/a.pdf \
  --input /tmp/b.pdf \
  --output /tmp/out.pdf \
  [--param key=value ...] \
  [--opt key=value ...]

Exit 0 on success. On failure: exit non-zero and write a single actionable error line to stderr.

Writing a plugin

#!/usr/bin/env bash
case "$1" in
  capabilities)
    cat <<'JSON'
{"protocol_version":2,"version":"0.1.0","capabilities":[{"from":"foo","to":"bar","cost":3,"quality":90,"lossy":false}]}
JSON
    ;;
  convert)
    # parse --from --to --input --output from "$@"
    my-tool "$INPUT" "$OUTPUT"
    ;;
esac

Name it convertr-myplugin, place it in your $PATH, and convertr plugins list will find it immediately.

See pkg/plugin/protocol.go for the Go type definitions.


Progress reporting

convertr picks a reporter automatically based on the environment:

Environment Reporter
Interactive TTY In-place progress bar ([3/10] converting report.md)
Non-TTY / pipe Plain text, one line per job
--json or CI=1 JSON Lines

JSON Lines format

{"event":"start",   "total":10, "ts":"2026-04-17T12:00:00Z"}
{"event":"convert", "file":"report.md", "done":1, "total":10, "status":"ok",    "ts":"..."}
{"event":"convert", "file":"broken.doc","done":2, "total":10, "status":"error", "error":"exit status 1", "ts":"..."}
{"event":"done",    "ts":"2026-04-17T12:00:05Z"}

JSON output is never localised — it is a stable scripting contract.


TUI

convertr tui

Starts the interactive terminal UI.

Available screens:

  • Backend Status — inspect registered backends, availability, and capability counts.
  • Route Explorer — select source and target formats, then preview the conversion route.
  • Convert — run an interactive conversion flow from an input file path.
  • Quit — exit the TUI.

Navigation:

  • Arrow keys or j / k — move selection.
  • Enter — select or confirm.
  • b or Esc — go back.
  • q — quit.

Web UI

convertr also ships with a built-in browser UI for conversions, backend inspection, and file operations:

convertr serve
# or bind explicitly
convertr serve --addr 127.0.0.1:8080

Convert

Upload a file, pick the target format, preview the route, and download the result.

convertr web UI: Convert file page with empty upload drop zone

Upload a file and pick the target format. The source format is auto-detected from the extension.

The route explorer shows the selected backend and conversion path before execution.

convertr web UI: Route explorer showing json to yaml conversion via yq backend

Route preview for json to yaml through the yq backend.

After conversion completes, the result is ready for download.

convertr web UI: Successful conversion with download button

Successful conversion with one-click download.

Backends

The Backends page lists detected tools, versions, installation paths, and supported conversions — the browser equivalent of convertr doctor.

convertr web UI: Backends page showing installed backends and supported formats

Backend dashboard with installed tools and supported conversion counts.

Tools

The Tools page exposes processor operations such as PDF merge, split, rotate, and optimize.

convertr web UI: PDF Tools page for merge, split, rotate, and optimize operations

Process PDF files through browser-based operations.


Architecture

cmd/convertr/          cobra entry point, blank imports for all backends

internal/
  cli/                 subcommand implementations (convert, watch, doctor, …)
  backend/             Backend interface, Options, registry for backends and processors, execx helper
    backends/
      pandoc/          pandoc backend
      ffmpeg/          ffmpeg backend
      imagemagick/     ImageMagick backend
      libreoffice/     LibreOffice backend (process-isolated)
      jq/              jq backend
      yq/              yq backend
      tesseract/       Tesseract OCR backend
      csvkit/          CSVKit backend
      asciidoctor/     AsciiDoctor backend
      calibre/         Calibre ebook backend
      libjxl/          JPEG XL backend
      resvg/           SVG renderer backend
      pdfcpu/          PDF processor operations
      figlet/          figlet backend
      textutil/        textutil backend (darwin only)
      plugin/          external plugin discovery and execution for conversion capabilities and process operations
  core/                Engine orchestration for conversion and processing requests
  config/              TOML loader, env overrides, profile merge, FieldSource
  deps/                Dependency/install manifest helpers
  fonts/               PDF font defaults and resolution
  formats/             Format registry, extension/MIME detection
  installer/           Package-manager detection and backend install plans
  router/              Dijkstra routing on the capability graph
  runner/              Job execution: serial + parallel pool, retry, conflict resolution
  server/              REST API, Web UI, uploads, jobs, downloads, SSE events
  sink/                Output path resolution, atomic write, conflict policy, template
  source/              Input iterators: file, glob, dir, stdin (iter.Seq2)
  tui/                 Bubble Tea terminal UI screens
  watch/               fsnotify wrapper with debounce, recursive add, delete handling
  progress/            Reporter interface: TUI, plain, JSON Lines, Noop
  i18n/                go-i18n v2, locales/en.json + ru.json
  slogx/               slog initialisation, JSON/text handlers, verbosity levels
  xdg/                 XDG Base Directory paths

pkg/plugin/            Public plugin protocol types (for plugin authors)

Key invariants

  • Atomic write — all output goes to os.CreateTemp then os.Rename. Never written directly.
  • TempDir per jobos.MkdirTemp("", "convertr-*") per conversion chain, removed with defer os.RemoveAll.
  • LibreOffice isolation — every soffice call gets -env:UserInstallation=file:///tmp/convertr-lo-PID to allow parallel execution.
  • Context propagation — all backends receive ctx and use exec.CommandContext.
  • Route policy parity: actual conversions and route previews use the same speed, quality, avoid_lossy, and max_hops semantics.
  • Registry isolation: backend.Registry owns both conversion backends and processors per engine instance. DefaultRegistry and package-level wrappers preserve legacy init() registration behaviour for CLI and older integrations.
  • Exit codes0 success · 1 error · 2 CLI usage · 3 no route · 4 partial batch · 5 missing backend.

Troubleshooting

cannot determine target format Provide --to FORMAT or give the output file a known extension (e.g., -o out.pdf).

no conversion route No installed backend covers the requested From → To pair. Run convertr doctor to see what is missing, and install the relevant tool.

convertr doctor shows a backend as MISSING Install it via the suggested command. On macOS run ./scripts/install-deps-macos.sh to install everything at once.

LibreOffice hangs or produces a corrupt output Make sure no other soffice process is running with the same UserInstallation directory. Parallel convertr jobs each get a unique directory; external LibreOffice processes may conflict.

Watch mode does not pick up changes inside a new subdirectory convertr watches new directories recursively — but only directories created after watch starts that trigger a CREATE event. Re-start watch if you have pre-existing deep trees.

Output file is not where I expected When --output is a directory, the output file is named <stem>.<target-ext>. Use --on-conflict rename if you are converting multiple files with the same stem.

Plugin not found by convertr plugins list Ensure the binary is named convertr-NAME (not convertrNAME), is executable (chmod +x), and its directory is in $PATH.

Enable verbose logging

convertr -vvv doctor
CI=1 convertr -r ./src/ -o ./out/ --to md   # structured JSON logs

License

MIT — see LICENSE.