Skip to main content

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

Guided Failure Recovery

When a MicroSkill can’t complete a request, Squillify doesn’t just hand your agent a dead-end error string. It returns a structured, machine-readable explanation of whythe call failed and — when the problem is repairable — a ranked list of currently accessible skills your agent can call next to fix the input and try again, each still subject to the normal checks on that follow-up call. Guided Failure Recovery (GFR) turns a failure into a next step.

Note
In one sentence: skills know why they failed; Squillify knows what you can use next. GFR connects the two, so a failure becomes a routing signal instead of a wall.

The problem it solves

A traditional API answers a bad request with something like error: “Row at line 2 has 4 columns, expected 3”. For a human that’s a mild annoyance. For an autonomous AI agent it’s a dead end: the agent has to guesswhat went wrong, guess whether anything can fix it, and guess which tool to reach for — often burning tokens and retries on approaches that were never going to work.

GFR removes the guessing. Every recovery-aware failure comes back as a typed signal your agent can branch on programmatically, paired with concrete, already-accessible skills that repair the path. The agent stays in control — Squillify only advises — but it now has everything it needs to make a good decision on the first try.

What you get back

A recoverable failure carries two structured objects alongside the usual error. You route on the fields, never on the prose message.

The failure envelope — why it failed

FieldWhat it tells you
categoryA stable, coarse taxonomy of the failure — e.g. VALIDATION_ERROR, PRECONDITION_FAILED, POLICY_DENIED, LIMIT_EXCEEDED, DEPENDENCY_UNAVAILABLE.
codeA stable, specific reason code such as CSV_MALFORMED or JSON_MALFORMED. Safe to branch on; a code change is treated as a contract change.
recoverabletrue when a repair path may exist. Only recoverable failures trigger a recovery lookup.
retryabletrue when the exact same call might succeed if you simply retry it (a transient blip). Different from recoverable.
recovery_intentThe kind of repair needed (e.g. format_inspection, json_repair) — a stable token describing the fix, not a skill name.
message / detailsHuman-readable context only. Never parse the message; details carry bounded, safe metadata (never your payload).

The recovery block — what you can do next

When a recoverable failure has a known repair intent, Squillify attaches an advisory recovery block with a ranked list of options:

FieldWhat it tells you
availabletrue when at least one option you can actually access was found.
options[].skill_name / skill_versionThe exact skill to call to perform the repair. At response time it has passed your current access scope; the follow-up call still goes through normal authorization, quota, and policy checks.
options[].purposeA plain, agent-facing sentence describing what running this skill will do for you before you retry.
options[].then_retryAn advisory hint naming the original skill to re-run once the repair succeeds. Squillify never runs it for you.

How Squillify finds your options

When a failure is recoverable, the runtime asks OSRE— Squillify’s skill resolution engine, the same engine behind Dynamic Skill Resolution — for existing skills that explicitly declarethey can satisfy the repair intent. The lookup is scoped to the caller’s current access and policy context, and is deliberately trustworthy:

  • Declared, not guessed. A skill can only be offered as a fix if it declares a compatible recovery capability. Squillify never suggests a skill just because it sounds similar.
  • Scoped to you.Options are intersected with your API key’s current access scope. The follow-up call still goes through normal authorization, quota, and policy checks.
  • Deterministic within context. For the same catalog version, access scope, policy state, and failure context, the same recovery options are returned in the same order.
  • Best-effort enrichment. Recovery resolution must never mask the original failure. If it is unavailable or exceeds its budget, Squillify returns the original failure without recovery options.

How your agent uses it

Here is a real recoverable failure from data.csv_normalize, trimmed to the parts that matter:

Recoverable failure responsejson
{
  "error": { "code": "CSV_MALFORMED", "message": "...", "request_id": "..." },
  "failure": {
    "category": "VALIDATION_ERROR",
    "code": "CSV_MALFORMED",
    "recoverable": true,
    "retryable": false,
    "recovery_intent": { "intent": "format_inspection" }
  },
  "recovery": {
    "available": true,
    "options": [
      {
        "rank": 1,
        "skill_name": "schema.infer_csv_schema",
        "skill_version": "1.0.0",
        "purpose": "Inspect the CSV structure, detect column counts, and identify malformed rows before retrying the original CSV normalization.",
        "then_retry": { "skill_name": "data.csv_normalize", "advisory": true }
      }
    ]
  }
}

A robust recovery loop looks like this:

  1. On any failure, branch on failure.category and failure.code— the stable fields — not on the human message.
  2. If failure.recoverable and recovery.available, call the first option’s skill_name to repair the input, then re-run the original skill named in then_retry.
  3. If the failure is retryable but not recoverable, just retry the same call with backoff.
  4. If recovery.available is false, don’t try to infer why — treat it as “no guided path right now” and fall back to your own handling.

Over MCP and REST

GFR is delivered the same way regardless of how you connect, and it is fully backward compatible — older clients keep working unchanged.

  • MCP.The tool result keeps its existing human-readable text item and, when there’s a typed failure, appends a second JSON content item under squillify_failure carrying the failure and recovery blocks. The recovery guidance is also baked into the tool description, so an agent connecting over MCP is told to prefer listed skills and never invent recovery skills.
  • REST (POST /v1/execute). The failure body gains top-level failure and recovery objects plus compact error.recoverable / error.recovery_available flags for lean clients. Advisory response headers mirror those flags for proxies, but the JSON body is always authoritative.
Tip
Using an official Squillify SDK? The TypeScript, Python, Rust, and Java SDKs preserve failure and recovery metadata on the typed result error and expose helpers like hasRecoveryOptions(), recoveryOptions(), and bestRecoveryOption(), so most agents do not need to parse raw JSON.

Recovery, not fallback

This is the most important thing to understand about how GFR behaves. A recovery option only ever repairs your input so the original skill can be retried toward the same goal— it prepares, normalizes, sanitizes, decomposes, or enriches. It will never quietly swap in a different skill that reaches the goal another way.

The test is simple: after the suggested skill runs, can the original skill be retried with a better chance of success?If not, it isn’t offered. That keeps your agent’s intent intact and avoids silent goal substitution.

What GFR does not do

Setting expectations clearly is part of trusting the feature. GFR deliberately stays out of your agent’s way:

  • It does not execute recovery automatically.
  • It does not reserve quota for suggested follow-up calls.
  • It does not guarantee that a suggested skill will still be available later.
  • It does not invent missing skills.
  • It does not replace your agent’s planning logic.
  • It does not offer fallback routes that change the original goal.

Guarantees you can rely on

  • Advisory, never orchestrating. Squillify resolves and suggests options; it never executes them, reserves no quota for them, and the original failure is always the canonical result.
  • Caller-scoped.You’re only ever shown skills you can already access.
  • No information leaks.When no option is available, Squillify says exactly that — it never reveals why (whether a skill doesn’t exist, isn’t accessible to you, or was filtered by policy).
  • Policy-safe. For policy-denied failures, recovery is deny-by-default: a fix is only offered when an explicit rule allows it, so recovery can never hand you a workaround that defeats a policy.
  • Billing-invariant. Turning recovery on does not change the cost of the failed call. Recovery resolution emits no billable event, and the same failure costs the same with recovery enabled or disabled. If your agent chooses to call a suggested recovery skill, that follow-up execution is billed normally.

When there’s no option yet

Sometimes a failure is genuinely recoverable in principle, but no skill in the catalog yet provides the needed repair — for example, a JSON_MALFORMED failure whose json_repairfix doesn’t exist as a skill today. Squillify records this as a catalog gap: a real product signal that helps us prioritize which capabilities to build next. Your agent simply sees recovery.available: false and handles it like any other no-guided-path case.

Why it matters

  • Fewer wasted attempts. Agents stop guessing and go straight to a repair that is known to help.
  • Higher end-to-end success.Complex, multi-step problems become navigable: inspect → repair → retry, guided by the platform.
  • Deterministic and safe. Reproducible within a given catalog and access context, scoped to your access, with no billing surprises and no policy escapes.
  • Zero migration cost.It’s additive over both REST and MCP; existing integrations keep working, and you adopt it when you’re ready.