New Standard, Who Dis?

I made a bet early on: if I wanted OpenPKG adopted, build on existing standards. JSON Schema (2020-12) for type representation, not something custom.

That bet paid off faster than I expected.

The trigger was working with Zod and the other schema libraries. Static analysis could extract the basic types (string, number, object) but missed everything that made those schemas useful. An email field? Just string. An age with min/max bounds? Just number. The constraints only exist at runtime.

So I started building plugins. Manual adapters for Zod, Valibot, ArkType, TypeBox, extracting constraints and merging them into the spec. It worked, I hated it. Every library update could break something and I'd be the one maintaining all of it.

Then Standard JSON Schema shipped.

the problem

Take a typical Zod schema:

import { z } from 'zod';
export const UserSchema = z.object({
email: z.string().email(),
age: z.number().min(18).max(120),
username: z.string().min(3).max(20),
});

Static analysis gets you the basic shape:

{
"schema": {
"properties": {
"email": { "type": "string" },
"age": { "type": "number" },
"username": { "type": "string" }
},
"required": ["email", "age", "username"]
}
}

The shape is right. But the constraints, the email format, the min/max values, the length limits. Static analysis can't see any of it.

Runtime introspection calls the schema directly and gets the actual constraints:

{
"schema": {
"properties": {
"email": { "type": "string", "format": "email" },
"age": { "type": "number", "minimum": 18, "maximum": 120 },
"username": { "type": "string", "minLength": 3, "maxLength": 20 }
},
"required": ["email", "age", "username"],
"additionalProperties": false
}
}

Email format. Numeric ranges. Length constraints. additionalProperties: false. Everything a developer (or an LLM) needs to actually use the code.

The spec

Standard JSON Schema gives validation libraries a common interface for runtime introspection. Any compatible library can expose its constraints as JSON Schema:

const jsonSchema = schema['~standard'].jsonSchema.output({
target: 'draft-2020-12'
});

One interface. Every library. No adapters. All those plugins I was dreading maintaining, gone before I shipped them.

Using it looks like this: detect a Standard JSON Schema-compatible library, run with --runtime, get the full picture.

Terminal
# Static only (fast, no execution)
npx @openpkg-ts/cli snapshot src/index.ts
# With runtime introspection
npx @openpkg-ts/cli snapshot src/index.ts --runtime

openpkg detects available TypeScript runtimes (bun, tsx, Node 22+), executes the entry file, finds Standard JSON Schema-compatible exports, and merges the runtime schemas with the static analysis.

Standard JSON Schema shipped late 2025. openpkg had already picked JSON Schema as its output format so the integration was mostly just... already done. I'd love to say I saw it coming. Really I just picked the boring option and got lucky.