CLAUDE LABJP
SANDBOX — Claude Code adds a sandbox.credentials setting that blocks sandboxed commands from reading credential files and secret environment variablesMODEL — Org-configured model restrictions now apply across the model picker, --model, /model, and ANTHROPIC_MODELAGENTS — Sessions that edit, merge, comment on, or push to an existing PR now link to that PR in the claude agents viewFIX — Fixed --json-schema silently producing unstructured output on an invalid schema, plus messages lost at the --max-turns limitRECAP — Claude adds a monthly recap and focus settings in beta, with break reminders, quiet hours, and work insightsOPUS — Claude Opus 4.7 is now generally available with stronger long-running coding tasks and higher-resolution visionSANDBOX — Claude Code adds a sandbox.credentials setting that blocks sandboxed commands from reading credential files and secret environment variablesMODEL — Org-configured model restrictions now apply across the model picker, --model, /model, and ANTHROPIC_MODELAGENTS — Sessions that edit, merge, comment on, or push to an existing PR now link to that PR in the claude agents viewFIX — Fixed --json-schema silently producing unstructured output on an invalid schema, plus messages lost at the --max-turns limitRECAP — Claude adds a monthly recap and focus settings in beta, with break reminders, quiet hours, and work insightsOPUS — Claude Opus 4.7 is now generally available with stronger long-running coding tasks and higher-resolution vision
Articles/API & SDK
API & SDK/2026-07-10Advanced

My Nightly Batch Was Quietly Running on a Bigger Model — Declaring Per-Task Model Ceilings and Enforcing Them

Scatter model names through your code and a cheap batch job will eventually run on an expensive model. Here is a manifest that declares a ceiling per task, a deny-by-default resolver, and a morning audit that catches drift — with working code.

Claude API109Cost DesignModel Selection3Operations8Governance

Premium Article

I opened the billing page and my hand stopped on the trackpad.

Same number of nightly jobs as the month before. The number was 1.7x higher. When you run scheduled work unattended across several sites as a solo developer, a jump like that is not a billing anomaly. It is a signal that something in the design broke.

It took a few minutes to find. A small auxiliary task had been refactored six months earlier to pull its model name from a shared constant. That constant was named for the interactive default, and someone — me — later pointed it at a stronger model. Nobody lied. The judgment that this particular task was fine on a cheap model simply had never been written down anywhere the code could see.

The per-model entitlements and spend alerts that landed for Enterprise in July 2026 close exactly this hole at organizational scale. The same idea works at solo scale, and you can build it yourself. What follows is the implementation I run today across the four Dolice Labs sites.

Treat a model name as a contract, not a setting

To the code, model="claude-opus-4-8" is a configuration value. To operations, it is a statement about how much this task is permitted to spend per invocation.

Contracts scattered across config files get silently rewritten by refactors. So I split the two concerns.

Each task declares the minimum capability it needs and the maximum cost it tolerates. A resolver decides which concrete model satisfies those bounds.

With that split, rewriting a shared constant cannot lift a task above its ceiling. And a task that genuinely needs a stronger model now requires editing the manifest — which means the change shows up as a reviewable diff.

The manifest: what gets declared

Keep the declaration small. Anything larger stops being maintained.

FieldMeaningExample
ceilingStrongest model this task may usesonnet-5
floorBelow this, do not run at allhaiku-4-5
max_output_tokensPer-call output cap4096
daily_usdApproximate daily budget for this task alone0.80
on_ceiling_missBehavior when the request exceeds the ceilingdegrade / fail

The floor exists because silent downgrades are the worst failure mode in this system. Errors announce themselves. A weaker model producing plausible-looking output can go unnoticed for weeks. I wrote about that failure in depth in A Silent Drop to a Weaker Model Is Scarier Than an Error.

Here is a real manifest.

# config/model_entitlements.yaml
_ladder:            # cheapest first. the resolver trusts only this ordering
  - haiku-4-5
  - sonnet-5
  - opus-4-8
 
_aliases:
  haiku-4-5: claude-haiku-4-5-20251001
  sonnet-5:  claude-sonnet-5
  opus-4-8:  claude-opus-4-8
 
tasks:
  news_ticker_summarize:
    ceiling: haiku-4-5
    floor: haiku-4-5
    max_output_tokens: 1024
    daily_usd: 0.15
    on_ceiling_miss: fail
 
  article_draft:
    ceiling: sonnet-5
    floor: sonnet-5
    max_output_tokens: 8192
    daily_usd: 2.50
    on_ceiling_miss: degrade
 
  weekly_seo_synthesis:
    ceiling: opus-4-8
    floor: sonnet-5
    max_output_tokens: 4096
    daily_usd: 1.20
    on_ceiling_miss: degrade

_ladder is explicit so that nothing has to infer price ordering from a model string. Inference like that will betray you the moment a naming convention shifts. When a new model ships, a human edits those three lines. That is the only entry point.

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 120-line deny-by-default policy layer that resolves each task to the cheapest model satisfying its declared ceiling and floor
A morning audit script that reconciles declared ceiling, resolved tier, and the model the API actually billed
Clear criteria for when to degrade-and-continue versus fail hard, and why cost drift and capability drift deserve opposite treatment
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-07-01
A Fail-Closed Model Pricing Registry So New Models Don't Quietly Break Your Cost Math
When Opus 4.8 and Haiku 4.5 landed in the Messages API, rates scattered across my code silently skewed the cost rollup. Here is how to centralize per-model rates and fail closed on unknown models, with complete working code.
API & SDK2026-06-22
Your Claude Files API Storage Is Quietly Filling Up — Dedup With a Content-Hash Ledger and Reap the Orphans
Use the Files API in an automated pipeline and the same file gets uploaded again and again while orphaned files pile up unnoticed. Here is a content-hash dedup ledger plus an orphan GC design, with working code.
API & SDK2026-06-22
When Your Claude API Cost Math Doesn't Match the Bill: Accounting for the Four Token Buckets
Turn on prompt caching and your homegrown cost tally drifts from the console bill. Here is how to weight the four token buckets the usage object returns and build a ledger you can reconcile.
📚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 →