Execute Code
execute_codeExecute JavaScript to query, search, read, extract, and cite PDF documents, returning JSON or HTML views.
Instructions
Execute JavaScript against Code Mode namespaces — the primary tool for exploring, querying, grepping, reading, and citing documents (results come back here). For a finished chart, table, metric, or HTML display, pass the working query to render_ui instead.
Code Mode API: docs.list() → [{id, file_name, status, total_pages}] docs.status({ docId }) → {phase, totalPages, totalNodes, ...} docs.read({ docId, pages? }) → {markdown, page_count, total_pages, truncated?} docs.ask({ docId, question }) → {answer, citations, trace_id} (LLM — slow, use sparingly) docs.extract({ docId, prompt, jsonSchema }) → {data, trace_id} (LLM — slow, use sparingly) sql.query({ docId, sql }) → {rows, count} — read-only SQL on one doc; rows include document_id sql.queryMany({ docIds, sql }) → {results:[{docId, rows, count}], count} — run the same query across docs sql.search({ query, docId?, docIds? }) → FTS5 keyword/phrase search across one doc or the current collection sql.grep({ query, docId?, docIds?, pages? }) → literal substring search across node values; useful when FTS tokenization is too strict citation.create({ claim, nodes, docId?, minQuality? }) → {id, url, verification} — mint a shareable link.okrapdf.com/c/{id} proof card; minQuality defaults to "high". citation.batch({ items }) → {citations:[{id,url,...}], count} — mint many proof links from multi-doc results.
SQLite tables per doc: nodes (id, parent_id, type, label, value, status, page_number, confidence, metadata, sort_order) nodes_fts — FTS5 on label+value (use MATCH) meta (key, value) page_ledger (page_number, status, pass, vendor, attempt, confidence, error)
Node data model — the nodes table is the extracted document tree:
Each row is one element.
typeis the raw parser type and varies by vendor, so always run SELECT DISTINCT type FROM nodes first (common values: text, table, row, cell, figure, heading).Tables come in TWO shapes depending on the parser; check with SELECT DISTINCT type: (a) a single
tablenode with the whole table serialized in itsvalue(e.g. the gemini-vision default), or (b) a nestedtable→row→celltree: row.parent_id = table.id, cell.parent_id = row.id, and eachcell.valueholds one cell's text (table/row values are usually empty). For shape (b) read a grid by joining BOTH levels and ordering by sort_order; row/column headers are the first/edge cells positionally, NOT stored onlabel(which is usually NULL).valueis always raw text exactly as printed ("88,268", "16 %", "Sept 30, 2025") — never a typed number/date. Cast in SQL for arithmetic, e.g. CAST(REPLACE(REPLACE(value,',',''),'$','') AS REAL).
Prefer SQL/FTS for discovery, filtering, keyword search, counting, and reading content. SQL is fast, free, and deterministic. Only fall back to reading full pages when SQL doesn't have what you need. When answering numerical or factual questions, use sql.query() to find exact values, then compute the answer step by step. If the first query doesn't return what you need, try a different query — iterate rather than guessing from partial data. IMPORTANT: nodes_fts rows contain full page text (5KB+ each). Always use substr() and JOIN nodes for page_number: SELECT n.page_number, substr(n.value, 1, 200) as excerpt FROM nodes_fts f JOIN nodes n ON n.id = f.node_id WHERE nodes_fts MATCH 'keyword' LIMIT 10 High-grade citation workflow:
Never cite from memory or from a generated answer alone. First use SQL/FTS/search to find exact candidate nodes.
For MCP users, prefer verify_source when you have a claim plus rough locator/pages/quote; pass pdf_url + page/pages for eager one-page public-PDF verification without full ingest, or document_id for parsed-node verification. It renders found/not-found/multiple-candidate states as an inline card.
verification_requirement controls what counts as verified. The default is verification_requirement="bbox": require coordinate evidence and only mint a proof link when a bbox is available. Pass verification_requirement="text_match" only when deterministic page-text/text-layer matching is sufficient; it returns a found state without a durable proof link, page-image proof, or bbox-backed confidence claim.
If you already have exact rows, pass rows that include id, document_id, page_number, value, bbox_x/y/w/h, confidence, and status to verify_source mode="exact_node" or citation.create.
For user-facing, audit, legal, or financial claims, visually verify the page/bbox with view_document or review_extraction before presenting the citation as final when the card says multiple_candidates, not_found, or low confidence.
Treat the returned verification_grade, verification_score, and verification_warnings as the citation quality gate; if warnings mention missing bbox, low confidence, or unverified status, disclose that or find better evidence. Only use ask/extract when the answer requires LLM reasoning, not data lookup.
Page images: https://api.okrapdf.com/v1/documents/{docId}/pg_{N}.png
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Async JavaScript body to execute against your document library. Runs in a V8 isolate. No network, no npm — but ESM imports work at render time (esm.sh). Code Mode namespaces: library.list() → [{id, file_name, status, total_pages}] — your whole document library (docs.list = deprecated alias) library.search({ name?, status?, minPages?, maxPages?, limit?, offset? }) → {documents,count} — filter the whole LIBRARY by name/metadata (vs sql.search, which searches text INSIDE a doc) docs.status({ docId }) → {phase, totalPages, totalNodes, ...} docs.read({ docId, pages? }) → {markdown, page_count, total_pages, truncated?} docs.ask({ docId, question }) → slower LLM answer over one doc docs.extract({ docId, prompt, jsonSchema }) → structured LLM extraction sql.query({ docId, sql }) → {rows, count}; stamps rows with document_id sql.queryMany({ docIds, sql }) → {results:[{docId, rows, count}], count} sql.search({ query, docId?, docIds? }) → FTS5 keyword/phrase search sql.grep({ query, docId?, docIds?, pages? }) → literal substring search citation.create({ claim, nodes, docId? }) → {id, url, verification} citation.batch({ items }) → {citations:[{id,url,...}], count} Action verbs (orchestrate: parse · tools · publish — on docs you OWN): docs.engines() → {engines:[{id,tier,category}], count} — the parse-engine menu (free) docs.parse({ docId, vendor }) → re-parse with an explicit engine id (pin/switch); waits, returns {phase, totalNodes, completed} docs.publish({ docId }) → publish a finished doc to a public read URL → {publicDocId, url} tools.extract({ docId, prompt, jsonSchema }) → okrapdf /extract (structured data) tools.to_json({ docId, schema }) → okrapdf /pdf-to-json (document → JSON in your schema) // Compare engines: call docs.parse per vendor (a dynamic workflow can parallel() them) — each call re-parses the same doc. SQLite tables per doc: nodes (id, parent_id, type, label, value, status, page_number, confidence, metadata, sort_order) nodes_fts — FTS5 on label+value (use MATCH) meta (key, value) | page_ledger (page_number, status, pass, vendor, attempt, confidence, error) Return values: return object/array → rendered as JSON viewer on embed return "<div>..." → auto-wrapped in HTML shell (dark theme, system-ui) return "<!DOCTYPE…" → served as full HTML document (you control everything) return { html, scripts } → html body + scripts block, auto-wrapped in shell Rendering HTML views: Return an HTML string. Fragments like "<h1>Hello</h1>" are auto-wrapped in a shell. For full control, return a complete document starting with "<!DOCTYPE html>". For interactive views, use ESM imports — the CSP allows esm.sh, jsdelivr, cdnjs: return `<div id="app"></div> <script type="module"> import { Chart } from 'https://esm.sh/chart.js@4'; // Chart.js, React, D3, Plotly, Three.js — any ESM package works </script>`; Page images available at: https://res.okrapdf.com/v1/documents/{docId}/pg_{N}.png Common SQL: Page content: SELECT value FROM nodes WHERE page_number = 5 ORDER BY sort_order FTS search: SELECT n.page_number, substr(n.value, 1, 200) as excerpt FROM nodes_fts f JOIN nodes n ON n.id = f.node_id WHERE nodes_fts MATCH 'revenue' LIMIT 10 Cross-doc: sql.queryMany({ docIds, sql }) IMPORTANT: nodes_fts rows are full page text (5KB+). Always use substr() to avoid huge results. | |
| public_doc_ids | No | Optional public doc IDs to mount alongside the authenticated user’s private docs for mixed private/public multi-document analysis. |