1aad1e0313
Auto-retry Claude Code sessions when hitting Anthropic subscription rate limits. Uses tmux monitoring + send-keys to detect rate limit messages, wait for reset, and send "continue" automatically. Zero dependencies, zero workflow change. - Shell wrapper intercepts `claude` command transparently - Background monitor polls tmux pane for rate limit patterns - Timezone-aware reset time parsing with DST safety - Safe send-keys with foreground process verification - --print mode: buffers output, retries cleanly for pipes - Config validation prevents bad values from causing crashes - 59 tests, 0 dependencies Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
300 lines
11 KiB
Markdown
300 lines
11 KiB
Markdown
# 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.**
|
|
|
|
[](https://www.npmjs.com/package/claude-auto-retry)
|
|
[](https://opensource.org/licenses/MIT)
|
|
[](https://nodejs.org)
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
```bash
|
|
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
|
|
- **`--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`
|
|
|
|
## Rate Limit Patterns Detected
|
|
|
|
The tool detects these real-world Claude Code messages:
|
|
|
|
| Pattern | Example |
|
|
|---------|---------|
|
|
| N-hour limit reached | `5-hour limit reached - resets 3pm (UTC)` |
|
|
| Usage limit | `Claude usage limit reached. Resets at 2pm` |
|
|
| Out of extra usage | `You're out of extra usage · resets 3pm` |
|
|
| Try again | `Please try again in 5 hours` |
|
|
| Hit your limit | `You've hit your limit · resets 3pm (Europe/Dublin)` |
|
|
| Rate limit | `Rate limit hit. Resets at 4pm` |
|
|
|
|
Custom patterns can be added via config for future message format changes.
|
|
|
|
## Configuration
|
|
|
|
Optional. Create `~/.claude-auto-retry.json`:
|
|
|
|
```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"]
|
|
}
|
|
```
|
|
|
|
| Option | Default | Description |
|
|
|--------|---------|-------------|
|
|
| `maxRetries` | `5` | Max retry attempts per rate-limit event |
|
|
| `pollIntervalSeconds` | `5` | How often to check the terminal (seconds) |
|
|
| `marginSeconds` | `60` | Extra wait after reset time (seconds) |
|
|
| `fallbackWaitHours` | `5` | Wait 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.
|
|
|
|
## CLI Commands
|
|
|
|
```bash
|
|
claude-auto-retry install # Install shell wrapper + tmux
|
|
claude-auto-retry uninstall # Remove shell wrapper
|
|
claude-auto-retry status # Show monitor activity + last log entries
|
|
claude-auto-retry logs # Tail today's log file in real-time
|
|
claude-auto-retry version # Print version
|
|
```
|
|
|
|
## Platform Support
|
|
|
|
### Operating Systems
|
|
|
|
| OS | tmux auto-install | Status |
|
|
|----|-------------------|--------|
|
|
| Ubuntu / Debian | `apt-get` | Fully supported |
|
|
| CentOS / RHEL / Fedora | `dnf` | Fully supported |
|
|
| Rocky Linux / Amazon Linux | `dnf` | Fully supported |
|
|
| macOS | `brew` | Fully supported |
|
|
| Arch Linux | `pacman` | Fully supported |
|
|
| Alpine | `apk` | Fully supported |
|
|
|
|
### Requirements
|
|
|
|
- **Node.js** >= 18
|
|
- **tmux** >= 2.1 (auto-installed if missing)
|
|
|
|
### Shell Support
|
|
|
|
| Shell | Status |
|
|
|-------|--------|
|
|
| bash | Full (auto-install to `~/.bashrc`) |
|
|
| zsh | Full (auto-install to `~/.zshrc`) |
|
|
| fish | Manual setup (instructions printed on `install`) |
|
|
|
|
## `--print` Mode
|
|
|
|
For scripted/piped usage (`claude -p "..." | jq`), the tool:
|
|
|
|
1. Buffers all output (nothing goes to stdout until done)
|
|
2. If rate-limited: discards partial output, waits, re-executes with same args
|
|
3. Consumer receives a single clean response
|
|
|
|
```bash
|
|
# This just works — retries transparently if rate-limited
|
|
claude -p "Generate a JSON schema" | jq .
|
|
```
|
|
|
|
## Logging
|
|
|
|
Logs are written to `~/.claude-auto-retry/logs/YYYY-MM-DD.log`:
|
|
|
|
```
|
|
[2026-03-18 15:00:05] [INFO] Monitor started for pane %3 (claude PID: 12345)
|
|
[2026-03-18 15:32:10] [INFO] Rate limit detected: "5-hour limit reached - resets 3pm". Waiting 3547s...
|
|
[2026-03-18 16:01:10] [INFO] Sent retry message (attempt 1)
|
|
```
|
|
|
|
Logs rotate daily. Files older than 7 days are cleaned automatically.
|
|
|
|
## Uninstall
|
|
|
|
```bash
|
|
claude-auto-retry uninstall
|
|
npm uninstall -g claude-auto-retry
|
|
```
|
|
|
|
This removes the shell function from your rc files. tmux is left installed.
|
|
|
|
## Known Limitations
|
|
|
|
1. **Retry message context** — The retry message is sent as plain text. If Claude was mid-confirmation or in a special input state, it may not interpret it as a continuation. You can customize the message via config.
|
|
|
|
2. **Node version lock** — The launcher path is resolved at install time. If you switch Node versions with nvm, re-run `claude-auto-retry install`.
|
|
|
|
3. **tmux required** — The tool needs tmux to monitor terminal output and inject keystrokes. It auto-installs if missing, but requires sudo for system package managers.
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Here's how to get started:
|
|
|
|
### Development Setup
|
|
|
|
```bash
|
|
git clone https://github.com/cheapestinference/claude-auto-retry.git
|
|
cd claude-auto-retry
|
|
npm test # Run all 59 tests
|
|
npm link # Install locally for testing
|
|
```
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
claude-auto-retry/
|
|
├── bin/cli.js # CLI: install/uninstall/status/logs/version
|
|
├── src/
|
|
│ ├── patterns.js # Rate limit detection + ANSI stripping
|
|
│ ├── time-parser.js # Reset time parsing with timezone support
|
|
│ ├── config.js # Config loading + validation
|
|
│ ├── logger.js # File-based logging with rotation
|
|
│ ├── tmux.js # tmux command wrappers (execFile-based)
|
|
│ ├── monitor.js # Core monitoring loop + retry logic
|
|
│ ├── launcher.js # Process orchestration + signal forwarding
|
|
│ └── wrapper.sh # Shell function template
|
|
├── test/ # 59 tests across 7 test files
|
|
├── package.json
|
|
├── LICENSE
|
|
└── README.md
|
|
```
|
|
|
|
### Architecture Decisions
|
|
|
|
- **Zero dependencies** — only Node.js built-ins. Reduces supply chain risk and install size.
|
|
- **`execFile` over `exec`** — all child process calls use array-based args to prevent shell injection.
|
|
- **`stdio: 'inherit'`** — Claude gets the real TTY for full TUI support. The monitor reads pane content independently via `tmux capture-pane`.
|
|
- **Iterative DST correction** — timezone offset is computed via 3-iteration convergence loop, not a single-shot formula that breaks at DST boundaries.
|
|
- **Config validation** — invalid user config values fall back to safe defaults instead of producing NaN/undefined behavior.
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
npm test # All tests
|
|
node --test test/patterns.test.js # Single file
|
|
node --test --watch test/ # Watch mode
|
|
```
|
|
|
|
### Submitting Changes
|
|
|
|
1. Fork the repo
|
|
2. Create a feature branch (`git checkout -b feat/my-feature`)
|
|
3. Write tests first (TDD)
|
|
4. Make your changes
|
|
5. Ensure all tests pass (`npm test`)
|
|
6. Submit a Pull Request
|
|
|
|
### Areas for Contribution
|
|
|
|
- **New rate limit patterns** — If you see a Claude Code rate limit message that isn't detected, open an issue with the exact text.
|
|
- **Fish shell support** — Auto-install for fish shell (currently manual).
|
|
- **Windows support** — WSL works, but native Windows would need a different approach.
|
|
- **Notification integration** — Desktop/Slack notification when rate limit detected or when Claude resumes.
|
|
|
|
## Related Projects
|
|
|
|
- [claude-code-queue](https://github.com/JCSnap/claude-code-queue) — Queue-based task system for Claude Code with rate limit handling
|
|
- [opencode-claude-quota](https://github.com/nguyenngothuong/opencode-claude-quota) — Rate limit quota monitoring (display only)
|
|
|
|
## FAQ
|
|
|
|
**Q: Does this work with Claude Max/Pro/Team?**
|
|
A: Yes. It works with any Anthropic subscription that has usage-based rate limits.
|
|
|
|
**Q: Does it work outside of tmux?**
|
|
A: Yes. If you're not in tmux, it creates a tmux session transparently. You won't notice a difference.
|
|
|
|
**Q: What if I continue manually before the retry fires?**
|
|
A: The monitor checks if the rate limit is still visible before sending keys. If you already continued, it resets and keeps watching.
|
|
|
|
**Q: What if Claude exits while the monitor is waiting?**
|
|
A: The monitor checks the Claude process every 30 seconds during the wait. If Claude exits, the monitor shuts down cleanly.
|
|
|
|
**Q: Does it consume a lot of resources?**
|
|
A: No. `tmux capture-pane` is extremely lightweight. The monitor uses ~0% CPU at a 5-second polling interval.
|
|
|
|
**Q: Can it accidentally type into the wrong program?**
|
|
A: The monitor verifies the foreground process is `node` or `claude` before sending keys. If you've switched to vim, bash, or anything else, it skips the retry.
|
|
|
|
## License
|
|
|
|
MIT — see [LICENSE](LICENSE) for details.
|
|
|
|
---
|
|
|
|
Made with care by [CheapestInference](https://github.com/cheapestinference).
|