How the Rate Limit Wait Daemon Auto-Resumes Claude Code Sessions in oh-my-claudecode
The rate limit wait daemon monitors Anthropic API usage quotas every 60 seconds and automatically sends a "1" followed by Enter to blocked tmux panes once limits reset, resuming Claude Code sessions without manual intervention.
The oh-my-claudecode toolkit provides a background rate limit wait daemon that eliminates the need to manually restart Claude Code after hitting API quotas. By continuously polling the Anthropic usage API and detecting blocked tmux sessions, the daemon orchestrates seamless auto-resume functionality. This article explains the implementation details, from the polling loop in daemon.ts to the tmux detection logic that identifies stalled sessions.
Core Architecture Components
The daemon’s architecture consists of specialized modules that handle API monitoring, process detection, and secure state management.
The Polling Loop (pollLoop)
Located in src/features/rate-limit-wait/daemon.ts at lines 42–56, the pollLoop function executes the main control cycle. It runs repeatedly at a default interval of 60 seconds, recording system status and driving the auto-resume logic. This loop determines whether to scan for blocked panes based on current rate limit conditions.
Rate Limit Monitoring (checkRateLimitStatus)
The checkRateLimitStatus function in src/features/rate-limit-wait/rate-limit-monitor.ts (lines 15–71) queries the Anthropic usage API via hud/usage-api.ts. It retrieves 5-hour, weekly, and monthly usage percentages, calculates the next reset time, and returns a boolean indicating whether any quota is exhausted. When the API returns a 429 status code, the function triggers degraded monitoring mode.
tmux Pane Detection (scanForBlockedPanes)
The detection engine resides in src/features/rate-limit-wait/tmux-detector.ts (lines 71–138) and comprises three coordinated functions:
listTmuxPanesenumerates all active tmux sessions and their pane IDscapturePaneContentretrieves the last N lines from each pane for analysisanalyzePaneContentflags a pane as blocked when it detects Claude Code patterns, rate-limit-related phrases, and a prompt state indicating the process awaits user input
The system validates all pane IDs against the strict regex /^%\\d+$/ to prevent injection attacks.
Resume Sequence Execution (sendResumeSequence)
Once quotas reset, the daemon invokes sendResumeSequence (lines 258–314 in tmux-detector.ts) to resume blocked sessions. This function executes tmux send-keys to transmit the sequence 1 followed by Enter (the default "continue" choice), plus any optional custom text configured by the user. The operation targets specific pane IDs collected during the detection phase.
State Persistence and Security Hardening
The daemon maintains operational state in ~/.omc/state/rate-limit-daemon.json with strict 0600 file permissions, ensuring only the owner can read the PID and blocked pane lists. Security measures include:
- Environment sanitization: Only whitelisted environment variables pass to the child process via
createMinimalDaemonEnv - Config isolation: Settings serialize to a temporary JSON file that the daemon reads, preventing shell injection
- Process tracking: The
writePidFileandremovePidFileutilities manage the daemon’s PID for clean shutdowns viaSIGTERM
The Auto-Resume Workflow
The daemon follows a precise state machine to ensure it resumes sessions exactly once per rate-limit cycle:
- Daemon initialization:
startDaemon()forks a detached Node process that importspollLoopWithConfigFilefrom the compiled daemon module - Status polling: Every interval, the loop calls
checkRateLimitStatus()to assess API quotas - Block detection: When limits are active,
shouldMonitorBlockedPanesreturns true, triggeringscanForBlockedPanesto populatestate.blockedPaneswith stalled tmux sessions - Quota reset detection: When the next poll reports no active limits and
state.blockedPanescontains entries, the daemon iterates over the list - Resume execution: For each blocked pane, the daemon calls
sendResumeSequence(pane.id), records successful resumes, and clears the blocked pane list
If no tmux environment is available, the daemon logs a warning and enters a passive monitoring state.
Programmatic API and CLI Usage
Starting the Daemon from TypeScript
import { startDaemon, stopDaemon } from './features/rate-limit-wait/daemon.js';
// Start (will no-op if already running)
const resp = startDaemon();
if (resp.success) {
console.log(`Daemon started (PID ${resp.state?.pid})`);
} else {
console.warn(`Daemon not started: ${resp.message}`);
}
// Later, stop it gracefully
// stopDaemon();
Using the Command Line Interface
# Start the background watcher (daemon)
$ omc wait --start
Daemon started with PID 12345
# Check operational status
$ omc wait status
Rate-limit daemon is running (PID 12345)
# Stop auto-resume functionality
$ omc wait --stop
Daemon stopped
Manual Resume Triggering
For edge cases requiring immediate intervention, the resume logic is exposed directly:
import { sendResumeSequence } from './features/rate-limit-wait/tmux-detector.js';
// Target a specific pane ID
const paneId = '%3';
if (sendResumeSequence(paneId)) {
console.log('Sent resume keys to pane', paneId);
} else {
console.error('Failed to send resume to pane', paneId);
}
Summary
- The rate limit wait daemon runs as a detached background process that polls the Anthropic API every 60 seconds via
pollLoop - Auto-resume triggers only when the daemon detects a transition from active rate limiting to available quota, ensuring sessions resume immediately upon reset
- tmux detection relies on content analysis of pane buffers to identify Claude Code sessions paused at rate-limit prompts
- The system implements security hardening through file permission restrictions (mode
0600), environment variable whitelisting, and regex validation of pane identifiers - Both programmatic APIs (
startDaemon,stopDaemon) and CLI commands (omc wait --start) provide flexible control over the daemon lifecycle
Frequently Asked Questions
How does the daemon know when Claude Code is waiting for a rate limit to reset?
The daemon uses scanForBlockedPanes in src/features/rate-limit-wait/tmux-detector.ts to capture the last several lines of each tmux pane. It analyzes this content for Claude Code-specific patterns combined with rate-limit-related phrases and a prompt indicating the process awaits user input. Only panes meeting all three criteria are flagged as blocked and added to the resume queue.
What specific keys does the daemon send to resume a session?
According to the source code in tmux-detector.ts, the sendResumeSequence function transmits the character 1 followed by an Enter keystroke (represented as C-m in tmux send-keys syntax). This corresponds to the default "continue" option presented by Claude Code when it pauses due to quota exhaustion. Users can optionally append custom text to this sequence via configuration.
Where does the daemon store its process state and blocked pane information?
The daemon persists operational data to ~/.omc/state/rate-limit-daemon.json with strict 0600 permissions, ensuring only the file owner can access the PID and blocked pane lists. Additionally, the daemon writes its process ID to a PID file for management by the stopDaemon function, which sends SIGTERM to cleanly terminate the background process.
Can the daemon run without tmux?
No, the auto-resume functionality requires a tmux environment. If the daemon starts and cannot detect tmux sessions, it logs a warning message and continues polling the API without attempting pane detection. The resume logic specifically depends on tmux send-keys to interact with Claude Code sessions, making tmux a hard dependency for the auto-resume feature.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →