DEV Community

Christopher Hoeben
Christopher Hoeben

Posted on • Originally published at stickwithfiddle-sys.github.io

How to migrate production prompts between GPT-5.5 and Claude Fable 5 without breaking schemas or burning tokens

How to migrate production prompts between GPT-5.5 and Claude Fable 5 without breaking schemas or burning tokens

A developer’s guide to handling refusal schemas, cost deltas, and scaffolding changes when swapping frontier models in production.

TL;DR: Audit prompts for Fable 5’s long-run scaffolding needs and refusal schema, strip GPT-5.5 retry loops that amplify token burn, and route by complexity: use Fable 5 where its SWE-Bench Pro lead justifies the $10/$50 per 1M token cost, while keeping GPT-5.5 at $5/$30 for simpler tasks. Validate all outputs with strict schema contracts.

Strip GPT-5.5 loop scaffolding and retarget for long-run agents

Replace GPT-5.5's retry harnesses and Codex CLI scaffolding with one comprehensive long-run prompt that lets Claude Fable 5 reason through the full task without interruption. This retargeting removes the tight feedback loops that Codex CLI relies on and replaces them with a single inference pass that includes full context, reasoning instructions, and exit criteria. Because GPT-5.5 tends to loop on complex problems rather than fixing them, production prompts often include retry logic that assumes iterative failure. Fable 5 is designed for end-to-end work that previously took hours, days, or weeks, so a common approach is to strip that loop and give the model room to solve the problem in a single pass. Remove intermediate validation gates that force the model to stop between sub-steps; embed success criteria and self-check instructions directly in the prompt so the agent can iterate internally. Test this change on your hardest unsolved problems, because evaluating Fable 5 only on simpler workloads undersells its capability range.

Before—tight retry loop for GPT-5.5:

# GPT-5.5 pattern: iterative retry loop via Codex CLI
for attempt in range(RETRIES):
    output = codex_cli.run(prompt)
    if output.valid:
        break
    prompt += f"\nFailure: {output.error}"
Enter fullscreen mode Exit fullscreen mode

After—single long-run prompt for Fable 5:

# Fable 5 pattern: single Messages API call with full context
response = client.messages.create(
    model="<fable-5-model-id>",
    messages=[{
        "role": "user",
        "content": (
            "Reason through the entire task end-to-end and produce a complete, "
            "validated solution without stopping for external confirmation.\n\n"
            f"{task_context}"
        )
    }]
)
Enter fullscreen mode Exit fullscreen mode

Handle Fable 5 refusals in your schema without throwing errors

Parse stop_reason and stop_details.category from the HTTP 200 response so your pipeline treats Fable 5 refusals as structured outcomes instead of exceptions. This prevents legitimate safety declines from triggering hard-failure logic designed for error codes.

Fable 5 ships with new classifiers for cybersecurity, biology/chemistry, and distillation attempts. When it declines, the Messages API returns HTTP 200 with stop_reason set to "refusal", and stop_details.category can be "cyber", "bio", "reasoning_extraction", or null. If your schema expects a content block or a tool call and raises when either is absent, you will break on every legitimate refusal. Update your response handler to inspect these fields before parsing content.

if response.stop_reason == "refusal":
    category = response.stop_details.category
    log_refusal(category, response.id)
    return RefusalOutcome(category=category)
Enter fullscreen mode Exit fullscreen mode

Update your response schema to treat stop_reason and stop_details as first-class fields rather than error states. A common approach is to branch on stop_reason immediately after the API call and only then attempt to validate tool arguments or message content. That way a refusal flows through your normal orchestration graph instead of crashing the job, and you can route each category to its own audit trail or fallback prompt without burning tokens on retries. Logging the exact category also lets you tune retries: a reasoning_extraction refusal may warrant a re-prompt, while a bio refusal should surface to a human reviewer.

Optimize token spend using the 2× cost delta and benchmark fit

Route complex, architecture-heavy prompts to Claude Fable 5 and keep GPT-5.5 for fast, straightforward tasks so you only pay the premium where the benchmark gap justifies it. Fable 5 input/output pricing is $10/$50 per 1M tokens versus GPT-5.5 at $5/$30 per 1M tokens, which means a uniform routing strategy doubles costs without improving outcomes on simple workloads. Fable 5 leads SWE-Bench Pro 80.3 to 58.6 and Terminal-Bench 2.1 88.0 to 83.4, so the higher per-token rate is justified for advanced architecture and complex problem-solving. For routine text generation or shallow queries, GPT-5.5 is the cheaper fit and prevents wasted spend.

A common approach is a lightweight router that inspects prompt complexity before calling the API:

def route(prompt: str, expected_tokens: int) -> str:
    hard_tags = {"refactor", "architecture", "debug", "multi-step"}
    if any(tag in prompt.lower() for tag in hard_tags) or expected_tokens > 2500:
        return "claude-fable-5"  # $10/$50 per 1M tokens
    return "gpt-5.5"             # $5/$30 per 1M tokens
Enter fullscreen mode Exit fullscreen mode

You can also enforce a token budget by model tier. If a GPT-5.5 run exceeds a context threshold or fails a validation check, escalate to Fable 5 rather than paying for repeated cheap attempts that accumulate:

if token_count > 12000 or validation_failed:
    response = call_fable_5(prompt)  # premium tier backed by SWE-Bench Pro 80.3 vs 58.6
else:
    response = call_gpt_55(prompt)   # fast path, avoids burning tokens on easy jobs
Enter fullscreen mode Exit fullscreen mode

This keeps spend low on the $5/$30 per 1M tier while reserving the $10/$50 per 1M tier for requests where the capability delta is measurable.

Lock output schemas with validation layers for both models

Enforce a single normalized schema at the API boundary so downstream consumers never see model-specific field ordering, optional keys, or refusal shapes. A lightweight validator sits between the raw LLM response and your business logic, absorbing structural differences between GPT-5.5 and Fable 5 before any downstream type touches the payload.

Because Fable 5 has several behavioral differences from Claude Opus 4.8 that may require prompt or scaffolding updates, a common approach is to add a strict output-schema validator that normalizes field order, optional keys, and refusal metadata before downstream consumption. Fable 5 returns HTTP 200 with stop_reason "refusal" when its classifiers decline a request, and stop_details.category can be "cyber", "bio", "reasoning_extraction", or null. Your validation layer should map every payload into the same canonical shape so that switching models does not break your downstream types, even when stop_reason or reasoning structure differs.

from pydantic import BaseModel
from typing import Literal, Optional

class CanonicalResponse(BaseModel):
    content: Optional[str] = None
    stop_reason: Optional[str] = None
    refusal_category: Optional[
        Literal["cyber", "bio", "reasoning_extraction"]
    ] = None
Enter fullscreen mode Exit fullscreen mode

A thin normalization function extracts refusal metadata safely and drops unknown fields:

def normalize(raw: dict) -> CanonicalResponse:
    details = raw.get("stop_details", {})
    return CanonicalResponse(
        content=raw.get("content"),
        stop_reason=raw.get("stop_reason"),
        refusal_category=details.get("category")
        if raw.get("stop_reason") == "refusal"
        else None,
    )
Enter fullscreen mode Exit fullscreen mode

By forcing both models through this layer, you isolate stop_reason and refusal handling from the rest of your pipeline.

Gate sensitive domains through vetted access on both sides

Before migrating production prompts in cybersecurity or biology, confirm your organization is approved for trusted-access programs on both APIs; otherwise you will hit hard refusals that no prompt engineering can override. Both labs now gate cybersecurity and biology prompts behind vetted access programs, and Claude Fable 5 surfaces refusals explicitly through its response schema rather than an error code. When Fable 5 classifiers detect a gated topic, the Messages API returns HTTP 200 with stop_reason set to "refusal" and stop_details.category set to "cyber" or "bio", so standard retry loops that only catch HTTP 4xx/5xx will miss it entirely. Because these refusals are policy-enforced and not model uncertainty, no system prompt or few-shot examples will override them. Your migration code must branch on these fields and fail open to human review instead of rephrasing automatically. Wire this check into your request router so that unapproved traffic never reaches the downstream schema parser, preventing silent data errors from partial completions.

if msg.stop_reason == "refusal":
    cat = msg.stop_details.category   # "cyber" or "bio"
    log_gated_refusal(cat)
    raise SystemExit("Trusted-access required; prompt tuning will not help.")
Enter fullscreen mode Exit fullscreen mode

Until your accounts are explicitly approved for both programs, do not route sensitive-domain prompts to either model in production. Attempting to bypass the gate with alternate wording burns tokens and violates platform policies.

FAQ

Will my existing GPT-5.5 JSON output parsers work with Claude Fable 5?

Not always. Fable 5 may return stop_reason "refusal" with stop_details.category set to "cyber", "bio", "reasoning_extraction", or null, which can break parsers that only expect content blocks. A common approach is to validate the presence of stop_reason before extracting JSON.

Is Claude Fable 5 always more expensive than GPT-5.5?

Yes, per-token pricing is roughly double: Fable 5 costs $10/$50 per 1M input/output tokens versus GPT-5.5 at $5/$30 per 1M. However, for complex workloads its higher pass rates on SWE-Bench Pro and Terminal-Bench 2.1 can reduce the total number of calls needed.

Do I need separate approval to run cybersecurity or biology prompts in production?

Both labs restrict these domains and offer vetted access. Fable 5 will return a refusal category such as "cyber" or "bio" if the classifiers fire, so you must have trusted-access programs in place before migrating sensitive production prompts.

Should I replace GPT-5.5 entirely with Fable 5?

A common approach is to use both. GPT-5.5 is faster and cheaper for straightforward tasks, while Fable 5 excels at end-to-end complex work that takes hours or days. Route by complexity to avoid burning tokens.

What is the simplest way to test if Fable 5 fits my existing prompt?

Test it on your hardest unsolved problem rather than a simple workload, because teams that evaluate Fable 5 only on easier tasks tend to undersell its capability range. If the prompt currently causes GPT-5.5 to loop or repeat mistakes, Fable 5 is a strong candidate.


I packaged the setup above into a ready-to-use kit — **The Fable 5 / GPT-5.5 Migration Kit: Prompt Rewrites & Breaking-Change Checklists* — for anyone who'd rather copy-paste than wire it from scratch: https://unfairhq.gumroad.com/l/hzsoc.*

Top comments (0)