Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when designing or writing the JSON request or response documents of a resource-style HTTP API: structure every document as a JSON:API v1.1 envelope — top-level data/errors/meta members, resource objects of type + id + attributes, relationships instead of foreign-key fields, included for related resources, media type application/vnd.api+json. Do NOT use for RFC 9457 problem-details error bodies, GraphQL responses, or for parsing a third-party payload you don't control.
.claude/skills/json-api-envelope/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 38 |
| gemini-3.1-pro-preview | 100% | 2 |
| Model | Lift | Δ tokens | Δ turns | Cases | Verified |
|---|---|---|---|---|---|
| gemini-3.6-flashbest | +23% | +144% | 0% | 22 | 54d ago |
| gemini-3.5-flash | pending re-run | — | |||
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | — | — |
| case-08 | ✗→✓ | ▲ Improved | — | — |
| case-11 | ✗→✓ | ▲ Improved | — | — |
| case-06 | ✗→✓ | ▲ Improved | — | — |
| case-12 | ✗→✓ | ▲ Improved | — | — |
Every JSON document the service sends or accepts is a JSON:API (jsonapi.org, v1.1) document: primary resources under a top-level data member, failures under a top-level errors array (never both in one document), extras under meta, resource objects of type + id + attributes + relationships, and the application/vnd.api+json media type. Apply when shaping request/response bodies for a resource-style HTTP service; not for RFC 9457 problem-details bodies (a separate convention) and not when consuming a format you don't control.
data, errors, meta — anddata and errors never coexist. Nothing else wraps them: no {"success": true} flag, no {"result": ...} or {"payload": ...} nesting, no collection-named top-level key.
data holds the primary resource(s). One resource object for a single-resourcedocument, an array of resource objects for a collection, null for an absent to-one target, [] for an empty collection. On a success document data is present, never silently omitted.
json { "type": "articles", "id": "1", "attributes": { }, "relationships": { } }
type — the collection name, a string.id — ALWAYS a JSON string, even when the underlying key is an integer.attributes — the record's own fields; type and id never appear inside it.relationships — one entry per connection to another resource.author_id-style attribute; it is a relationship whose data is a resource identifier:
json "relationships": { "author": { "data": { "type": "people", "id": "9" } } }
To-many linkage is an array of {type, id} identifiers; an empty to-one is "data": null; an empty to-many is "data": [].
the top-level included array, and the primary resources point at them through relationships by {type, id} — related records are never inlined inside attributes.
errors is a top-level ARRAY of error objects with members like status (theHTTP code as a string), title (a short type-level summary), detail (occurrence-specific), and source. Never a single error object, never a bare message string, never beside data.
meta. Non-standard extras — page counts, request ids, timings — go under top-levelmeta (or a resource-level meta), never as loose top-level fields like total or page.
Content-Type: application/vnd.api+json, and clientsask for them with the same value in Accept. Plain application/json is not the convention.
Collection with a reference — the ad-hoc default, then the conforming document:
jsonBEFORE { "articles": [ { "id": 1, "title": "Caching basics", "author_id": 9 } ], "total": 1 }
jsonAFTER { "data": [ { "type": "articles", "id": "1", "attributes": { "title": "Caching basics" }, "relationships": { "author": { "data": { "type": "people", "id": "9" } } } } ], "meta": { "total": 1 } }
Compound document — related record inlined vs. placed in included:
jsonBEFORE { "article": { "id": 1, "title": "Caching basics", "author": { "id": 9, "name": "R. Ortiz" } } }
jsonAFTER { "data": { "type": "articles", "id": "1", "attributes": { "title": "Caching basics" }, "relationships": { "author": { "data": { "type": "people", "id": "9" } } } }, "included": [ { "type": "people", "id": "9", "attributes": { "name": "R. Ortiz" } } ] }
Failure — ad-hoc flag vs. the errors array:
jsonBEFORE { "success": false, "error": "Article not found" }
jsonAFTER { "errors": [ { "status": "404", "title": "Not Found", "detail": "No article numbered 7 exists." } ] }
Creation request — flat fields vs. a typed resource object:
jsonBEFORE { "title": "Caching basics", "author_id": 9 }
jsonAFTER { "data": { "type": "articles", "attributes": { "title": "Caching basics" }, "relationships": { "author": { "data": { "type": "people", "id": "9" } } } } }
"data": [], not null, not an omitted member, not an error."data": null — not a..._id: null attribute and not a missing key.
id; the response documentsupplies the authoritative string id.
"7", not 7).meta with data is fine; meta with errors is fine; data with errors never.first, prev, next, last) under top-level links;counts under meta.
type or id → it cannot live in attributes (reserved);rename it (e.g. kind) or nest it.
data. Don't emit a collection-named top-level key.attributes. Don't flatten them onto the resourceobject.
relationships with {type, id} identifiers. Don't ship *_idattributes.
included. Don't inline them inside attributes.errors array. Don't return {"success": false} or mix errorswith data.
id as a string. Don't leak integer ids.application/vnd.api+json. Don't default to application/json.{"users": [...]} / {"items": [...]} — the collection-named wrapper instead of data.{"success": true, "data": ...} — a boolean status flag the envelope never uses.id values copied straight from the database.customer_id, owner_id) left inside attributes.attributes instead of included.errors array; errors returned besidedata.
total / page / request_id floating at the top level instead of under meta.Content-Type: application/json on a conforming document.data / errors / meta (plus links, included); never data witherrors.
type, string id, fields in attributes.relationships entry with {type, id} linkage — no *_id attributes.included, pointed at by {type, id}.errors array of status/title/detail objects.meta. Media type: application/vnd.api+json.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
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 +23 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.5-flash | verified | 7/10/2026 | +95% |
Other measured skills in the registry, with their headline benchmark lift.