Every system that asks an LLM for JSON eventually grows a half-finished parser. Claiv Parser separates generation from formatting: let the model work in its own idiom, then convert afterwards, deterministically, with no second model call.
npm install @claiv/parserRead the docs ## Positioning Acme is the fastest scheduling tool for small teams. ## Pricing | Tier | Price | Seats | |------|--------|-------| | Pro | £29/mo | 10 | Sources: https://acme.com/pricing
{
"positioning": "Acme is the fastest…",
"pricing": [
{ "tier": "Pro", "price": 29 }
],
"sources": ["https://acme.com/…"]
}
// price: "£29/mo" → 29 (coerced)Tiers run cheapest-first and halt at the first schema-valid result, so cost and latency stay proportional to how broken the input actually was.
JSON.parse and validate against your schema. If the model behaved, you pay nothing for the rest.
~0msCode fences, chatty preambles, single quotes, unquoted keys, Python literals, comments, smart quotes, trailing commas and truncated output.
~1msSchema-guided conversion: "£29/mo" becomes 29, "yes" becomes true, keys match across camelCase, snake_case and Title Case, enums snap, envelopes unwrap.
~1msHeadings become keys, tables become arrays of objects, bullets become string arrays, Key: value lines are read, and URLs collect into sources.
~2msCombines partial JSON with partial markdown when neither is complete on its own.
~1msOnly runs if you configure an adapter. There is no default and no required dependency, so the library works fully offline.
your callTiers 0 to 4 are pure functions. The same input and schema produce byte-identical output every time, cacheable, testable, auditable and entirely offline.
Anything not present in the source is returned as null and named in unresolved. A parser that quietly fabricates a plausible value is worse than one that fails, because the output looks correct.
r.ok → false r.data → { pricing: null } r.unresolved → ["pricing"]
Each value reports the tier that resolved it, so you decide what to trust. Accept coerced silently, flag model, reject missing, your policy, not ours.
Perplexity and friends rarely emit JSON, but they rarely emit unstructured text either. Headings are keys, tables are records, footnotes are citations, structured data wearing a costume.
That is recoverable without a model, which matters when regenerating a research call costs real money and seconds of latency because the formatting was wrong rather than the answer. Native structured output does not cover search-augmented models, most open models, or documents.
Run it yourself with npm run bench against the bundled corpus of 19 real-world failure modes.
Worth stating plainly: this corpus was written alongside the library, so it demonstrates coverage of known failure modes rather than proving performance on unseen data. Real messy outputs that break it are the most useful thing you can send us.
One synchronous call covering the deterministic tiers, and one async call that adds your optional model adapter.
parseDeterministic(input, schema, opts?) → ParseResult // sync, tiers 0 to 4 parse(input, schema, opts?) → Promise<ParseResult> // + optional tier 5
The internals are exported too, so you can reach for a single piece rather than the whole pipeline.
validateisValidrepairJsonrepairAndParseextractCandidateparseTableparseListparseKeyValuesextractUrlsmatchKeySchema support is a deliberately small JSON Schema subset: type, properties, required, items, enum, default and additionalProperties. PDF, OCR and HTML extraction are out of scope, bring your own text.
Install it and point it at your worst model output. If you would rather have the whole pipeline designed, built and supported for you, that is what we do for clients.
npm install @claiv/parserHave us build it