feat: claude-auto-retry v0.1.0
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>
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
# 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).
|
||||
Reference in New Issue
Block a user