Settings can come from three places. Precedence, highest first:
- CLI flag —
--llm-model google/gemini-2.5-flash - Environment variable —
LLM_MODEL=google/gemini-2.5-flash ~/.pdf2md.json— JSON object with any of the keys below- Built-in default
Loaded from .env in the current working directory (walking up) and then ~/.env.
| Variable | Purpose |
|---|---|
OPENROUTER_API_KEY |
OpenRouter API key |
ANTHROPIC_API_KEY |
Anthropic API key |
OPENAI_API_KEY |
OpenAI API key |
PDF2MD_BACKEND |
Default backend: vision or marker |
LLM_PROVIDER |
Default provider |
LLM_MODEL |
Default per-page model |
CLEANUP_MODEL |
Model used for the cleanup pass (vision backend) |
CLEANUP_RPM |
Cap sustained cleanup requests per minute |
Run pdf2md config init to write a starter file. Unknown keys are rejected.
| Key | Type | Default | Notes |
|---|---|---|---|
output_dir |
path | ./output |
Output directory |
backend |
vision|marker |
vision |
|
no_llm |
bool | false |
[marker] Skip vision pass |
llm_provider |
string | openrouter |
anthropic, openai, or openrouter |
llm_model |
string | provider-specific | Per-page model |
confidence_threshold |
float | 0.60 |
[marker] Reprocess text below this score |
image_mode |
enum | data-only |
[marker] all, data-only, or none |
max_image_tokens |
int | 1024 |
[marker] Max output tokens per image call |
max_page_tokens |
int | 2200 |
[vision] Max output tokens per page call |
dpi |
int | 200 |
[vision] Rasterization DPI |
rasterize_workers |
int | 4 |
[vision] Rasterization thread-pool workers |
cleanup |
bool | true |
[vision] Run document-wide cleanup pass |
cleanup_model |
string | falls back to llm_model |
[vision] Model for the cleanup pass |
crop_figures |
bool | true |
[vision] Crop and inline figure regions |
url_guard_enabled |
bool | true |
[vision] Reject hallucinated URLs |
max_concurrency |
int | 16 |
Max concurrent LLM calls |
requests_per_minute |
int or null | null |
Cap sustained per-page requests per minute |
cleanup_concurrency |
int | 16 |
[vision] Max concurrent cleanup-section calls |
cleanup_rpm |
int or null | null |
[vision] Cap sustained cleanup requests per minute |
dry_run |
bool | false |
[marker] Show what would be sent to the LLM |
verbose |
bool | false |
Log per-page / per-image progress |
Default models per provider (when llm_model is unset):
| Provider | Model |
|---|---|
anthropic |
claude-sonnet-4-20250514 |
openai |
gpt-4o |
openrouter |
anthropic/claude-sonnet-4 |
--fast— vision backend, no cleanup pass. Lower latency and cost.--raw— vision backend, no cleanup, no figure cropping, no URL guard. Use when debugging extraction.
--fast and --raw are mutually exclusive, and neither can combine with --cleanup.
~/.pdf2md.json for a cheap-and-fast default:
{
"backend": "vision",
"llm_provider": "openrouter",
"llm_model": "google/gemini-2.5-flash",
"cleanup": true,
"cleanup_model": "deepseek/deepseek-v3.2-exp",
"dpi": 200,
"max_concurrency": 16
}Override the model just for one run:
pdf2md convert paper.pdf --llm-model anthropic/claude-sonnet-4Throttle when you're rate-limited:
pdf2md convert paper.pdf --rpm 60 --cleanup-rpm 30