Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Authors and validates JSON Schema (Draft 2020-12 and Draft-07) for configuration files and HTTP/REST APIs, applying types, constraints, composition keywords, and human-readable error messaging. Use this skill when the user wants to write, fix, refactor, or validate a JSON Schema, define a config-file contract, document request/response payloads, add validation rules to an OpenAPI spec, generate schemas from sample JSON, or produce clear validation error messages.
.claude/skills/jayrha-json-schema-author/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-12 | ✗→✓ | ▲ Improved | 111% | 0% |
| case-11 | ✓→✓ | = Same ✓ | 81% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 256% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 167% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 159% | 0% |
Keywords: JSON Schema, Draft 2020-12, Draft-07, $schema, $ref, $defs, validation, config schema, API schema, OpenAPI, additionalProperties, oneOf, anyOf, allOf, if/then/else, format, pattern, const, enum, error messages, ajv, jsonschema.
This skill helps you design correct, strict, and maintainable JSON Schemas for two dominant use cases: configuration files (validate user/operator input, fail fast with helpful messages) and APIs (contract for request/response bodies, often embedded in OpenAPI). It covers the type system, every important constraint keyword, schema composition, reuse via $ref/$defs, conditional validation, and turning raw validator output into actionable error messages.
Use the bundled material:
references/keywords.md — complete keyword reference (types, constraints, composition, applicators, annotations, draft differences) with copy-paste snippets.references/error-messages.md — patterns for clear, user-facing validation errors and how to map validator output to them.templates/config-schema.json — a strict, annotated starting point for a config-file schema.templates/api-schema.json — request/response schema pattern suitable for OpenAPI components.schemas.scripts/validate.py — stdlib-only structural linter that flags the most common schema authoring mistakes; falls back to jsonschema if installed for real validation.examples/config-walkthrough.md — sample config JSON turned into a finished schema with passing and failing instances.$schema: "https://json-schema.org/draft/2020-12/schema"). Use Draft-07 when targeting tooling that lags (older ajv configs, many OpenAPI 3.0 toolchains). OpenAPI 3.1 aligns with 2020-12. Note the differences: 2020-12 uses $defs and prefixItems/items; Draft-07 uses definitions and items (array)/additionalItems. See references/keywords.md."additionalProperties": false) or tolerated (forward-compatible APIs may allow them).type, then properties, then required. List every known property. Add a one-line description and a realistic examples/default where it aids users and generated docs.enum/const, numeric bounds (minimum, maximum, exclusiveMinimum, multipleOf), string rules (minLength, maxLength, pattern, format), and array/object cardinality (minItems, uniqueItems, minProperties). Prefer enum over free-form strings when the value set is closed.$defs and reference with $ref. Use allOf to combine/extend, oneOf for mutually-exclusive variants (tagged unions), anyOf for "at least one", and if/then/else for conditional requirements. Avoid oneOf when only one branch can plausibly match — prefer a discriminator pattern (see references/keywords.md).additionalProperties: false for configs and internal APIs. For arrays, decide additionalItems/items: false if a tuple. Mark deprecated fields with deprecated: true.title/description and, where supported, errorMessage (ajv-errors) or a post-processing map. Follow references/error-messages.md.scripts/validate.py to lint the schema structure, then validate at least one passing and several failing instances (one per constraint). Never ship a schema without a failing-case test.| Need | Keyword | Notes | |------|---------|-------| | Exactly one of several variants | oneOf | Validation fails if zero or 2+ match. Add a discriminating const per branch. | | At least one variant (overlap OK) | anyOf | Cheaper, clearer than oneOf when overlap is allowed. | | Combine constraints (extend a base) | allOf | All subschemas must pass. Beware additionalProperties interactions. | | Required field depends on another field's value | if/then/else | e.g. if type=="ssl" then cert is required. | | Field A requires field B present | dependentRequired | Simple co-presence rules. | | Closed value set | enum / const | const for single value; enum for a list. |
Critical gotcha: additionalProperties: false only sees properties declared in the same schema object, not those introduced by allOf/$ref siblings. To extend strictly, either declare all properties locally or use unevaluatedProperties: false (Draft 2019-09+/2020-12). See references/keywords.md.
A notification config where the payload depends on channel:
json{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["channel"], "properties": { "channel": { "enum": ["email", "sms"] } }, "oneOf": [ { "properties": { "channel": { "const": "email" }, "to": { "type": "string", "format": "email" } }, "required": ["to"] }, { "properties": { "channel": { "const": "sms" }, "to": { "type": "string", "pattern": "^\\+[1-9]\\d{6,14}$" } }, "required": ["to"] } ], "unevaluatedProperties": false }
Each branch pins channel with const, so exactly one branch can match — clean error attribution. See examples/config-walkthrough.md for a full multi-property example.
$schema. It tells validators and humans the dialect.additionalProperties: false for configs; require what's mandatory. Loosen deliberately, not accidentally.$defs and $ref them."type": "string" port number is a bug; use "type": "integer", "minimum": 1, "maximum": 65535.enum to pattern when the set is finite — it yields better errors and docs.title, description, examples, default, deprecated feed docs, IDE autocomplete, and form generators.format judiciously. Many validators treat format as annotation-only unless explicitly enabled (e.g. ajv formats, format: "full"). Back security-critical formats with a pattern.const inside oneOf branches so exactly one branch matches and errors point to the right place.additionalProperties: false + allOf/$ref silently rejects inherited properties. Use unevaluatedProperties: false instead when extending.definitions (Draft-07) and $defs (2020-12) inconsistently, or items: [..] tuple syntax under 2020-12 (use prefixItems).required does not imply existence checks for nested objects unless you also constrain the nested schema — list required at each level.oneOf with non-exclusive branches fails when input matches two branches. Add discriminators.type lets unexpected JSON types pass (a number where you meant a string).format assumed enforced. It's often advisory; verify your validator enforces it or add a pattern."type": "number" accepts 1.5; use "integer" for counts/ports/IDs.pattern. JSON requires \\ for a single backslash; \d must be written \\d.enum drift. When the value set grows, update the schema — stale enums reject valid new values.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-11 | pass→pass | 13,985 | 12,177 | -13% | 1 | 1 | 0% | 2,374 | 4,296 | +81% | 0 | 0 | — |
case-01 | pass→pass | 5,424 | 7,234 | +33% | 1 | 1 | 0% | 1,060 | 3,778 | +256% | 0 | 0 | — |
case-02 | pass→pass | 7,215 | 10,432 | +45% | 1 | 1 | 0% | 1,566 | 4,180 | +167% | 0 | 0 | — |
case-03 | pass→pass | 5,241 | 5,071 | -3% | 1 | 1 | 0% | 1,222 | 3,167 | +159% | 0 | 0 | — |
case-04 | pass→pass | 10,844 | 6,668 | -39% | 1 | 1 | 0% | 1,886 | 3,386 | +80% | 0 | 0 | — |
case-05 | pass→pass | 9,391 | 6,514 | -31% | 1 | 1 | 0% | 2,172 | 3,329 | +53% | 0 | 0 | — |
case-06 | pass→pass | 11,990 | 7,720 | -36% | 1 | 1 | 0% | 2,250 | 3,527 | +57% | 0 | 0 | — |
case-07 | pass→pass | 8,605 | 5,989 | -30% | 1 | 1 | 0% | 1,551 | 3,122 | +101% | 0 | 0 | — |
case-08 | pass→pass | 8,295 | 9,480 | +14% | 1 | 1 | 0% | 1,770 | 3,975 | +125% | 0 | 0 | — |
case-09 | pass→pass | 3,669 | 4,093 | +12% | 1 | 1 | 0% | 724 | 2,885 | +298% | 0 | 0 | — |
case-10 | pass→pass | 3,508 | 3,201 | -9% | 1 | 1 | 0% | 563 | 2,573 | +357% | 0 | 0 | — |
case-12 | fail→pass | 7,372 | 5,049 | -32% | 1 | 1 | 0% | 1,463 | 3,089 | +111% | 0 | 0 | — |
case-13 | pass→pass | 5,699 | 4,636 | -19% | 1 | 1 | 0% | 1,047 | 2,998 | +186% | 0 | 0 | — |
case-14 | pass→pass | 3,000 | 3,306 | +10% | 1 | 1 | 0% | 496 | 2,670 | +438% | 0 | 0 | — |
case-15 | pass→pass | 8,256 | 6,023 | -27% | 1 | 1 | 0% | 1,506 | 3,220 | +114% | 0 | 0 | — |
case-16 | pass→pass | 7,117 | 5,642 | -21% | 1 | 1 | 0% | 1,310 | 3,061 | +134% | 0 | 0 | — |
case-17 | pass→pass | 2,606 | 3,185 | +22% | 1 | 1 | 0% | 481 | 2,674 | +456% | 0 | 0 | — |
case-18 | pass→pass | 7,251 | 34,895 | +381% | 1 | 1 | 0% | 1,427 | 3,015 | +111% | 0 | 0 | — |
case-19 | pass→pass | 5,723 | 3,651 | -36% | 1 | 1 | 0% | 1,105 | 2,772 | +151% | 0 | 0 | — |
case-20 | pass→pass | 5,771 | 5,662 | -2% | 1 | 1 | 0% | 1,269 | 3,104 | +145% | 0 | 0 | — |
case-21 | pass→pass | 10,101 | 9,978 | -1% | 1 | 1 | 0% | 1,946 | 4,586 | +136% | 0 | 0 | — |
case-22 | pass→pass | 7,424 | 8,300 | +12% | 1 | 1 | 0% | 1,562 | 3,702 | +137% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/3/2026 | +8% |
Other measured skills in the registry, with their headline benchmark lift.