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.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
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 : the extraction, the matches, the paths. Reading the store is
a convenience, never a requirement — and publishes
each verb's shape, so you never have to discover it by running.
whole result is on
stdout
ade help --json
--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):
(--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.
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:
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.