@okrapdf/cli
v0.17.0
Published
okraPDF CLI — upload PDFs, stream a local PDF-to-HTML twin, pull grounded context with bbox citations, run parse jobs, and query collections.
Maintainers
Readme
@okrapdf/cli
The okraPDF command line: stream a local PDF-to-HTML twin, upload PDFs, pull grounded context with bbox citations, run parse jobs, extract structured data, and query collections — built for agents first (JSON envelopes with next_actions whenever stdout is not a TTY).
npm install -g @okrapdf/cli
okra auth loginSelf-hosted server + browser workbench
Running okraPDF on a server? The one-command stack (Docker image with poppler +
tesseract, Postgres, API key, healthchecks) and the operator guide live in
apps/api/node:
cp .env.example .env && docker compose up -d. The commands below run the same
runtime directly on your machine.
Start the account-free local server and open its attached browser client:
npx @okrapdf/cli@latest webThe workbench follows the desktop app's document-first flow: open and read a
PDF without parsing, then press Parse when you want local text/OCR extraction.
Documents, runs, Markdown, blocks, and manifests persist under
~/.okra/serve. The browser talks to the same okra.client.v1 HTTP+SSE API
that desktop and other clients can attach to.
Use serve for the headless/server-first form. It still serves the web client
at /, but does not open a browser:
npx @okrapdf/cli@latest serveBoth commands bind to 127.0.0.1:8787 by default. To share on a trusted LAN
or behind your HTTPS reverse proxy, bind explicitly and set a password:
OKRA_SERVER_PASSWORD=secret npx @okrapdf/cli@latest web --host 0.0.0.0The browser uses HTTP Basic auth (okra is the default username; override it
with OKRA_SERVER_USERNAME). OKRA_API_KEY remains available for Bearer or
x-okra-api-key automation on document and run routes (reads and writes). An
API key alone is not enough to share the browser workbench on a LAN bind; set
OKRA_SERVER_PASSWORD for that. This command does not create a public tunnel;
set OKRA_PUBLIC_URL when an external proxy already supplies one.
To serve the full React workbench from apps/web instead of the built-in
page, build its node target and pass --public-dir apps/web/dist-node
(same origin, same auth; see apps/api/node/README.md).
The installed npm CLI is another client of this server, just like the desktop
UI. Point it at any okra.client.v1 host explicitly or with
OKRA_CLIENT_URL:
okra parse ./report.pdf --server http://127.0.0.1:8787 --wait
okra runs --server http://127.0.0.1:8787
okra run <run-id> --server http://127.0.0.1:8787 --artifacts
okra pii analyze <run-id> --server http://127.0.0.1:8787For a protected self-host, OKRA_API_KEY is sent as the Bearer credential. On
macOS, omitting --server and OKRA_CLIENT_URL makes these processing commands
discover Okra.app through its authenticated LaunchServices callback. Local PDF
bytes go to an explicitly selected self-host; the desktop path passes the
original file path to the sandboxed app and does not duplicate the PDF.
pii analyze follows Presidio's Analyzer category and runs only over a completed
positioned parse. The desktop host identifies its analyzer as presidio; the
reference self-host identifies its smaller offline analyzer as basic-policy.
Analysis only creates candidates. Applying and exporting redactions remain
separate, human-approved actions.
Local PDF-to-HTML viewer
Run the same progressive HTML stream as live.okrapdf.com on your machine — no okraPDF account, no okraPDF API traffic, no telemetry. The viewer and server bind to loopback; PDF page batches are sent directly to Unstructured using the key in your environment.
export UNSTRUCTURED_API_KEY='...'
okra view ./paper.pdf --web
# Or without a global install:
UNSTRUCTURED_API_KEY=your_key npx @okrapdf/cli@latest view ./paper.pdf --webThe command emits the released okra.live_html.v1 contract, keeps completed pages visible if a later page fails, and can download the finished self-contained HTML. It uses one page per request and four concurrent requests by default; see okra view --help for batching, concurrency, timeout, page-limit, and self-hosted endpoint options. Provider keys are never accepted as CLI flags.
The earlier Gemini BYOK engine and the --recipe parsebench trajectory harness still ship inside the tarball as dist/okra-view.mjs for direct invocation (node "$(npm root -g)/@okrapdf/cli/dist/okra-view.mjs" --pdf ./report.pdf --web), but the okra view command is the Unstructured path above.
Want the hosted upload flow instead? Open okrapdf.com/tools/pdf-to-html.
Primary workflows
okra upload ./report.pdf # add --no-wait to queue; resume with okra jobs wait
okra documents read doc-abc123 --pages 1-3
okra chat "Summarize this document" --doc doc-abc123
okra parse ./report.pdf --wait # macOS: attach to Okra.appGrounded context (agent loop)
okra context structure doc-abc123
okra context get "termination clause" --source-id doc-abc123
okra context ask "What is the guaranteed fee?" --source-id doc-abc123
okra parse doc-abc123 --model gemini-3-flash --prompt layout-bbox-gemini-multipage@1
okra jobs wait doc-abc123Context responses are token-bounded and cited: every citation is Anthropic page_location-shaped — cited_text, start_page_number, a deterministic page-image citation_url, the matched node's bbox (bbox_source: "node"), and match (exact/fuzzy). The identical shape comes back from extract --cite, context get, and context ask, so an agent parses citations the same way everywhere. structure/resolve report pages_parsed / page_coverage so a partial parse is never silent.
Structured extraction (grounded)
okra extract ./report.pdf --schema ./schema.json --cite # typed object + every field cited to page+bbox
okra content-types list # built-in typed contracts (e.g. invoice)
okra extract ./invoice.pdf --content-type invoice # schema + grounding from a content type — no --schema/--cite needed
okra collections extract ap-inbox --content-type invoice --cite # same, across a whole corpus--cite is the differentiator: each extracted field comes back with a page_location citation (page + bbox + proof URL), and a field that can't be grounded is dropped rather than guessed.
More
okra render ./report.py --out report.pdf
okra collections query earnings "What changed quarter over quarter?" -o earnings.csv
okra resources list # discover every API noun and verb
okra doctor # diagnose auth, API reachability, Node, and self-host envRun okra --help for the full surface, including the self-host runtime (okra self-host --help).
Automation contracts
Headless or --json failures are machine-readable:
{
"ok": false,
"command": "documents list",
"error": "no_api_key",
"message": "No API key found. Set OKRA_API_KEY=okra_… or run `okra auth login`.",
"hint": "Run `okra auth login` or set OKRA_API_KEY.",
"retryable": false,
"code": 401,
"exit_code": 1,
"next_actions": [{ "cmd": "okra auth login", "why": "Authenticate interactively." }]
}Exit codes are stable: 0 success, 1 client/auth/usage error, 2 server or network error.
Shell completions
okra completions zsh > ~/.zfunc/_okra
okra completions bash > ~/.okra-completions.bashSource the generated file from your shell profile, or place the zsh file on your fpath.
Library
Importing okraPDF from code? Use @okrapdf/sdk. This package owns the okra executable and its bundled local viewer; cloud/API commands delegate to the SDK command tree. The legacy unscoped okrapdf package is deprecated.
Agent skill
Teach a coding agent the cited-context loop:
npx skills add okrapdf/okra-agent