Skip to content

matalvernaz/claude-ha

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

claude-ha

High-availability wrapper for Claude Code. When one Anthropic account hits its usage or billing limit, claude-ha transparently rotates to the next account and resumes the same conversation with --resume <session-id> — no manual intervention.

How it works

  1. The wrapper launches Claude Code under the primary account and writes its PID to a per-process file.
  2. A StopFailure hook in settings.json watches for rate_limit or billing_error events from the API. When one fires, the hook runs claude-ha-kill, which signals the wrapped Claude Code process to exit.
  3. The wrapper detects the usage-limit signal in the session JSONL, picks up the session id, and relaunches Claude Code under the next account with --resume <session-id>. The conversation continues seamlessly.

A shell function on claude routes interactive use through the wrapper, so you never have to type claude-ha directly.

Single-account hosts work transparently: if only one config dir from the account list exists, the wrapper just execs Claude Code with no rotation overhead.

Prerequisites

  • Claude Code installed.
  • Two Anthropic accounts (e.g. a personal Pro plan and a Team plan), each logged in to a separate config directory:
    • ~/.claude — primary
    • ~/.claude-acct2 — secondary

To log in to the secondary account:

CLAUDE_CONFIG_DIR=~/.claude-acct2 claude

Follow the auth flow, then exit. One-time setup.

Installation

1. Install the scripts

mkdir -p ~/.local/bin
cp claude-ha claude-ha-kill ~/.local/bin/
chmod +x ~/.local/bin/claude-ha ~/.local/bin/claude-ha-kill

Make sure ~/.local/bin is on your PATH.

2. Wire up the hook

Merge the contents of settings.example.json into your existing ~/.claude/settings.json. The relevant block is:

{
  "hooks": {
    "StopFailure": [
      {
        "matcher": "rate_limit",
        "hooks": [
          { "type": "command", "command": "claude-ha-kill" }
        ]
      },
      {
        "matcher": "billing_error",
        "hooks": [
          { "type": "command", "command": "claude-ha-kill" }
        ]
      }
    ]
  }
}

The hook needs to be active in both account config dirs. The simplest way is to symlink:

mkdir -p ~/.claude-acct2
ln -sf ~/.claude/settings.json ~/.claude-acct2/settings.json

The hook is gated on the CLAUDE_HA_PID env var (set only by the wrapper), so plain claude invocations are unaffected.

3. Route claude through the wrapper

Add to your ~/.bashrc (or ~/.zshrc):

# Route `claude` through the HA wrapper.
# The function only exists in your interactive shell; scripts that call
# `claude` directly are unaffected (no recursion).
claude() { command claude-ha "$@"; }

# Optional helpers
alias claudep='claude -p'                                             # print mode
alias claude2='CLAUDE_CONFIG_DIR=$HOME/.claude-acct2 command claude'  # force account 2

Reload:

source ~/.bashrc

Configuration

Override defaults with environment variables:

Variable Default Purpose
CLAUDE_HA_ACCOUNTS $HOME/.claude:$HOME/.claude-acct2 Colon-separated config dirs in priority order
CLAUDE_BIN claude Path to the real Claude Code binary

Example — three accounts, primary first:

export CLAUDE_HA_ACCOUNTS="$HOME/.claude:$HOME/.claude-work:$HOME/.claude-team"

Verifying it works

Run claude as normal. If the primary account hits its limit mid-session you will see:

claude-ha: ~/.claude hit usage limit
claude-ha: resuming session <id> on .claude-acct2

The conversation picks up where it left off on the next account.

Files

File Purpose
claude-ha Main wrapper script. Iterates configured accounts, launches Claude Code, rotates on usage limit.
claude-ha-kill Hook helper. Reads the wrapper's PID file and signals the wrapped Claude Code process to exit.
settings.example.json The StopFailure hook block to merge into ~/.claude/settings.json.

Why a hook (not polling)

An earlier version polled session JSONL files every 2 seconds for usage-limit markers. The current implementation uses Claude Code's StopFailure hook, which fires immediately on a structured rate_limit or billing_error event from the API. Faster signal, no polling overhead, no false positives from conversational text mentioning "rate limit".

License

MIT

About

High-availability wrapper for Claude Code: rotates between Anthropic accounts on rate-limit, resumes sessions seamlessly

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages