Use when an agent harness must respect upstream model/tool rate limits, manage quotas across concurrent sessions, and handle 429s without dropping work. Apply when designing the queue/throttle layer in front of model and tool calls. Covers token-bucket vs leaky-bucket, per-key vs global quotas, backoff strategies (exponential, jittered), queue fairness across sessions, and 429/Retry-After handling.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Use when an agent harness must respect upstream model/tool rate limits, manage quotas across concurrent sessions, and handle 429s without dropping work. Apply when designing the queue/throttle layer in front of model and tool calls. Covers token-bucket vs leaky-bucket, per-key vs global quotas, backoff strategies (exponential, jittered), queue fairness across sessions, and 429/Retry-After handling.
Rate Limiting
Pain Signals — You Need This Pattern When:
Bursts of agent activity hit the model API's RPM/TPM ceiling and 429s spike
One greedy session starves others on a shared API key
Backoff retries pile on during incidents — making outages worse
Tool calls (external APIs, DB) have their own rate limits and the harness ignores them
Cost spikes because retries on 429 doubled the bill before respecting Retry-After
Rate limiting is bidirectional. The harness must respect upstream limits and fairly allocate its own capacity across concurrent users/sessions.
Core Principle
Treat upstream limits as shared resources the harness must schedule against. Three interacting concerns:
Predictive limiting — know your budget and stay under it
Reactive handling — when you hit a limit anyway, back off correctly
Fair allocation — when capacity is scarce, distribute it across sessions
Anthropic API (and most LLM APIs) enforces multiple concurrent limits. All matter:
Limit
Unit
What hits it
RPM
requests / minute
Many small calls
ITPM
input tokens / minute
Long-prefix calls
OTPM
output tokens / minute
Long generations
Concurrent
in-flight requests
Many parallel sessions
The harness can hit any of these. Track all four. Predict against all four.
Token Bucket
Token-bucket is the right default. A bucket of capacity C refills at rate R; each request consumes 1 token (RPM bucket) or N tokens (TPM bucket). Empty bucket → request waits or rejects.
After response, reconcile estimate vs actual; adjust bucket if undersized. Over-estimate is safer — wastes some capacity but avoids breaches.
429 Handling
429 means you exceeded the limit despite predicting. Recover correctly:
Read Retry-After — server says when to retry. Honor it precisely; do not retry sooner.
Don't immediately retry without honoring — adds load to a service already saying "back off."
Update local bucket — your prediction was wrong; recalibrate.
Don't compound — many concurrent requests retrying without coordination = thundering herd. Use a singleton bucket; failures wait on the bucket, not on independent timers.
asyncdefcall_with_retry(request, max_retries=3):
for attempt inrange(max_retries + 1):
try:
returnawait call_model(request)
except RateLimitError as e:
wait = e.retry_after or backoff(attempt)
wait += random.uniform(0, wait * 0.1) # jitterawait asyncio.sleep(wait)
raise BudgetExhausted()
Backoff
When Retry-After is missing, backoff is your fallback:
Strategy
Use
Exponential + jitter
Default. Doubles each attempt; jitter prevents synchronization.
Linear
Tighter timing requirement, low retry count
No backoff
Never. Retrying immediately is always wrong on 429.
Cap max wait. After N attempts or T total wait, fail the request; don't retry forever.
Fair Allocation
In multi-session harness, one session can monopolize the shared bucket. Defenses:
Per-session cap prevents one session from consuming >X% of the global budget at once.
Queue Discipline
When multiple requests wait on the bucket, FIFO is the default. Edge cases:
Priority — interactive turns over batch jobs; size-based (small first to reduce average wait)
Deadline-aware — drop requests whose deadline has passed
Cancellation — cancelled session's queued requests must be removable
Queue depth is a load metric; alarm when it grows.
Tool Rate Limits
Don't only think about the model API. Tool calls hit external services:
GitHub API: 5000 req/hr authenticated
Search APIs: per-key quotas
Internal services: their own RPS limits
Treat tool calls like model calls: per-tool buckets, predictive consumption, 429 handling. The agent loop fanning out tool calls can DoS your own backends.