01 Overview
Second Wind is a single-file Python CLI orchestrator that runs Claude Code in one tmux session per repository. It watches the 5-hour account-level usage limit, parses the reset time from the pane output, waits for the reset clock to advance, and types the resume message into every paused session automatically. The watcher runs in its own detached tmux session so it survives terminal restarts, and a live localhost dashboard lets you monitor all sessions, expand them into modals to read full scrollback, send messages, or manually resume. No external dependencies — just Python 3.9+, tmux, and the Claude Code CLI.
02 Problem & why it's needed
Running long Claude Code sessions unattended across multiple repos hits the 5-hour account-level usage limit at unpredictable times, pausing all sessions. Manually resuming every repo after waiting for the reset is tedious and requires babysitting the clock. No tool exists to watch for the limit message, parse the reset time, wait it out, and sweep a resume nudge across all paused sessions automatically.
03 Install
One-liner (recommended)
curl -fsSL https://raw.githubusercontent.com/abhijitbansal/claude-skills/main/tools/second-wind/install.sh | shexec $SHELLPlaces wind in ~/.wind with a shim at ~/.wind/bin/wind, adds to PATH with your consent, then verify with wind --help
From clone
cd ~/projects/claude-skillsbash tools/second-wind/install.shexec $SHELLInstalls from the local repo if already cloned
Claude Code plugin (optional)
/plugin marketplace add abhijitbansal/claude-skills/plugin install second-wind@claude-skillsTeaches Claude Code to guide you through wind setup via the /second-wind command
04 Usability guide
Every capability, how to invoke it, and a concrete example.
wind init — create or edit your config
An interactive wizard scans your git repos (the scanned roots are persisted as scan_roots so you can add more repos later), lets you pick which ones wind should manage, choose a global permission preset, then either configure each repo individually or apply the global preset + defaults to every selected repo in a single choice (no per-repo click-through). Presets are acceptEdits, plan, default, custom, and auto — where auto (--permission-mode bypassPermissions) accepts everything and, as of v2.1, is the shipped default for a fresh config; that's the same risk class as --dangerously-skip-permissions, so pick acceptEdits/plan/default to dial autonomy back down. It also selects an agent (claude or copilot) and writes the config to ~/.wind/config.json. Pass --defaults to get a non-interactive starter file. The wizard also offers to open prompt files in your editor immediately after writing the config.
wind initwind init --defaultswind prompt <repo> — author first prompts
Creates or edits a prompt file in $EDITOR for a single repo. By convention the file lives at ~/.wind/prompts/<repo>.md. The prompt is sent verbatim to the repo's session on the next wind up. For one-liners, give a repo an inline prompt string in the config instead — it wins over prompt_file. The editor is read from --editor flag, $EDITOR env var, then defaults to vi or nano.
wind prompt myrepowind prompt myrepo --editor 'code --wait'wind add <path> — bring a repo under management, no re-init
Adds a git repo to your existing config without re-running the wizard: it validates the path, appends a {name, path} entry that inherits the global permission preset, launches its tmux session immediately, and refreshes the watcher so the new session is auto-resumed. It deliberately writes {name, path} only — no claude_args/agent/prompt from the CLI — so it opens no new execution surface. Requires a prior wind init.
wind add ~/code/newrepowind up — start sessions and the watcher
Starts one tmux session per repo in parallel, launches the agent in each (claude or copilot per config), sends each repo's initial prompt, and auto-spawns the watcher in its own detached <prefix>-watcher tmux session. The watcher stays alive even if you close your terminal, and on macOS it self-caffeinates to keep the machine awake. Pass --no-watch to skip the watcher; run wind watch yourself in the foreground or wind watch --detach to spawn it by hand.
wind upwind up --no-watchwind watch --detachwind status — check each session and reset time
Prints per-session state (running, paused, limit detected, etc.) plus the next account-level reset time. Shows which repos are watched (claude) vs shown-only (copilot) and the countdown until the limit resets.
wind statuswind resume — manually nudge all sessions
Types the resume_message (default: 'continue') into every paused session immediately, without waiting for the limit to reset. Useful if you've checked in, read a session, and want to kick it forward by hand.
wind resumewind watch — run the watcher in foreground
Starts the watcher loop, polling every pane every 30 seconds for the limit message, keeping a single account-level reset clock, and sweeping the resume message across all paused sessions after the reset. Runs in the foreground (pass --detach to re-exec it into a detached <prefix>-watcher tmux session instead). On macOS it self-caffeinates by default (respects the caffeinate config key).
wind watchwind watch --detachwind dash — live localhost dashboard
Serves a live dashboard at http://127.0.0.1:8787 (or a custom --port). Shows one card per session: state pill, reset countdown, and the last 30 lines of each pane in full color. Click a card to expand it into a full-height modal with up to 1000 lines of colorized scrollback and a roomy send box — easier to read on a small screen. The modal's attach button copies the tmux attach command to your clipboard. Actions: resume all, send a message to any session, kill a session, or use the + add repo button to bring a scanned-but-unmanaged repo (found under your persisted scan_roots) under management and launch it live. Localhost-only; every action requires a per-run CSRF token, so other sites cannot reach your sessions. Pass --no-browser to skip auto-opening.
wind dashwind dash --port 9000wind dash --no-browsertmux attach — jump into a live session
Attach to a running repo's tmux session with full Claude Code TUI, autocomplete, history, and keybindings. Useful when the dashboard send box or a modal isn't enough. Detach with Ctrl-b d.
tmux attach -t wind-myrepowind down — kill all wind sessions
Kills every wind tmux session (including the watcher) without saving pane contents. Always confirm with the user before running this on their behalf — it's destructive.
wind downConfiguration essentials
Wind reads ./second-wind.json, then ~/.wind/config.json, then ~/.config/second-wind/config.json (legacy). Config keys: session_prefix (default: wind; tmux session names are <prefix>-<repo>), agent (default: claude; presets are claude or copilot), claude_cmd and claude_args (launch command + args; overridable per repo — the global permission preset; the auto preset --permission-mode bypassPermissions is the shipped default for a fresh config), scan_roots (directories the wizard scanned, persisted so wind add and the dashboard's + add repo can offer more repos without re-init), resume_message (text typed after limit reset; default: continue), resume_buffer_seconds (wait after reset before resume; default: 120), poll_interval_seconds (how often watcher captures panes; default: 30), resume_cooldown_seconds (ignore stale limit text in scrollback after resume; default: 600), startup_delay_seconds (wait before sending first prompt; default: 8), capture_lines (trailing pane lines to scan; default: 120), caffeinate (keep macOS awake during watch; default: true), ntfy_url (optional ntfy.sh topic for notifications), limit_patterns (extra regexes for limit detection). Per-repo: name, path, optional agent override, optional prompt_file or inline prompt string, optional claude_args override.
05 How it works under the hood
Account-level reset clock
The 5-hour usage limit is account-wide: all sessions pause and reset together. Wind keeps a single reset clock (the latest reset time detected across all panes) instead of per-repo clocks. When any session detects the limit message, the watcher records the parsed reset time and schedules a resume sweep for after that time plus a configurable buffer (default: 120 seconds).
Polling and pane capture
The watcher polls every tmux pane every 30 seconds (configurable via poll_interval_seconds), capturing the trailing lines of each pane (120 by default, configurable via capture_lines). Each capture is scanned against a list of limit-detection regexes to find the reset time.
Limit detection via regex
Built-in patterns cover the formats Claude Code emits: Claude AI usage limit reached|<epoch> (headless/print mode), 5-hour limit reached ∙ resets 3am (interactive UI), usage limit...resets at 8pm or try again at 6:15pm (variants). Clock times like '3am' are interpreted as the next local occurrence. If a pattern matches but time parsing fails, the watcher falls back to a conservative 1-hour retry. Custom regexes added to limit_patterns in the config take precedence over built-ins, so you can adapt to format changes between Claude Code versions.
The resume sweep
When the reset time arrives plus the buffer, the watcher types resume_message into every paused session's tmux pane. After resume, a cooldown period (600 seconds by default, configurable via resume_cooldown_seconds) ignores any stale limit text still visible in the scrollback so the watcher doesn't trigger again on old messages.
Watcher lifecycle and detachment
wind up auto-spawns the watcher in a detached <prefix>-watcher tmux session (one per machine) unless you pass --no-watch. That session stays alive even if you close your terminal or restart your editor. On macOS, the watcher calls caffeinate -dims to keep the machine awake. wind down reaps the watcher along with all repo sessions. You can run wind watch in the foreground to watch logs, or wind watch --detach to spawn the session by hand.
Agents: Claude vs. Copilot
The agent key (top-level default, overridable per repo) selects a preset. claude is watched: the watcher scans its panes for limit messages and auto-resumes on reset. copilot is launched with the copilot CLI and shown in the dashboard, but the watcher skips it entirely — never scans its panes, never auto-resumes — so you handle Copilot's rate limits yourself. You can still send Copilot sessions initial prompts on wind up and send them messages via the dashboard; a manual wind resume nudges it with its preset message.
Dashboard security and CSRF
The dashboard binds 127.0.0.1 only. /api/status serves a 30-line pane tail without authentication (reachable only from localhost; cross-origin reads are blocked by browser SOP). /api/pane (the modal's full-scrollback endpoint) and every write action (/api/send, /api/kill, /api/resume) require a per-run CSRF token generated with secrets.token_hex(16) at startup and embedded in the served page, passed via X-Wind-Token header. The handler enforces a Host-header allowlist to block DNS-rebinding attacks. Pane text is stripped of unsafe ANSI codes and rendered via textContent/createTextNode, never innerHTML.
Atomic config and state writes
Config and state files are written atomically: written to a temp file in the same directory, fsynced, then os.replace'd into place. A crash mid-write or a concurrent watcher/dashboard read never sees a truncated JSON file. Config keeps 0644 mode; state keeps 0600.
Prompt and editor handling
wind prompt never invokes a shell. The $EDITOR env var is parsed with shlex.split and exec'd as an argv list (no shell=True, no os.system). The first token is validated with shutil.which, and the repo-to-filename mapping is validated as a single path component, so names with /, .., or path separators are rejected to prevent traversal or injection.
Notifications (optional)
If ntfy_url is set to an http:// or https:// URL (validated at config load), the watcher POSTs a notification when the limit hits and when sessions resume. Works with ntfy.sh topics. Notifications carry only session counts and reset times — never repo content or secrets.
06 What's inside
Commands
CLI
Explore the other plugins
prompt-craft
Sharpen rough prompts into specs, suggest follow-up commands
ios-dev
Build iOS apps, screenshot remotely, release to App Store
core-workflow
Opinionated dev workflow: commit + share + team up
linear-pm
Linear issues → code, branches, PRs — autonomous end-to-end