Sandbox
@cheapestinference/claude-auto-retry

Auto-retry wrapper for Claude Code in tmux

This tool sits around Claude Code and watches for limit banners, overload errors, safeguard flags, and interrupted streams. When it sees one, it waits, retries, or resumes by sending the next message automatically. It uses tmux so the monitor can keep running even if your terminal disconnects.

368 stars70 forksJavaScriptUpdated 21d ago
Who it's for

Builders who run Claude Code on long sessions and want retries to happen without manual babysitting.

What it delivers

You can leave Claude Code running through limits and transient errors without coming back to retype continue.

What it does

Usage limit retry

Detects printed reset times, waits until the limit clears, and sends `continue` automatically.

Tmux-aware session handling

Creates or reuses a tmux session so monitoring keeps working across disconnects.

Overload backoff

Retries terminal `429/5xx/529` overload errors with exponential backoff and jitter.

Safeguard retry

Re-sends a short retry message when Claude Code falsely flags a message with safeguards.

Interrupted stream resume

Resumes after sleep, disconnect, or stalled-response errors that leave the prompt idle.

Hook-based overload detection

Can install a `StopFailure` hook so overload retries use event markers instead of terminal scraping.

Reconcile support

Can re-arm monitors for live Claude sessions that lost their watcher.

How to get it

  1. 1Run
    ⏺ Approaching your 5-hour usage limit — Claude will wrap up the current step.
  2. 2Run
    git clone https://github.com/cheapestinference/claude-auto-retry.git
    cd claude-auto-retry
    npm test            # Run all 128 tests
    npm link            # Install locally for testing

README

claude-auto-retry

Automatically retry Claude Code sessions when you hit Anthropic subscription rate limits.

When Claude Code shows "5-hour limit reached - resets 3pm", this tool waits for the reset and sends "continue" automatically. You come back to find your work done.

No dependencies. No workflow change. Just install and forget.

npm version License: MIT Node.js >= 18

📢 Status (Aug 2026): The Claude Desktop app now does this natively — an "☑ Auto-continue when limits reset" checkbox (confirmed in the wild). The CLI still doesn't have it — that's the gap this tool covers today. Track anthropics/claude-code#35744 for the native CLI version; until it lands, npm i -g claude-auto-retry is the way.


💡 Why wait out the limit at all? This tool auto-resumes Claude Code the moment you're rate-limited — but if you run overnight jobs or always-on agents, there's a way to stop hitting the wall in the first place. See how it's done →

The Problem

You're in the middle of a complex task with Claude Code. After a while, you see:

You've hit your limit · resets 3pm (Europe/Dublin)

Claude stops. You have to wait hours, come back, and type "continue". If you're running long tasks overnight or while AFK, this kills your productivity.

The Solution

npm i -g claude-auto-retry
claude-auto-retry install

That's it. Type claude as you always do. When the rate limit hits, the tool:

  1. Detects the rate limit message in the terminal
  2. Parses the reset time (timezone-aware)
  3. Waits until the limit resets + 60s margin
  4. Verifies Claude is still the foreground process
  5. Sends "continue" automatically

You come back to find your task completed.

How it Works

You type "claude"
       │
       ▼
  Shell function (injected in .bashrc/.zshrc)
       │
       ├─ Already in tmux? ──▶ Start background monitor
       │                        Launch claude with full TUI
       │
       └─ Not in tmux? ──▶ Create tmux session transparently
                             Launch claude + monitor inside
                             Attach (looks the same to you)

  MONITOR (background, ~0% CPU):
       │
       ├─ Polls tmux pane every 5 seconds
       ├─ Detects rate limit text
       ├─ Parses reset time from message
       ├─ Waits until reset + safety margin
       ├─ Verifies Claude is still the foreground process
       └─ Sends "continue" via tmux send-keys

Why tmux?

When you disconnect (SSH drops, close terminal, laptop sleeps), tmux keeps running. The monitor keeps waiting. When you reconnect with tmux attach, you find Claude working on your task. This is the key advantage over wrapper scripts.

Features

  • Zero workflow change — same claude command, same TUI, same everything
  • Works with and without tmux — auto-creates tmux session if you're not already in one
  • Auto-installs tmux if missing (apt, dnf, brew, pacman, apk)
  • Timezone-aware — parses reset times with full IANA timezone support (including half-hour offsets)
  • DST-safe — iterative offset correction handles daylight saving transitions
  • Safe send-keys — verifies Claude is still the foreground process before injecting text
  • Self-healing coveragereconcile re-arms monitors for any live claude session that lost one; an optional timer (systemd --user on Linux, launchd on macOS) runs it automatically (details)
  • Overload backoff — detects sustained API overload (429/500/502/503/504/529) and retries on a configurable exponential backoff with jitter and a cumulative-wait cap, distinct from the usage-reset path (details)
  • Safeguard retry — auto-continues past an AUP-safeguard false-positive (often transient), capped at a few tries so a sticky flag can't loop (details)
  • Interrupted-stream resume — picks the work back up when a laptop suspend or a dropped connection truncates a response mid-turn and leaves the session parked at an idle prompt (details)
  • Near-limit wrap-up nudge — when Claude Code winds the turn down at ~95% of the 5-hour window ("Approaching your 5-hour usage limit — Claude will wrap up the current step") and parks the session at an idle prompt with no limit banner, sends one continue so the work runs on to the real limit, where the usage wait takes over (details)
  • tmux status bar indicator — see at a glance whether a pane is being monitored, waiting on a reset, backing off from overload, or has given up (details)
  • --print mode support — buffers output, retries cleanly for piped/scripted usage
  • Configurable — retry count, wait margin, custom patterns, retry message
  • Config validation — bad config values fall back to safe defaults instead of crashing
  • Zero dependencies — pure Node.js, no node_modules

Messages Detected (verbatim)

The tool acts on these real-world Claude Code renders — if you landed here after pasting one of these errors into a search engine or an AI assistant: yes, this tool automates the wait-and-retry for all of them.

Usage / session limits — waits until the printed reset, then continues

RenderExample
N-hour limit5-hour limit reached - resets 3pm (UTC)
Session limitYou've hit your session limit · resets 2am (Europe/Zurich)
Weekly limitYou've hit your weekly limit · resets Oct 9, 10am
Usage limitClaude usage limit reached. Resets at 2pm
Out of extra usageYou're out of extra usage · resets 3pm
Try againPlease try again in 5 hours
Hit your limitYou've hit your limit · resets 3pm (Europe/Dublin)
Rate limitRate limit hit. Resets at 4pm
Live-limit companion hint/usage-credits to finish what you're working on.

The /rate-limit-options menu — driven to "Stop and wait", never "Upgrade"

What do you want to do?
❯ 1. Upgrade your plan
  2. Stop and wait for limit to reset (3pm)

Handled across any menu layout (the option order varies by Claude Code version); the tool locates the cursor and the "Stop and wait" option, and refuses to press Enter if the layout is unreadable.

API overload / transient errors — exponential backoff with jitter

RenderExample
Terminal API error (colon form)API Error: 529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}
5xx familyAPI Error: 500 / 502 / 503 / 504 … (including bodyless renders like 503 no healthy upstream)
API-level 429API Error: Server is temporarily limiting requests (not your usage limit) · Rate limited

Safeguard false positives — bounded immediate re-send

API Error: <model>'s safeguards flagged this message (https://www.anthropic.com/legal/aup).
They may flag safe, normal content as well. … Claude Code can't respond to this request with <model>.

Interrupted streams — one resume, then stop

API Error: Your computer went to sleep mid-response. The response above may be incomplete.
API Error: Connection lost mid-response. The response above may be incomplete.
API Error: The response stopped arriving. The response above may be incomplete.
API Error: Server error mid-response. The response above may be incomplete.

…and the three "before a response was produced. Try again." variants (suspend, stall, connection). All seven come from the same stream finalizer and leave the same wreckage: a truncated turn at an idle prompt.

Near-limit wrap-up — one nudge, then the usage wait

⏺ Approaching your 5-hour usage limit — Claude will wrap up the current step.

Not an error: Claude Code prints this at ~95% of the window and tells the model to checkpoint. The model finishes the step, lists what's left and ends the turn — no banner, idle prompt, nothing resumes it. One continue picks the work back up.

Custom patterns can be added via config for future message format changes.

Detection is chrome-aware: it looks at the live bottom of the pane, but first skips past Claude Code's UI furniture — the input box, footer, key hints, the todo/task widget, the status spinner, and the /usage-credits hint. So a genuine limit banner still registers even when a tall task list or background-agent status pushes it well above the prompt, while a banner merely quoted in scrollback (with real output below it) does not trigger a retry.

Your own customPatterns are the exception: they are matched against the raw last-N lines (not the chrome-skipped view), so a pattern keyed on footer text — a usage percentage, a model name — keeps firing. You own the false-positive tradeoff for your regexes; the built-in detection keeps the chrome-aware discipline.

Configuration

Optional. Create ~/.claude-auto-retry.json:

{
  "maxRetries": 5,
  "pollIntervalSeconds": 5,
  "marginSeconds": 60,
  "fallbackWaitHours": 5,
  "retryMessage": "Continue where you left off. The previous attempt was rate limited.",
  "customPatterns": ["my custom pattern"]
}
OptionDefaultDescription
maxRetries5Max retry attempts per rate-limit event
pollIntervalSeconds5How often to check the terminal (seconds)
marginSeconds60Extra wait after reset time (seconds)
fallbackWaitHours5Wait time if reset time can't be parsed
retryMessage"Continue where..."Message sent to Claude on retry
customPatterns[]Additional regex patterns to detect rate limits

All fields optional. Invalid values fall back to defaults automatically.

Launch wrapper

Set CLAUDE_AUTO_RETRY_LAUNCH_WRAPPER to a prefix command and it's prepended to each interactive session — useful for keeping a machine awake while Claude works, or any other per-process wrapper:

# macOS: don't sleep while a session runs
export CLAUDE_AUTO_RETRY_LAUNCH_WRAPPER="caffeinate -i"

Generic (not macOS-specific — e.g. nice, chrt … work too). Unset or blank spawns claude directly, unchanged.

Session lifetime

When claude exits cleanly inside the auto-created tmux session, the session now ends with it — tmux reaps it, nothing lingers. When the launcher exits non-zero (a crash), the pane falls through to your login shell so the scrollback survives for inspection. Two opt-outs:

# Always keep a shell in the pane after claude exits (the pre-0.7 behavior)
export CLAUDE_AUTO_RETRY_KEEP_SHELL=1

# Never create a tmux session (e.g. you're inside Zellij/screen and don't want nesting).
# Note: the monitor needs a tmux pane to watch, so this disables auto-retry for the run.
export CLAUDE_AUTO_RETRY_NO_TMUX=1

Environment forwarding

Your full shell environment reaches claude inside the tmux session via a 0600 snapshot file under ~/.claude-auto-retry/tmp/ that only the launcher reads (and deletes immediately). Nothing about your environment — names or values — ever appears on a tmux command line, so secrets can't surface in /proc/<pid>/cmdline.

Overload backoff

Separate from subscription rate limits, this fork also detects sustained API overload — Claude Code's own terminal API Error: <code> line for the retryable set (429 / 500 / 502 / 503 / 504 / 529, or an overloaded_error JSON body) — and retries on an exponential backoff instead of waiting for a usage reset. The two paths never collide; usage limits always take precedence.

Sustained only. Claude Code already retries transient 5xx/529 internally with its own backoff. This feature fires only when those internal retries are exhausted and a terminal error is left in the pane. It should rarely trigger.

Terminal vs. transient. Claude Code renders an in-progress retry as the parens form API Error (529 …) · Retrying in 5s · attempt 3/10, and the final exhausted error as the colon form API Error: 529 …. Detection requires the colon form and suppresses the · Retrying… / attempt n/m suffix, so the tool never interrupts Claude's own backoff.

Anchored, tail-only matching (why it won't fire on your code). Patterns are case-insensitive regexes matched against only the last 12 lines of the pane — never the full scrollback. They are anchored to Claude Code's API Error: <code> render, so a bare 503 in code you're editing (res.status(503)), a port number, a quoted log, or a status.claude.com link in a comment will not trip detection. The one residual: a live tail that literally contains API Error: 529 (e.g. editing this tool, or docs about Claude errors) will match — set "enabled": false while doing that. (Earlier versions matched bare status numbers across the whole capture, which injected spurious retries during ordinary web-dev sessions.) For a structured, ambiguity-free trigger see DESIGN-NOTES.md.

Configured under an overload block (shown with its defaults):

{
  "overload": {
    "enabled": true,
    "patterns": ["API Error:\\s*(429|500|502|503|504|529)\\b", "overloaded_error", "temporarily limiting requests"],
    "backoffSeconds": [30, 60, 120, 240, 300],
    "steadyStateSeconds": 300,
    "jitterPct": 15,
    "maxTotalWaitMinutes": 120,
    "retryMessage": "Continue where you left off.",
    "relaunchOnExit": false,
    "relaunchCommand": "claude --continue"
  }
}
OptionDefaultDescription
enabledtrueTurn the overload path on/off
patterns(see above)Case-insensitive regexes matching a terminal overload error in the pane tail (last 12 lines)
backoffSeconds[30,60,120,240,300]Wait before each retry; index i for attempt i
steadyStateSeconds300Wait once the backoffSeconds array is exhausted
jitterPct15±% jitter applied to every wait (clamped 0–100)
maxTotalWaitMinutes120Cumulative-wait cap — give up loudly past this
retryMessage"Continue where you left off."Sent to Claude on each retry
relaunchOnExitfalseSee the gating decision below
relaunchCommand"claude --continue"Command used by relaunchOnExit

The waits go 30 → 60 → 120 → 240 → 300 → 300 …, each with ±15% jitter, until the error clears (success) or the cumulative wait reaches maxTotalWaitMinutes (give up — the cap guards against hammering a genuinely-down endpoint or masking a real outage; check status.claude.com).

Event-driven detection (recommended — no scraping)

The scraper above is a heuristic over terminal output. For an exact, ambiguity-free trigger, install the StopFailure hook — Claude Code fires it precisely when a turn ends in an API error, with a typed error class:

claude-auto-retry install-hook                  # into $CLAUDE_CONFIG_DIR or ~/.claude
claude-auto-retry install-hook /path/to/config  # repeat per CLAUDE_CONFIG_DIR you use

This adds a StopFailure hook (matcher overloaded|server_error) that writes a pane-keyed marker the monitor consumes — no terminal scraping, so it cannot false-positive on code or scrollback. Sessions launched via the wrapper after installing the hook use it automatically; the first marker latches event mode and disables the scraper for that session. Sessions without the hook (or pre-install) fall back to the anchored scraper. Remove with uninstall-hook. See DESIGN-NOTES.md for the architecture.

Why not rate_limit? The event path handles only transient overloads (seconds-scale backoff). A rate_limit is the subscription session/usage limit — an hours-scale wait until a printed reset time — so it's handled by the usage-wait path above, not the overload path. Routing it through the hook would fire premature retries against a session that's simply out of quota.

Gating decision (alive-at-prompt vs exited-to-shell)

A transient API error in interactive Claude Code surfaces inline and leaves the process alive at its prompt — it does not exit to the shell. So the default, robust behavior reuses the existing usage-limit mechanism: only retry when the foreground process is claude/node and the session is idle, not working (the esc to interrupt footer is absent). Retrying mid-internal-retry would double-drive the session, so that case is deferred, never sent.

If a 500 ever does drop you to the shell, send-keys is correctly blocked by the foreground check (it never types into bash), and the tool logs overload-exited-to-shell rather than masking it. Auto-relaunch is off by default — blindly typing claude --continue into a shell the user may be using is worse than surfacing the stall. Set relaunchOnExit: true (and adjust relaunchCommand) only if you actually observe shell-exits on overload.

Safeguard retry

A third failure mode, separate from usage limits and 5xx overloads: the model's safeguards flag your message and Claude Code can't respond. It renders like:

● API Error: Fable 5's safeguards flagged this message (…/legal/aup). They may flag
  safe, normal content as well. … Claude Code can't respond to this request with Fable 5.
  Double press esc to edit your last message, or try a different model with /model.

These flags are often false positives (the message says so) and semi-random, so an immediate re-send frequently clears them. When the tool sees this render at an idle prompt, it sends a short retry message (continue by default), waits a few seconds, and repeats — but only up to maxRetries times, then gives up loudly (logged) rather than looping. A sticky flag means the content/model combination is genuinely blocked; switch models with /model or rephrase.

Detection is tail-anchored (last 12 pane lines) like the overload path, and a match additionally requires the API Error render line nearby — so the phrases appearing in scrollback or in a conversation about safeguards won't trigger it.

Configured under a safeguard block (defaults shown):

{
  "safeguard": {
    "enabled": true,
    "patterns": ["safeguards flagged this message", "can't respond to this request with", "legal/aup"],
    "maxRetries": 3,
    "retryDelaySeconds": 8,
    "retryMessage": "continue"
  }
}
OptionDefaultDescription
enabledtrueTurn the safeguard-retry path on/off
patterns(see above)Case-insensitive regexes marking the safeguard render (matched in the pane tail, near an API Error line)
maxRetries3Re-send attempts before giving up — kept small; retrying a sticky flag won't help
retryDelaySeconds8Wait between re-sends
retryMessage"continue"Message sent to nudge past the flag

Usage limits always take precedence; the safeguard path only acts when Claude is idle (no esc to interrupt footer) and the foreground process is claude/node.

Interrupted-stream resume

Close your laptop lid while Claude is mid-answer and the work does not survive. Claude Code wraps the response body in a byte watchdog; when the bytes stop arriving it aborts the stream and finalizes whatever had already been printed, naming the cause:

⏺ API Error: Your computer went to sleep mid-response. The response above may be
  incomplete.

The turn is then over. The prompt returns idle and nothing resumes it, so the session sits there — potentially for hours — with a half-finished answer on screen. Claude Code retries by itself only while the response is still thinking-only; once real content has been yielded it declines to retry, which is exactly when this render appears. That is the gap this closes: seeing it at an idle prompt, the tool sends continue, bounded at maxRetries because a machine that just woke may not have its network back yet.

The same finalizer emits the render for a dropped connection, a stalled stream and a mid-response server error. All are the same truncated-turn state with the same remedy, so all are matched — sleeping is just the cause we can name.

Detection is anchored on the shape of the line, not its vocabulary: a real render begins with API Error:, behind at most Claude's message glyph. The "an API Error line nearby" rule the overload and safeguard paths use is deliberately not enough here — these sentences are ordinary English, so a session merely explaining them quotes the whole render, anchor included, mid-sentence. Prose carries it mid-line and your own typed line carries , so neither trips it.

Configured under a streamInterrupted block (defaults shown):

{
  "streamInterrupted": {
    "enabled": true,
    "patterns": ["went to sleep mid-response", "Connection lost mid-response", "…"],
    "maxRetries": 2,
    "retryDelaySeconds": 5,
    "retryMessage": "continue"
  }
}
OptionDefaultDescription
enabledtrueTurn the interrupted-stream path on/off
patterns(all 7 renders)Case-insensitive regexes, matched only against a line that begins with the API Error: render
maxRetries2Resume attempts before giving up loudly
retryDelaySeconds5Wait before resuming — lets the network settle after a wake
retryMessage"continue"Message sent to pick the work back up

Usage limits take precedence, and like the safeguard path this only acts when Claude is idle and the foreground process is claude/node.

Near-limit wrap-up nudge

At roughly 95% of the 5-hour window, Claude Code injects a checkpoint instruction into the model's context — finish the current step, then list up to three short bullets of the most impactful remaining work, don't start subagents or long-running work — and prints:

⏺ Approaching your 5-hour usage limit — Claude will wrap up the current step.

The model does exactly that and ends the turn. There is no limit banner (the limit has not been hit), the prompt returns idle, and nothing resumes the session — so an overnight run winds down at 95% and stays parked long after the window has reset. This is a server-side Claude Code behavior with no user-facing switch (it is feature-flagged, not a setting), so the tool handles the render instead.

Seeing the notice at an idle prompt, the tool sends one continue. The session then either finishes its work or runs into the real limit, where the usage wait takes over as usual. Unlike the retry families above this is not a bounded machine: the nudge renders as a user row under the notice, and a notice with a user row below it — yours or ours — belongs to a turn that has already been answered, so it is never nudged twice. The maxRetries cap only bounds the pathological case where the nudge never renders.

Detection is anchored on the shape of the line, like the interrupted-stream render: the notice begins its line, behind at most Claude's message glyph, so prose quoting it and your own typed copy don't trip it.

Configured under a nearLimitWrapUp block (defaults shown):

{
  "nearLimitWrapUp": {
    "enabled": true,
    "maxRetries": 3,
    "retryMessage": "continue"
  }
}

Set "enabled": false if

Files in the repo

Repository payload12 top-level entries
  • bin
  • launchd
  • src
  • systemd
  • test
  • .gitignore
  • CHANGELOG.md
  • DESIGN-NOTES.md
  • LICENSE
  • llms.txt
  • package.json
  • README.md

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More tools

JuliusBrussee/
caveman

🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman

105k
1 add
MemPalace/
mempalace

The best-benchmarked open-source AI memory system. And it's free.

59k
stablyai/
orca

Orca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.

66k

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

132k

Never stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors

64k
headroomlabs-ai/
headroom

Compress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.

71k