draft is a command-line tool that turns a research PDF into a publication-ready Markdown article where every sentence is grounded in a quote-verified claim from the source. This page takes you from a clean machine to a checked, published article, then documents every flag, output and failure mode.
New to the idea? Read how grounding works first — it explains the gate that makes the output trustworthy. Ready to run it? Start below.
Overview
A run moves a paper through four phases. Only two of them call a model; the rest are deterministic Go.
- Read and section. The PDF is read to text and split into sections.
- Extract and verify. Each section is mined for claims, and a claim survives only if its quote appears verbatim in the source and every number in it appears in that quote.
- Write. The verified ledger — and nothing else — is arranged into an article in your house style.
- Attribute and sign. Every sentence is mapped back to the claim behind it, and a C2PA manifest is written beside the article.
Install
Pick one. Homebrew is the shortest path on macOS; go install works anywhere
with a Go toolchain.
Homebrew (macOS)
Go toolchain (any platform)
From source
&&
Dependencies by platform
draft reads PDFs with pdftotext (Poppler) and, offline, writes with a local
Ollama model. .docx is read by textutil on macOS
(built in) or by --reader docling anywhere.
| Platform | Poppler (pdftotext) |
Ollama (offline writing) |
|---|---|---|
| macOS | brew install poppler |
brew install ollama |
| Debian / Ubuntu | sudo apt-get install poppler-utils |
curl -fsSL https://ollama.com/install.sh | sh |
| Fedora | sudo dnf install poppler-utils |
curl -fsSL https://ollama.com/install.sh | sh |
| Windows | scoop install poppler (or choco install poppler) |
download from ollama.com/download |
You need Poppler only for PDF input, and Ollama only for offline runs.
Quickstart
From a clean machine to a checked article in four steps.
1. Check the machine
draft --doctor reports what draft can find: readers, backends, and the paths
it will read from and write to. You need one online backend or a running
Ollama server.
SOURCE TOOLING
✓pdftotext /opt/homebrew/bin/pdftotext
✓docling --reader docling: tables and structure, slower
BACKENDS
✓claude session provider
✓copilot session provider
✓ollama responding at http://127.0.0.1:11434
PATHS
✓drafts (--out) ~/Drop/Drafts
Ready. Run draft --dry-run <source> to check a specific paper.
Real draft --doctor output. A green tick is a backend draft can use; run --dry-run to check one specific paper without calling a model.
2. Run a paper
Point draft at a PDF. In auto mode it picks the first backend you are logged
into and shows a live view of the four phases as they run.
draft ⧇ Drafting Grounded Articles — claude · sonnet · 900–1200 words
Queue
[1/1] ⠙2603.23420.pdf
Pipeline
✓Resolve source
✓Read and section
✓Extract claims
⠙Write article
·Validate and save
Log
· read 5 section(s)
· 6 claim(s) verified, 9 dropped
· writing…
Live Draft
⠙ writing, 342 words visible
57%
## Router-S: conditional compute at a fixed budget
Router-S reaches a validation loss of 3.41 against a dense baseline on an identical token budget — but the same evaluation reports that seed variance exceeds the gap being measured, which is the more important number to sit with.
Sparse routing is designed to cut the compute spent on tokens that are trivially predictable▋
[q] quit · [j/k] up/down · [pgup/pgdn] page
The draft terminal UI mid-run. On the left, the queue and the five-phase pipeline with a live log; on the right, the Live Draft panel — a status line, a progress bar, and the grounded article previewing as it is written, sentence by sentence. Prefer no UI? Add --print (paths to stdout) or --json (one JSON object per job).
When it finishes, the summary line reports the result:
✓Resolve source
✓Read and section
✓Extract claims · 6 verified, 9 dropped
✓Write article
✓Validate and save
✓ 1,066 words via claude in 3m 54s · 16,230 tokens · $0.52
A finished run. Nine of fifteen candidate claims were dropped by the gate — that is grounded-by-construction working, not a bug. A thin source yields a short draft rather than a padded one.
3. Inspect the article set
Each run writes one article as a dated set: three files that stay in sync, plus two a reader can check.
~/Drop/Drafts/2026-07-29/
├── source/2026-07-29-<slug>-body.md # the article — edit this
├── yaml/2026-07-29-<slug>-frontmatter.yaml # adjacent frontmatter
├── final/2026-07-29-<slug>-final.md # combined, ready to publish
└── provenance/
├── 2026-07-29-<slug>-attribution.json # which claim backs each sentence
└── 2026-07-29-<slug>-c2pa.json # C2PA manifest
Edit the body, then regenerate the other two in place with
draft --frontmatter <body.md>. Your curated fields are preserved; only missing
ones are rebuilt. See the article set for the rules.
4. Verify it
draft --verify recomputes the digests and confirms the article still matches
the ledger it was written from.
PROVENANCE
✓made by draft 0.0.35
·written with claude sonnet
✓article unchanged since it was written (64261b97…)
✓claim ledger matches the verified claims
GROUNDING
·claims 6 verified
·attribution 13 of 36 sentences rest on a claim
SOURCES
✓two-column.pdf unchanged since it was read
Verified. The article matches the provenance written beside it.
Edit a sentence the ledger did not support and re-run this: verification fails. Download a real, verifiable set on the provenance & compliance page and run --verify on it yourself.
The run, phase by phase
The live view above maps one-to-one onto the pipeline. Each phase reports as it completes:
| Phase | What happens | Model call? |
|---|---|---|
| Resolve source | Locate the file; bare names resolve against ~/Drop/Drafts/Sources. |
No |
| Read and section | pdftotext (or --reader docling) extracts text; it is split into sections. |
No |
| Extract claims | One call per section mines claims; each is checked against the source and dropped unless its quote is verbatim. | Yes |
| Write article | One call arranges the verified ledger into an article in your house style. | Yes |
| Validate and save | House-style checks run; the set is written with attribution and a C2PA manifest. | No |
Choosing an engine
In auto mode draft walks a preference list and uses the first backend you are
logged into. Force one with --engine <name>, or split the two model phases
with --extract-engine and --write-engine.
Verified, used by auto mode: claude, copilot, codex, grok, agy,
cursor-agent.
Experimental (invocation correct, output unverified; auto uses them only
with --experimental): amp, crush, goose, qwen, gemini-acp,
codex-acp.
Offline: --engine ollama runs the whole pipeline against a local model. If
an online call fails because you are offline, draft fails over to Ollama and
stays there for the rest of the run.
Escape hatch (opt-in): on a machine with no agent CLI, --engine api:anthropic or --engine api:openai calls a hosted API directly, reading
your own key from ANTHROPIC_API_KEY or OPENAI_API_KEY. It is never chosen by
auto mode — the keyless agent-session path stays the default — and it fails
over to Ollama like any other backend.
Readers
| Reader | Use it for | Speed |
|---|---|---|
pdftotext (default) |
Most PDFs. A 62-page paper in about 110 ms. | Fast |
--reader docling |
Papers where tables and structure matter; reads PDF and DOCX on every platform. Mines table cells into claims. | Slower |
PDF, Markdown, plain text and DOCX are all accepted, and so is LaTeX
(.tex) — read directly with no external tool, keeping a formula as exact
text where pdftotext would scramble it.
Command reference
draft [flags] <source> [more-sources...]
Bare filenames resolve against ~/Drop/Drafts/Sources. Each source becomes its
own draft, processed as a queue.
Engine and model
| Flag | Description |
|---|---|
--engine <mode> |
auto (default), ollama, a provider name, or api:<provider> |
--extract-engine <m> |
Backend for claim extraction (default: --engine) |
--write-engine <m> |
Backend for writing (default: --engine) |
--model <name> |
Session-provider model override (e.g. opus) |
--experimental |
Let auto mode use experimental providers |
--num-ctx <n> |
Ollama context window (default 8192) |
--num-predict <n> |
Ollama max output tokens (default 6000) |
Reading and grounding
| Flag | Description |
|---|---|
--reader <name> |
pdftotext (default) or docling |
--style <file> |
JSON house-style file: word band, banned vocabulary, language variant |
--strict-numbers |
Fail on a number found in no verified claim |
--second-gate |
Opt-in semantic pass: drop verified claims a local model finds unsupported by their quote |
--no-cache |
Re-extract instead of reusing cached claims |
--clear-cache |
Delete every cached claim extraction and exit |
Output and workflow
| Flag | Description |
|---|---|
--out <dir> |
Directory to write drafts into (default ~/Drop/Drafts) |
--sources-dir <dir> |
Directory bare filenames resolve against |
--merge |
Combine all sources into one draft |
--force-new |
Draft even if today's folder already has one |
--resume |
Reuse a verified claim ledger from an earlier attempt |
--review <draft.md> |
Enhance an existing draft with surgical edits |
--frontmatter <file> |
Regenerate frontmatter and the final article |
--verify <file> |
Check an article against its provenance, and exit |
--keep-artifacts |
Keep prompt/ledger files beside a successful draft |
Modes and info
| Flag | Description |
|---|---|
--print |
Run without the UI; print draft paths to stdout |
--json |
Machine-readable output: one JSON object per job, or a verification record with --verify |
--dry-run |
Report what a run would do, without calling a model |
--doctor |
Check that this machine can run draft, and exit |
--completion <sh> |
Print a completion script: bash, zsh, or fish |
--version |
Print version and exit |
-h, --help |
Show help |
Examples
The article set
One article. Three files. Always in sync. Plus two a reader can check. Edit
the body, then run draft --frontmatter <body.md> to regenerate the frontmatter
and combined document. Three rules make that safe to run at any time:
- The filename is the article's identity. Its date and slug drive every URL in the frontmatter. Retitle the article and the permalink holds.
- Your edits always win. Curated fields are preserved verbatim; only missing ones are generated. Delete a field to have it rebuilt.
- Unchanged input is a no-op. Reprocessing a set that has not changed rewrites every file byte for byte identically.
The provenance pair is written once, by the run that produced the article, and is not regenerated — it describes the article the ledger was verified against.
Provenance and verification
Every set ships a per-sentence attribution file and a C2PA manifest.
draft --verify <final.md> recomputes the digests and reports whether the
article, the ledger and the sources are all unchanged. It is the reader's check,
not just yours — anyone with the files can run it.
Signed credentials (opt-in). Configure a signing certificate chain and key
(DRAFT_C2PA_CERT / DRAFT_C2PA_KEY, with c2patool installed) and draft also
writes a signed, detached .c2pa credential bound to the article; draft --verify then validates its signature and trust chain as well as the digests.
Without a certificate the manifest stays an unsigned definition, exactly as
before.
A portable record. draft --verify --json prints a self-contained
draft.verification-record/v1 — the article digest and whether it matches, the
grounding summary, the signature state, and the overall verdict — that a script
or another tool can consume and re-check without the CLI.
See provenance & compliance for what the manifest contains, how it maps to AI-disclosure rules, and a real set you can download and verify.
House style
--style <file> points draft at a JSON house-style file: a word band, a banned
vocabulary, and a language variant. Style is enforced on the finished draft,
not merely requested — a draft that breaks a rule is corrected, not shipped.
Configuration and environment
Most flags have an environment-variable equivalent, useful for CI or a shared default:
DRAFT_ENGINE, DRAFT_EXTRACT_ENGINE, DRAFT_WRITE_ENGINE, DRAFT_EDIT_ENGINE,
DRAFT_MODEL_SESSION, DRAFT_MODEL, DRAFT_WRITE_MODEL, DRAFT_EXTRACT_MODEL,
DRAFT_EDIT_MODEL, DRAFT_NUM_CTX, DRAFT_NUM_PREDICT, DRAFT_STRICT_NUMBERS,
DRAFT_SECOND_GATE, DRAFT_READER, DRAFT_DRAFTS_DIR, DRAFT_SOURCES_DIR,
DRAFT_CACHE_DIR, DRAFT_NO_CACHE, DRAFT_C2PA_CERT, DRAFT_C2PA_KEY,
DRAFT_C2PA_ALG, OLLAMA_HOST
Set DRAFT_SHOW_LOGO=0 to suppress the nib mark in --help. Publisher identity
for the C2PA manifest is configured with the DRAFT_SITE_* variables.
Config files
For defaults you would otherwise repeat, draft reads a project draft.toml in
the working directory and a user ~/.config/draft/config.toml (honouring
XDG_CONFIG_HOME). They set the same settings as the flags — engine,
extract-engine, write-engine, edit-engine, reader, model, the Ollama
models, out, sources-dir, style, and the c2pa-cert / c2pa-key /
c2pa-alg signing keys.
Precedence is flags > environment > project file > user file >
built-in default, so adding a config file never changes what an existing
command already does. DRAFT_CONFIG names an explicit file; DRAFT_NO_CONFIG
disables the layer. The parser is a dependency-free flat key = value reader —
no new module.
# draft.toml
engine = "claude"
reader = "docling"
out = "~/Drafts"
Troubleshooting
No backend found. Run draft --doctor. Log into one supported agent CLI, or
install Ollama and start it for offline runs. You need exactly one.
A thin ledger. A source with few checkable claims yields a short draft by design. draft never pads; a short draft means the paper offered little the gate could verify.
Offline model not pulled. --engine ollama needs the model downloaded
beforehand and the Ollama server running. draft --doctor reports whether it is
reachable.
A run failed partway. The verified ledger is left on disk. Re-run with
--resume to skip straight to writing rather than re-paying for extraction.
Next steps
- How grounding works — the nine-check gate, in detail.
- Examples — a sentence, its source span, and the attribution that binds them.
- Provenance & compliance — a real set you can download and verify.
- Go packages — every capability as an importable Go package.
- Roadmap — what draft does not yet do.