Skip to content

Build Not yet confirmed elsewhere1 publisher 3 min read Published

A quota error looks like a retry, so 15 jobs idled six hours unnoticed

One developer's LaunchAgent fleet hit Claude Code's weekly limit and kept firing. His fix is a shared circuit breaker with a state file, not better error handling inside each job.

The Engineer · Build desk

How we use AI Send a correction

What happened

  • Fifteen scheduled jobs on one developer's Mac hit Claude Code's weekly usage limit and spent six hours returning errors while appearing to run.
  • Scripts exit 1 on that error, launchd files it as a failed job, and then starts the same job again on its next cycle.
  • launchd sends no failure notice by default, and a plist has no way to say stop running until the quota resets.
  • The fix routes every job through a wrapper script via the CLAUDE variable, which runs the real binary and scans what comes back.
  • On a quota match the wrapper opens the circuit for six hours, records it in a JSON state file, and fires an alert to Discord.

Why it matters

  • capability A locked state file makes the quota a fleet-level fact: the first job to hit the ceiling stops the other fourteen without any of them spending an attempt to find out.
  • constraint With no meaningful exit code to key on, the breaker has to match the vendor's error wording, so whoever edits that string decides whether the fleet stops.
  • exposure Two of the seven trigger patterns are loose enough that unrelated output mentioning a reset time can park every Claude job on the machine.
  • decision Skipping with exit 0 keeps launchd's log clean, which moves the only evidence of a stoppage out of the scheduler and into the notifier.

The arithmetic in the writeup is on the low side. The author prices the outage at 6 hours x 15 jobs = 90 jobs' worth of work [2], which only holds if each job runs once an hour [17]. He also says these LaunchAgent entries fire every 5 minutes or every hour [7]. A five-minute job gets 72 attempts inside a six-hour window [15], so fifteen of them on that cadence would produce 1,080 invocations with no chance of succeeding [16]. Each one forked a process, made the call, was told the weekly limit was reached [3], exited 1, and was rescheduled by launchd [4].

Per-job error handling cannot close that loop, and not because the handling is sloppy. Each invocation is a short-lived process that knows nothing about the run before it or about its fourteen siblings, while the quota is a property of the account rather than of the job. The guard's answer is the cheapest shared memory available: one JSON file, an fcntl.LOCK_EX lock, and os.replace() to swap it in so concurrent writers cannot tear it [10]. That is the entire difference between fifteen jobs each finding the wall and one job finding it on behalf of the rest.

What the design trades away is detection quality. There is no exit code to key on, because Claude Code returns 0, 1, or other values depending on the situation [18], and the error text goes to stderr in a /tmp log nobody tails [6]. So the guard reads prose: seven case-insensitive regexes over the last 131,072 bytes of combined stdout and stderr [9]. Two of them, "rate limit" and "resets? (at|in|on|tomorrow)", will match output that has nothing to do with quota [9], and the penalty for a wrong match is six hours of stopped automation [8] until someone runs --reset or open_until expires [11]. The 128KB tail fails in the opposite direction: a chatty run that pushes the limit message out of the window passes as healthy.

Then there is the window itself. The limit being defended is weekly [3], while the circuit opens for 21,600 seconds and then closes on its own [8][11]. A seven-day limit period has room for twenty-eight of those windows [14], so if the reset has not arrived, the fifteen jobs wake up, trip the breaker again, and keep cycling, at a cost of one real invocation per job per reopening. That is much better than 1,080 blind attempts, but it is a rate limiter on your own retries, not a stop, and the state file never learns when the quota actually returns.

One caveat on sourcing: this is a single developer's account of his own machine, published on dev.to, and the Y1.2M/month attached to the stack is his stated revenue, not a measured loss [1]. The mechanism travels regardless. A scheduler that treats quota exhaustion as a transient error will retry at whatever cadence you configured, for as long as the quota lasts, and will file every attempt as an ordinary failure.

What to watch

  • Whether Anthropic changes the wording of its limit errors, since seven regexes are the only trigger the guard has.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence34
Adoption8
Hype gap+26
Incentives62
Confidence42
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    The author's 15 LaunchAgent jobs, behind an autonomous stack he says earns Y1.2M/month, hit Claude Code's weekly quota ceiling and then spent six hours swallowing errors while appearing to work; he discovered it the next morning by checking by hand.

    Reported Supported Source: dev.to post, author's account of his own machine2 sources— create a free account to open themView cited source
  2. [2]

    Fifteen Claude-invoking jobs run in parallel in the author's environment, so hitting the limit skips all of them at once; he counts the loss as 6 hours x 15 jobs = 90 jobs' worth of work.

  3. [3]

    Claude Code has a weekly usage limit; when it is hit, API calls come back with an error message containing the text "weekly usage limit".

    Reported SupportedView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · August 22, 2026

    6 Hours, 15 Jobs, Zero Alerts: A Circuit Breaker for Claude Code's Weekly Quota

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

Loading related stories