Home/Features/Second Wind
CLI + plugin

Second Wind

Run Claude overnight; auto-resume after 5-hour limit resets.

Install → View source ↗
10
wind subcommands
1
slash command
0
runtime deps
2
OS tested

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

The friction

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.

Why it mattersEngineers need to run Claude overnight across many repositories for intensive refactoring, implementation, or analysis. Second Wind removes the babysitting burden by detecting the limit, waiting for the reset, and resuming every session in one sweep — so you can set it and sleep.

03 Install

One-liner (recommended)

curl -fsSL https://raw.githubusercontent.com/abhijitbansal/claude-skills/main/tools/second-wind/install.sh | sh
exec $SHELL

Places 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-skills
bash tools/second-wind/install.sh
exec $SHELL

Installs from the local repo if already cloned

Claude Code plugin (optional)

/plugin marketplace add abhijitbansal/claude-skills
/plugin install second-wind@claude-skills

Teaches 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 init
# or:
wind init --defaults

wind 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 myrepo
# or with custom editor:
wind 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/newrepo

wind 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 up
# or without auto-watcher:
wind up --no-watch
# then start watcher yourself:
wind watch --detach

wind 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 status

wind 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 resume

wind 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 watch
# or detached:
wind watch --detach

wind 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 dash
# or on a custom port:
wind dash --port 9000
# or without auto-opening:
wind dash --no-browser

tmux 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-myrepo
# (Ctrl-b d to detach)

wind 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 down

Configuration 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.

# ~/.wind/config.json or ./second-wind.json { "session_prefix": "wind", "agent": "claude", "claude_cmd": "claude", "claude_args": "", "resume_message": "continue", "ntfy_url": "", "repos": [ { "name": "api", "path": "~/code/api", "agent": "claude", "claude_args": "--permission-mode acceptEdits", "prompt_file": "~/.wind/prompts/api.md" }, { "name": "web", "path": "~/code/web", "prompt": "continue the refactor and run tests" } ] }

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

/second-windGuide the user through Second Wind setup (init → prompt → up → dash) and optionally run each step for them. Input: optional 'setup' to walk setup, or a question about wind. Confirms wind is installed first; if missing, points to install.sh.

CLI

wind initInteractive wizard: scans dirs (roots persisted as scan_roots), lets user pick repos, choose a global permission preset (auto/full-auto is the shipped default), then configure each repo or apply the global preset + defaults to all in one choice; pick agent (claude or copilot), write config. Pass --defaults for non-interactive starter file.
wind prompt <repo>Create/edit a repo's first-prompt file in $EDITOR (convention ~/.wind/prompts/<repo>.md; wires prompt_file into config); pass --editor to override $EDITOR
wind add <path>Add a git repo to the config ({name, path} only, inherits the global preset), launch its tmux session, and refresh the watcher — no re-init
wind upStart a tmux session per repo, launch agent, send initial prompt, auto-spawn watcher in detached <prefix>-watcher session (pass --no-watch to skip)
wind watchRun watcher loop in foreground (keep running; on macOS self-caffeinate); pass --detach to re-exec it into detached tmux session
wind statusPer-session state + next reset time
wind resumeManually nudge all sessions with resume message
wind downKill all wind sessions (and watcher); confirm with user before running destructively
wind dashServe live localhost dashboard (status, full-color pane tails, click-to-expand modal, resume/send/kill, + add repo from scanned candidates); pass --port to change port, --no-browser to skip auto-open
wind guidePrint the setup walkthrough (start here)

Explore the other plugins

Browse the full skills & tools catalog →