Claiv Parser · open source

Turn any model output into JSON you can trust.

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
Zero dependenciesMIT licensedNo AI required
model-output.mdinput
## Positioning
Acme is the fastest scheduling
tool for small teams.

## Pricing
| Tier | Price  | Seats |
|------|--------|-------|
| Pro  | £29/mo | 10    |

Sources: https://acme.com/pricing
parse · tier 3 · 0 model calls
result.jsonoutput
{
  "positioning": "Acme is the fastest…",
  "pricing": [
    { "tier": "Pro", "price": 29 }
  ],
  "sources": ["https://acme.com/…"]
}
// price: "£29/mo" → 29  (coerced)

Six tiers. It stops at the first one that works.

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.

0direct

JSON.parse and validate against your schema. If the model behaved, you pay nothing for the rest.

~0ms
1repair

Code fences, chatty preambles, single quotes, unquoted keys, Python literals, comments, smart quotes, trailing commas and truncated output.

~1ms
2coerce

Schema-guided conversion: "£29/mo" becomes 29, "yes" becomes true, keys match across camelCase, snake_case and Title Case, enums snap, envelopes unwrap.

~1ms
3markdown

Headings become keys, tables become arrays of objects, bullets become string arrays, Key: value lines are read, and URLs collect into sources.

~2ms
4merge

Combines partial JSON with partial markdown when neither is complete on its own.

~1ms
5model

Only runs if you configure an adapter. There is no default and no required dependency, so the library works fully offline.

your call

Tiers 0 to 4 are pure functions. The same input and schema produce byte-identical output every time, cacheable, testable, auditable and entirely offline.

It never invents a value.

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"]

Every field says how it got there.

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.

exactrepairedcoercedmarkdowndefaultmodelmissing

Search model output is already structured.

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.

Measured, and honestly caveated.

Run it yourself with npm run bench against the bundled corpus of 19 real-world failure modes.

18/18
Solvable cases resolved
1
Honest failure, unstructured prose, correctly not fabricated
0
Model calls made
10ms
Total time for the whole corpus

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.

Two functions to learn.

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

And the helpers, if you want them.

The internals are exported too, so you can reach for a single piece rather than the whole pipeline.

validateisValidrepairJsonrepairAndParseextractCandidateparseTableparseListparseKeyValuesextractUrlsmatchKey

Schema 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.

Free and open source

Stop regenerating calls because the formatting was wrong.

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