Skip to main content
The SuperDoc SDK ships tool definitions that give LLMs structured access to document operations: reading, searching, editing, formatting, lists, tables, comments, and tracked changes. Pick a provider format, pass the tools to your model, dispatch the calls, and the SDK handles schema formatting, argument validation, and execution.

How the pieces fit

Your loop is the broker: the model only ever sees tools, a system prompt, and tool results; documents live in sessions inside the CLI host the SDK spawns; the browser editor renders the same file for the user. Three rules prevent most first-hour confusion:
  1. The SDK is server-sidedispatch needs a session-bound handle from createSuperDocClient().open(...); it does not run in the browser.
  2. The editor is browser-side — never import superdoc / @superdoc-dev/react in backend code or API routes.
  3. Pair everything from one preset — tools, system prompt, and dispatch must come from the same preset (the toolkit guarantees this).
The full mechanics — what crosses the SDK ↔ CLI boundary, sessions and revisions, a complete tool-call round trip with sequence diagrams, and where Python and MCP fit — have their own page: How it works.

Two presets

The SDK ships two tool surfaces. Pass the same preset to chooseTools, getSystemPrompt, and dispatchSuperDocTool.
Use the core preset for new integrations. Legacy remains the default only for backwards compatibility — existing integrations keep working unchanged. Core scores measurably higher on our revision-fidelity evals and returns verifiable receipts. Each preset has its own reference page: core · legacy.
Both presets are also served over MCP: the SuperDoc MCP server registers the legacy intent tools by default, or the core action surface with MCP_PRESET=core (two tools plus session lifecycle, with the core MCP instructions).

Quick start

Install the SDK, create a client, open a document, and wire up an agentic loop.

Tool selection

The one-call setup — tools, system prompt, and a pre-bound dispatcher that always agree on preset and exclusions:
The toolkit makes preset/exclusion mismatches impossible by construction — an excluded action is simultaneously out of the tool enum, out of the system prompt, and refused at dispatch. The standalone functions below remain available when you need the pieces individually; if you use them with excludeActions, pass the same list to all three. chooseTools() returns provider-formatted tool definitions plus metadata about the selection.

Legacy tool catalog

The legacy preset’s 10 grouped intent tools, their behaviors (superdoc_search require semantics, ref expiry, superdoc_mutations batching), and the migration mapping to core actions now live on the legacy preset page.

Dispatching tool calls

dispatchSuperDocTool() resolves a tool name to the correct SDK method, validates arguments, and executes the call against a bound document handle.
The dispatcher validates required parameters, rejects unknown arguments, and throws descriptive errors the LLM can act on. doc must be the session-bound handle from client.open(...) — a plain object or a browser editor instance will not work.

System prompt

getSystemPrompt(preset?) returns the prompt each tool surface was designed — and evaluated — with. It teaches the model the document vocabulary the tools use (blocks, ordinals, markers, visual sections), when to inspect before editing, how to read results, and the tracked-changes rules.
Guidance:
  • Use it as-is as your system message, or as the first section of one.
  • Extend, don’t replace: append your product’s instructions (tone, guardrails, domain language) after it. The prompt’s tool-usage sections encode behavior the schemas alone can’t teach; dropping it measurably degrades edit quality.
  • Pair prompt and tools from the same preset — the prompt documents exactly the surface the model was given.

Provider formats

Each provider gets tool definitions in its native format:
Agent loops are not provider-interchangeable. The tool definitions adapt automatically, but the message protocol does not: OpenAI uses message.tool_calls + role: "tool" replies; Anthropic uses tool_use content blocks + role: "user" messages containing tool_result blocks. Budget for a per-provider loop — the Anthropic variant is below.

Anthropic loop

Token budget

Tool schemas and the system prompt are re-sent on every turn, and every tool result lives in conversation history forever. Untended, a typical loop crosses low-tier per-minute token ceilings within a few turns. What the SDK gives you and what to do yourself:
  • Prompt caching (Anthropic) — pass cache: true to chooseTools({ provider: 'anthropic', cache: true, ... }): the SDK marks the tool array with cache_control: {type: 'ephemeral'} so the static prefix is cached across turns (~90% cost reduction on the cached portion). For the other half of the prefix, getSystemPromptForProvider({ provider: 'anthropic', cache: true }) returns the system prompt as cacheable system blocks — pass its content as the system parameter (the Anthropic loop shows both together).
  • Narrow the surfaceexcludeActions (core preset) removes actions from the schema and the prompt in one move.
  • Windowed reads — on large documents, inspect in block windows (blockOffset/blockLimit) instead of pulling the whole document into history; with legacy superdoc_get_content action:"text", be aware the full text lands in history on every use.
  • Receipts are pre-capped — core-preset receipts cap long per-item lists at 8 entries with count fields, specifically to keep history lean.
  • Plan for 429s — tier-1 accounts should implement exponential backoff and history truncation from day one.

Error codes

Runtime errors carry a stable code your loop (and your model) can branch on: Core-preset action failures additionally return structured recovery hints (reinspect / retry / revert with a paste-ready call) inside the receipt.

Troubleshooting: Host process disconnected

This one error has several distinct causes — check in order:
  1. macOS Gatekeeper killed the unsigned binary (SIGKILL at launch). Check xattr -d com.apple.quarantine <binary> / your MDM policy.
  2. Unsupported Node version — the SDK supports current LTS versions, but doesn’t declare engines, so npm won’t warn you at install time. Check node --version first.
  3. The host crashed mid-call — enable transport debug logs (DEBUG=superdoc.transport) to see the host’s stderr and exit code.
  4. Next.js bundling — mark the SDK as external (serverExternalPackages: ['@superdoc-dev/sdk']) so the native binary isn’t bundled away.

Streaming status to your UI

The agent loop is the natural place to emit progress events — each tool call is a meaningful step. Server-sent events sketch:
Core-preset receipts make the events meaningful for users: action names read like product verbs (“replace_text”, “add_comments”), and status/verified let you render success/warning states without parsing prose. For the final message, instruct the model (in your appended system-prompt section) to end with a short user-facing summary of what changed — receipts give it the evidence to be specific.

Creating custom tools

Custom capabilities are documented per preset:
  • Core preset: Custom actions add named actions with defineAction and createAgentToolkit.
  • Legacy presetCreating custom tools: define provider tools that call doc.* operations and merge them with the SDK’s.

SDK functions