| name | ade |
| description | Parse documents and extract schema-shaped data with the ADE (Agentic Document Extraction) v2 APIs through the ade CLI. A local job-item store makes every run idempotent, resumable, and citable — repeat runs are free, interrupted runs resume, and every answer can cite element ids with visual evidence. |
ade — agent skill
ade drives the ADE (Agentic Document Extraction) v2 document APIs
(parse, extract) and persists
everything it produces in a local store under ~/.ade. You are the
judgment; the CLI is deterministic plumbing: it parses, persists,
searches, renders, and totals — it never ranks or selects for you.
First move
ade help --json
One call returns the whole shipped surface: every command and flag, each
verb's --json result shape, the exit states, and the store layout.
Prefer it over N --help round trips. ade help workflow (also
output, credentials, errors) is the conceptual page behind it.
Check credentials with ade auth status --json; if logged out, set
ADE_API_KEY, or pipe a key in (echo $KEY | ade auth login) — no
terminal required either way. An API key acts in the organization it
was created in; browser (OAuth) sessions carry their own selection —
status reports it, ade auth org list --json shows the memberships,
and ade auth org switch <org> --env <env> changes it. If a run must
bill to a specific organization, confirm the selection before
parsing: re-running the same invocation after a switch joins the
recorded run instead of re-billing under the new organization.
Conventions
- Always pass
--json. Every command emits one stable JSON
object/array on stdout — errors and pending payloads included. Human
text is for terminals, not for parsing. The whole result is on
stdout: the extraction, the matches, the paths. Reading the store is
a convenience, never a requirement — and ade help --json publishes
each verb's shape, so you never have to discover it by running.
--id-only when you only need the id. parse, extract, and
find take it: the id(s), one per line, nothing else —
JOB=$(ade parse -d report.pdf --id-only). Errors go to stderr, so a
captured id is never a sentence.
- Job item ids are the currency. Every parse or extract run is a
job item: one folder under
~/.ade/jobs/<job-item-id>/, keyed by the
invocation (verb × environment × source × content × params; URL
sources are keyed by the URL alone — no content component, so remote
drift does not re-key). Commands accept an
unambiguous id prefix. Changing the file, its path, or any param mints
a sibling item — nothing is silently replaced.
- Commands are guarantees.
parse means "ensure this exact run
exists", not "fire a request". Re-running an already-done invocation is
free — served from disk with an already parsed notice and
"cached": true. Only --force re-bills.
The loop
-
Parse (free if already done):
ade parse -d report.pdf --json
The payload carries job_item_id — hold onto it. Everything else
keys off it. The markdown and the elements projection stay on disk
unless you ask for them: --include markdown, --include elements.
-
Discover element ids (local, instant, no API call):
ade find JOB_ITEM_ID "total revenue" --json
ade find JOB_ITEM_ID --type table_cell --page 3 --json
(--job JOB_ITEM_ID is the equivalent flag spelling — repeat it to search
several items in one call.)
Matches are citation records: {job_item_id, element_id, type, page, box, text}. Filters compose (AND); results come in document order,
never ranked — selection is your job.
-
Extract structured data against a JSON Schema:
ade extract JOB_ITEM_ID --schema schema.json --json
The result is its own job item. The payload's extraction key is the
schema-shaped result itself — read it there, not off disk. Per-field
evidence (evidence, persisted as evidence.json) joins extraction
spans to element ids, pages, and boxes — non-empty fields the model
synthesised rather than quoted are flagged ungroundable;
empty-valued fields (blank cells, absent optionals — nothing to
ground) are labeled empty. Neither is ever silently dropped.
-
Cite and show. ade view JOB_ITEM_ID --json builds a
self-contained HTML viewer; deep links are the citation contract:
ade view JOB_ITEM_ID --element-id ELEMENT_ID --json # emits view.html#element=ELEMENT_ID
ade crop JOB_ITEM_ID --element-id ELEMENT_ID --json # PNG of that element's region
ade crop JOB_ITEM_ID --type figure --json # every figure, one command
End answers with one deep link per job item, citing element ids.
Use crop when you need to look at evidence mid-reasoning — it
takes find's own filters (--type, --page, --all), so a
selection crops in one call and returns crops[]; never loop find
into crop yourself.
Reuse posture — parse bills once
Every parse the CLI ever runs is a reusable job item. Given a document
path, extract -d FILE --schema … reuses the latest completed parse of
that path+content (logged in the summary; no parse billed). If none
exists, it runs a standalone parse first — a normal, top-level
parse item, exactly as if you had run parse -d — then the extraction
referencing it: two billable runs, both itemised. Repeat extract -d
runs of the same file then reuse that parse, so it bills exactly once.
Prefer the explicit two-step (parse -d, then extract JOB_ITEM_ID) when
you want the same parse to feed several schemas — the id makes the reuse
visible.
Pending and resume
Wait expiry is a normal outcome, not an error. If the poll budget
(--wait, default 600s) runs out, the command exits with code 3 and a
{"status": "pending", "run_id": …, "job_item_id": …} payload while the
run continues server-side (submitted work always completes and bills —
there is no cancel). The recovery gesture is always the same command,
re-run. A re-run joins the recorded run; it never resubmits and never
re-bills. Interrupts (Ctrl-C) stop the waiting, not the work — same
gesture. --wait 0 submits and returns immediately.
Submit-and-return, then collect later — the pending payload carries the
id too, so this works in both steps:
JOB=$(ade parse -d report.pdf --wait 0 --id-only) # exit 3, run continuing
ade parse -d report.pdf --json # re-run: resumes, never re-bills
Exit codes
| Code | State | Meaning |
|---|
| 0 | ok | Success — the payload is on stdout. |
| 1 | failed | The run failed or the target cannot serve the request. |
| 2 | usage | The invocation itself was wrong; nothing was submitted. |
| 3 | pending | Wait budget expired; the run continues server-side. Re-run the same command to resume. |
| 4 | rate_limited | Submit was rate-limited and the wait budget ran out before a run existed; nothing billed. Re-run to retry. |
Reading the store directly
Optional, never required: every result is already on stdout. Artifacts
are plain files — history list --json gives every item's records, and
the summaries print each item's store path.
parse.json — raw ParseResponse (ground truth, verbatim)
parse.md — the parse markdown extraction spans index
elements.json — flat element records with inline grounding; boxes
are normalized {xmin, ymin, xmax, ymax} fractions of page size in
[0, 1]
extract.json — raw extraction result with per-field spans
evidence.json — the field→box join (element ids, pages, boxes)
One vocabulary note when reading these files: on-disk records
(meta.json, job.json, parse/ref.json) spell the server-side run id
as job_id — the wire contract's name for the same value --json
payloads report as run_id. Neither is ever the job item id.
Prefer find over loading elements.json into context: it returns
joined records, not lines. history clear JOB_ITEM_ID deletes an item;
clearing a parse item cascades to the extractions referencing it.
Sharp edges
--options is a verbatim ParseOptions pass-through — the server
rejects unknown keys with a 422, so consult ade help parse for
the accepted keys rather than guessing.
- Parse variants coexist. The same document parsed with different
params is a sibling item, not a replacement. An extraction goes stale
only when its exact parse item is re-run in place with
--force.
- Moving or editing a file changes identity — the next parse of it
is a new job item that bills. The old item and its evidence stay
intact and true of the run they came from.
--markdown extractions have no page evidence (there is no parse
to join against) — evidence degrades to spans-only, and view
renders the markdown pane alone.
- URL parses have no local bytes, so page imagery renders from an
attached copy:
parse --document-url … --keep-copy fetches it at
parse time (reliable — pre-signed URLs expire); otherwise the first
view/crop downloads it automatically (--no-download skips;
the payload records downloaded, and on a failed fetch view
degrades to an empty preview with download_error while crop
errors). Markdown, elements, and extractions work either way.