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:

  • listTmuxPanes enumerates all active tmux sessions and their pane IDs
  • capturePaneContent retrieves the last N lines from each pane for analysis
  • analyzePaneContent flags 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 writePidFile and removePidFile utilities manage the daemon’s PID for clean shutdowns via SIGTERM

The Auto-Resume Workflow

The daemon follows a precise state machine to ensure it resumes sessions exactly once per rate-limit cycle:

  1. Daemon initialization: startDaemon() forks a detached Node process that imports pollLoopWithConfigFile from the compiled daemon module
  2. Status polling: Every interval, the loop calls checkRateLimitStatus() to assess API quotas
  3. Block detection: When limits are active, shouldMonitorBlockedPanes returns true, triggering scanForBlockedPanes to populate state.blockedPanes with stalled tmux sessions
  4. Quota reset detection: When the next poll reports no active limits and state.blockedPanes contains entries, the daemon iterates over the list
  5. 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →