CLAUDE LABJP
CORPS — Anthropic unveils Claude Corps (Jun 11), a $150M national fellowship placing 1,000 early-career workers inside US nonprofits; the first cohort starts in OctoberSUBAGENTS — Claude Code sub-agents can now spawn their own sub-agents, up to 5 levels deep — multi-stage delegation workflows out of the boxWORKFLOWS — Dynamic workflows arrive in research preview across CLI, Desktop, and VS Code for codebase-wide bug hunts and large migrations (Max/Team/Enterprise)BILLING — 2 days to the Jun 15 change: Agent SDK, headless runs, and GitHub Actions move to monthly credits ($20/$100/$200); Sonnet 4 and Opus 4 retire from the API the same dayFABLE5 — Fable 5 remains included free on Pro, Max, Team, and Enterprise through Jun 22CODE80 — IPO coverage reports Claude now writes over 80% of its own code, up from under 10% in February 2025CORPS — Anthropic unveils Claude Corps (Jun 11), a $150M national fellowship placing 1,000 early-career workers inside US nonprofits; the first cohort starts in OctoberSUBAGENTS — Claude Code sub-agents can now spawn their own sub-agents, up to 5 levels deep — multi-stage delegation workflows out of the boxWORKFLOWS — Dynamic workflows arrive in research preview across CLI, Desktop, and VS Code for codebase-wide bug hunts and large migrations (Max/Team/Enterprise)BILLING — 2 days to the Jun 15 change: Agent SDK, headless runs, and GitHub Actions move to monthly credits ($20/$100/$200); Sonnet 4 and Opus 4 retire from the API the same dayFABLE5 — Fable 5 remains included free on Pro, Max, Team, and Enterprise through Jun 22CODE80 — IPO coverage reports Claude now writes over 80% of its own code, up from under 10% in February 2025
Articles/API & SDK
API & SDK/2026-06-13Advanced

Auditing pinned model IDs before claude-sonnet-4 and claude-opus-4 retire from the API

On June 15, claude-sonnet-4 and claude-opus-4 retire from the API. Here is how to find every pinned model ID before then, measure output parity, and cut over safely with an alias layer and a fallback.

api-sdk9migration5model-deprecationproduction88

Premium Article

When you read "claude-sonnet-4 and claude-opus-4 retire from the API on June 15," the first thing to check is where those model IDs are hard-coded in your own code. The trouble is never in the obvious places. It is the nightly batch you wrote six months ago and never reopened, the default value of an environment variable, or the model: "claude-opus-4" buried inside a vendored wrapper you integrated long ago. On retirement day, that one spot quietly starts returning model_not_found.

As an indie developer, I have stepped on these forgotten constants more than once. The more reliable a piece of code is, the less you reread it, so when the retirement notice lands and you reach for a full-text search, your search term fails to match and you miss the very spots that matter. This walkthrough removes those misses mechanically, and carries the migration all the way through to a verified, staged cutover.

grep alone misses things — audit mechanically first

If grep -r "claude-opus-4" were enough, there would be no problem. What slips through are IDs embedded as defaults like os.environ.get("MODEL", "claude-opus-4"), IDs sitting as plain strings in config.json, and IDs written with a date suffix such as claude-opus-4-20250514.

So instead of searching for what is leaving, keep an allowlist of what is current and surface every other claude-*. Name the two retiring models explicitly, but also flag any unfamiliar ID as "confirm."

#!/usr/bin/env python3
"""Surface retiring or unknown model IDs left in a production codebase."""
import re
import sys
from pathlib import Path
 
# Model IDs current as of 2026-06 (anything else is treated as "confirm").
# Always verify the exact, latest IDs in the official docs.
ALLOWED = {
    "claude-opus-4-8",
    "claude-sonnet-4-6",
    "claude-haiku-4-5",
}
# Explicit targets retiring from the API on 6/15.
RETIRING = {"claude-sonnet-4", "claude-opus-4"}
 
# Anything that looks like a model ID, including a -20250514 date suffix.
MODEL_RE = re.compile(r"claude-[a-z]+-[0-9][a-z0-9-]*")
SCAN_EXT = {".py", ".ts", ".tsx", ".js", ".mjs", ".json",
            ".yaml", ".yml", ".env", ".toml", ".sh"}
 
 
def normalize(model_id: str) -> str:
    # Drop the trailing date suffix so we compare by "generation".
    return re.sub(r"-\d{8}$", "", model_id)
 
 
def scan(root: str):
    hits = []
    for path in Path(root).rglob("*"):
        if path.is_dir() or path.suffix not in SCAN_EXT:
            continue
        if "node_modules" in path.parts or ".git" in path.parts:
            continue
        try:
            text = path.read_text(encoding="utf-8", errors="ignore")
        except OSError:
            continue
        for lineno, line in enumerate(text.splitlines(), 1):
            for raw in MODEL_RE.findall(line):
                base = normalize(raw)
                if base in RETIRING:
                    hits.append((str(path), lineno, raw, "RETIRING 6/15"))
                elif base not in ALLOWED:
                    hits.append((str(path), lineno, raw, "unknown - confirm"))
    return hits
 
 
if __name__ == "__main__":
    root = sys.argv[1] if len(sys.argv) > 1 else "."
    found = scan(root)
    for path, lineno, model, tag in found:
        print(f"[{tag}] {path}:{lineno}  {model}")
    print(f"\n{len(found)} model IDs need attention", file=sys.stderr)
    sys.exit(1 if found else 0)

Run it at the repository root with python3 scan_models.py ., and any line tagged [RETIRING 6/15] is a spot that will error on the day. The allowlist approach also means that when a different model retires later, you update the allowlist and reuse the same scanner.

One caveat: fixing all the code does not fully settle it. IDs can linger in in-flight request logs or dashboard queries. Aggregate the last 30 days of request logs and print the distribution of model IDs actually being called — that catches the case where you thought you removed an ID from code but a code path still reaches it.

Why "sed it all at once" is dangerous

Once you have the hits, it is tempting to bulk-replace claude-opus-4 with claude-opus-4-8. But replacing a model ID is not a string edit — it is a behavior change. A newer generation can shift output token volume for the same prompt, shift latency, and subtly shift formatting habits (bulleted versus prose, how code blocks are fenced).

This is where one design decision pays off: do not scatter IDs through your code. If client.messages.create(model="...") appears in dozens of places, every replacement means reviewing dozens of spots — and you will miss exactly one. After getting burned by that one missed spot, I started confining model IDs to a single layer. The concrete implementation comes later.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A Python scanner that surfaces claude-sonnet-4 / claude-opus-4 hiding in code, cron jobs, config files, and vendored SDKs
A parity harness that measures what a naive replacement breaks (output token volume, formatting, downstream parsers) before retirement day
An alias layer that turns the next retirement into a one-line change, plus a fallback that surfaces model_not_found instead of swallowing it
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API & SDK2026-05-05
The Real Cost of Claude API Extended Thinking in Production — ROI Data by Task Type
Three months of measured cost, quality, and speed data for Extended Thinking across five task categories. Learn exactly when extended thinking is worth it—and when it's not.
API & SDK2026-05-03
Building a Production-Grade Contract Review System with the Claude API — Risk Detection, Version Diffing, and Remediation Suggestions
A complete production guide for automating contract review with the Claude API: PDF parsing, risk clause detection, structured JSON output, version diffing, and remediation suggestions.
API & SDK2026-04-26
Replay-Driven Testing for Claude API: A Production Pattern for Recording and Replaying Responses
A production-grade design for stabilizing Claude API tests by recording and replaying real responses. Covers cassettes for Messages, Streaming, Tool Use, CI integration, and incident replay.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →