Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Model Output JSON Guard

ai.output_json_guard

ProductionBounded custom (Class B)Deterministicstrictinstantv1.0.0
No network

Overview

You asked a model for JSON and got back a fenced code block wrapped in an apology, or an object with a sentence after it, or something that is nearly JSON but has a trailing comma in it. Send us the raw reply and we find the JSON, parse it strictly, and hand back the parsed value along with where in your text it came from and which extraction rung found it. Parsing is RFC 8259 and nothing looser: no comments, no trailing commas, no single quotes, no unquoted keys, no NaN or Infinity. When something fails we name the exact construct and where it sits, so you know whether to retry the model or send the text to schema.repair_json. A reply with no JSON in it is not an error here — it comes back as valid false, because that is the answer you asked for. We check that it is JSON; we do not check it against a schema, and schema.validate_json is the one skill on the platform that does.

Every team that asks a model for JSON writes the same fragile snippet: strip the fences, find the first brace, hope. It works until a value contains a closing brace, or the model sends two blocks, or the reply is cut off mid-object — and then it fails quietly with the wrong half of a payload. Doing it once, string-aware, with the rung reported and every malformation named, turns that snippet into something you can reason about.

Reliability

Fully deterministic: the same reply and settings always give the same verdict, with no clock, randomness or network involved, and the parse is done by a mature streaming parser rather than hand-rolled. A reply with no JSON is a valid false answer, not a failure. The failures, which are all about the request or a hard ceiling: GUARD_TEXT_INVALID means text was empty, so there is nothing to look in — send the reply and retry; GUARD_TEXT_TOO_LARGE means the reply passed 2000000 characters, which is one reply's worth rather than a whole transcript, and retrying unchanged will fail again; GUARD_EXTRACTION_UNSUPPORTED means extraction, expect or onMultipleCandidates named a value outside its list, and we refuse rather than fall back to a default you did not choose; GUARD_MULTIPLE_CANDIDATES means more than one JSON value was found while onMultipleCandidates is REJECT — switch to FIRST or LARGEST, or narrow extraction; GUARD_DEPTH_EXCEEDED means the payload nests deeper than maxDepth, or maxDepth itself was outside 1 to 64 — raise it up to 64, and past that the payload is genuinely beyond what we accept; GUARD_CANDIDATE_LIMIT_EXCEEDED means one rung found more candidates than maxCandidates, or maxCandidates was outside 1 to 100; GUARD_OUTPUT_TOO_LARGE means the JSON found is over 1,048,576 characters and returnJson is on — send returnJson false and you still get the verdict, the span and the diagnostics. None of these are retryable unchanged.

Context footprint

Accepts up to 2000000 characters of model output. The answer carries the parsed value, which is bounded by the extracted span and capped at 1,048,576 characters unless you turn returnJson off, plus at most 20 diagnostics. Nothing else from your text comes back: the error messages carry line, column and member path, never the characters at that position. A successful call costs 1 execution credit.

When to use it

Immediately after any model call whose reply is supposed to be JSON, before anything downstream touches it.

When the question is whether the JSON matches your schema, when you want the broken JSON fixed rather than diagnosed, or when the payload is already known-clean JSON from a machine.

Powered by Jackson's streaming parser, the JVM's most widely deployed JSON engine, so strictness comes from a battle-tested implementation of RFC 8259.

Scope

Note
Locates a JSON value inside a model's raw reply using a published extraction ladder, parses it as strict RFC 8259, and returns the parsed value with its position and a named diagnosis when it fails.

Non-goals

  • Does not validate against a JSON Schema — schema.validate_json is the platform's only validator
  • Does not repair malformed JSON — schema.repair_json does that, and the error code here tells you when to go there
  • Does not call a model or retry one for you
  • Does not accept relaxed JSON: comments, trailing commas, single quotes, unquoted keys, NaN and Infinity are all refused by name
  • Does not reformat or pretty-print; you get the parsed value, not new text

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

parsingvalidation

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input2 MB

How we handle your data

Sensitive output possible
What this means

This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response may contain submitted or transformed content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
textstringYesRaw model reply containing the JSON to locate and parse. The skill refuses more than 2,000,000 characters with GUARD_TEXT_TOO_LARGE.
extractionstringNoExtraction ladder; omit it for AUTO. Published values: AUTO, FENCED_ONLY, WHOLE_TEXT_ONLY, FIRST_BALANCED. An unrecognised mode is GUARD_EXTRACTION_UNSUPPORTED.
expectstringNoRequired JSON shape; omit it for ANY. Published values: ANY, OBJECT, ARRAY. An unrecognised shape is GUARD_EXTRACTION_UNSUPPORTED.
onMultipleCandidatesstringNoTie-break when one rung finds several values; omit it for FIRST. Published values: FIRST, LARGEST, REJECT. An unrecognised tie-break is GUARD_EXTRACTION_UNSUPPORTED.
allowTrailingTextbooleanNoWhether prose around the JSON is allowed; omit it for true.
maxDepthintegerNoNesting ceiling enforced while parsing; omit it for 64.
maxCandidatesintegerNoHow many candidates one rung may find; omit it for 20.
returnJsonbooleanNoWhether the parsed value is returned in json; omit it for true.

Output schema

FieldTypeRequiredDescription
validbooleanYesWhether a JSON value of the demanded shape was found and parsed.
jsonobjectNoParsed JSON value returned only when valid is true and returnJson stays on.
extractedBystringYesLadder rung that produced the chosen value, or NONE.
candidateCountintegerYesHow many matching candidates the winning rung found.
spanobjectYesClosed character-offset span into the supplied text; both offsets are 0 when nothing was found.
trailingTextPresentbooleanYesWhether non-whitespace sits outside the chosen span.
errorsarrayYesBounded array of 0 through 20 closed findings with code, message, and optional placement.
summaryobjectYesClosed extraction summary with input size, span size, depth, and expected shape.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"ai.output_json_guard","input":{"text":"Here you go:\n```json\n{\"category\":\"billing\"}\n```","expect":"OBJECT"}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("ai.output_json_guard", {"expect":"OBJECT","text":"Sure — here is the classification you asked for.\n\n```json\n{\"category\": \"billing\", \"confidence\": 0.82, \"tags\": [\"invoice\", \"refund\"]}\n```\n\nLet me know if you would like it broken down further."});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
GUARD_TEXT_INVALID400NoThe request payload failed this skill's input validation.
GUARD_TEXT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
GUARD_EXTRACTION_UNSUPPORTED400NoThe skill does not support the requested variant.
GUARD_MULTIPLE_CANDIDATES412NoThe input is valid but cannot be processed as-is.
GUARD_DEPTH_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GUARD_CANDIDATE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GUARD_OUTPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not validate against a JSON Schema — schema.validate_json is the platform's only validator
  • Does not repair malformed JSON — schema.repair_json does that, and the error code here tells you when to go there
  • Does not call a model or retry one for you
  • Does not accept relaxed JSON: comments, trailing commas, single quotes, unquoted keys, NaN and Infinity are all refused by name
  • Does not reformat or pretty-print; you get the parsed value, not new text
  • Checking a payload against a JSON Schema, which belongs to schema.validate_json
  • Fixing broken JSON rather than diagnosing it
  • Parsing a payload you already know is clean JSON, where your own parser is cheaper

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "ai.output_json_guard",
  "input": {
    "expect": "OBJECT",
    "text": "Sure — here is the classification you asked for.\n\n```json\n{\"category\": \"billing\", \"confidence\": 0.82, \"tags\": [\"invoice\", \"refund\"]}\n```\n\nLet me know if you would like it broken down further."
  }
}

Examples

A fenced block wrapped in prose, which is what most models actually send

Inputjson
{
  "expect": "OBJECT",
  "text": "Sure — here is the classification you asked for.\n\n```json\n{\"category\": \"billing\", \"confidence\": 0.82, \"tags\": [\"invoice\", \"refund\"]}\n```\n\nLet me know if you would like it broken down further."
}
Expected outputjson
{
  "json": {
    "category": "billing",
    "confidence": 0.82,
    "tags": [
      "invoice",
      "refund"
    ]
  },
  "span": {
    "start": 58,
    "end": 132
  },
  "errors": [],
  "valid": true,
  "candidateCount": 1,
  "trailingTextPresent": true,
  "summary": {
    "inputChars": 191,
    "jsonChars": 74,
    "depth": 2,
    "expect": "OBJECT"
  },
  "extractedBy": "FENCED_JSON"
}
Tip
extractedBy is FENCED_JSON because the block was labelled json, so the ladder stopped on its first rung. The prose either side sets trailingTextPresent without making the answer invalid, and span tells you exactly which characters the JSON occupied.

Nearly-JSON with a trailing comma, diagnosed by name

Inputjson
{
  "text": "{\n  \"category\": \"billing\",\n  \"tags\": [\"invoice\", \"refund\",],\n}"
}
Expected outputjson
{
  "valid": false,
  "trailingTextPresent": false,
  "candidateCount": 0,
  "extractedBy": "NONE",
  "summary": {
    "inputChars": 62,
    "jsonChars": 0,
    "depth": 0,
    "expect": "ANY"
  },
  "errors": [
    {
      "code": "TRAILING_COMMA",
      "message": "A comma sits before the closing bracket with no value after it; strict JSON has no trailing commas.",
      "line": 3,
      "column": 32,
      "pointer": "/tags/2"
    }
  ],
  "span": {
    "start": 0,
    "end": 0
  }
}
Tip
valid is false and the answer names the trailing comma with a line and column, without quoting a character of the payload back. That is the signal to send this text to schema.repair_json rather than asking the model again.
  • Turn a chatty model's fenced code block into a value your code can use
  • Decide whether to retry the model or route the reply to schema.repair_json
  • Enforce a JSON-only response contract and get the position of anything that breaks it

Avoid for

  • Checking a payload against a JSON Schema, which belongs to schema.validate_json
  • Fixing broken JSON rather than diagnosing it
  • Parsing a payload you already know is clean JSON, where your own parser is cheaper

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

aijsonparsingvalidation