schemafit
Lint your LLM structured-output & JSON schemas against OpenAI, Anthropic, Gemini, Mistral, and Cohere — and fail CI before they 400 in production.
Open source (MIT) · Static & offline · Zero runtime dependencies · CI-enforceable.
Watch schemafit in action
Recorded output from schemafit v0.5.0, edited as a replay of a synthetic schema. Static versioned rules; no live provider calls or acceptance claim. Locally synthesized Dan narration.
Read the transcript
This is schemafit, a local schema linter. This synthetic order schema fails the bundled OpenAI rule pack. The output points to two missing constraints before any model call. Repair writes a new file and flags a lossy change. Making a property required can change what your application accepts, so review the diff instead of applying it blindly. The repaired schema passes the same static pack. This is a check against versioned rules, not live provider verification. The source and quickstart are linked below.
The problem
A JSON Schema / tool definition / response_format that works on OpenAI can 400 on Anthropic or Gemini (and vice-versa): nested oneOf, a missing additionalProperties: false, a default in a property, Anthropic-rejected keywords (minLength, format, pattern), Gemini’s lack of anyOf. The API tells you it failed — not which constraint — so teams hand-port schemas and debug by trial-and-error at runtime.
schemafit encodes each provider’s documented constraint surface as a versioned, declarative rule pack and lints your schema statically — pointing at the exact JSON-Pointer path, the keyword, and why — with a non-zero exit code so CI fails the PR instead of prod. A repair pass emits a best-effort provider-valid variant. It makes no model calls, needs no API key, and has zero runtime dependencies.
Demo
lint statically checks your schema against each provider’s rule pack, names the exact violation, and exits non-zero so CI blocks the PR. repair emits a provider-valid variant. (Illustrative schema; the output format is the tool’s real one.)
# 1. Lint a schema against all three providersschemafit lint order.schema.json --provider openai,anthropic,geminiopenai PASSanthropic FAIL /properties/email keyword: format→ Anthropic rejects `format` in tool input schemasgemini FAIL /properties/items keyword: anyOf→ Gemini does not support anyOf / union typesSCHEMAFIT_STATUS=FAIL (exit 1 — build blocked)# 2. Auto-repair to a provider-valid variantschemafit repair order.schema.json --provider anthropic --out fixed.jsonwrote fixed.json (1 keyword rewritten, intent preserved)
Quickstart
On PyPI — pip install and lint your schema. No API key, no model calls; the core has zero runtime dependencies.
pip install schemafitschemafit lint my-schema.json \
--provider openai,anthropic,gemini,mistral,cohereschemafit demoCommand surface
- lint
- Lint one or more schemas against one or more providers; reports each violation’s JSON-Pointer, keyword, and reason, and exits non-zero so CI fails the build.
- repair
- Emit a best-effort provider-valid variant of a schema — stripping or rewriting the offending keywords while preserving intent.
- providers
- List the supported providers and the versioned rule pack backing each (OpenAI, Anthropic, Gemini, Mistral, Cohere).
- demo
- Run a hermetic, end-to-end proof from a fresh clone — no API key, no network, deterministic output.
Why it is different
Static, pre-ship CI lint
Instructor, BAML, LiteLLM and the Vercel AI SDK are excellent runtime clients — they normalize or repair at call-time. schemafit fills the gap they leave: a static lint that fails the build before the schema ever reaches a provider, over the raw schemas you already ship, with no DSL or codegen buy-in.
Zero runtime deps, no API key
It makes no model calls and needs no key — easy to vendor, audit, and trust in a build pipeline. Runs from a fresh clone or a single pip install, fully offline.
Grounded, versioned rule packs — with drift detection
Every rule is grounded in a real, cited provider issue. Provider constraints are encoded as declarative, versioned rule packs — so the lint stays honest and reviewable as provider APIs change. New in v0.5: automatic rule-pack drift detection — an opt-in --live-verify run that rejects a schema the static pack passed flags the pack as lagging the provider’s docs, so the packs stay honest as the APIs move.
CI-enforceable, with SARIF
A non-zero exit fails the PR; lint --format sarif feeds GitHub code-scanning / the Security tab. An opt-in --live-verify can confirm against a real provider, but it is mock-default and never required in CI.