Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@
"authentication"
],
"category": "security"
},
{
"name": "claude-switcher",
"source": "./plugins/claude-switcher",
"description": "Switch between multiple Claude Code accounts instantly by swapping credential profiles",
"version": "2.0.0",
"author": {
"name": "moukrea"
},
"homepage": "https://github.com/moukrea/claude-code-plugins",
"repository": "https://github.com/moukrea/claude-code-plugins",
"license": "MIT",
"keywords": [
"auth",
"account",
"switch",
"profile",
"credentials"
],
"category": "productivity"
}
]
}
3 changes: 1 addition & 2 deletions .github/scripts/validate-plugins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ echo "marketplace.json is valid."

echo "Validating plugin directories..."

for PLUGIN_DIR in plugins/*/; do
PLUGIN=$(basename "$PLUGIN_DIR")
for PLUGIN in $(jq -r '.plugins[].name' .claude-plugin/marketplace.json); do
echo " Checking plugin: $PLUGIN"

# Verify valid JSON
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ claude-code-plugins/
│ ├── release.yml # Auto-release on main
│ └── tag-release.yml # GitHub release creation
└── plugins/
├── claude-switcher/ # Account switching plugin
└── opaq/ # Credential security plugin
```

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Productivity and security plugins for [Claude Code](https://claude.ai/code).
| Plugin | Description |
|--------|-------------|
| [opaq](plugins/opaq/) | Secure credential access — use secrets in commands without ever exposing them |
| [claude-switcher](plugins/claude-switcher/) | Switch between multiple Claude Code accounts instantly by swapping credential profiles |

## Installation

Expand All @@ -22,6 +23,7 @@ Install plugins:

```
/plugin install opaq@moukrea-plugins
/plugin install claude-switcher@moukrea-plugins
```

### From a local clone
Expand Down
12 changes: 12 additions & 0 deletions plugins/claude-switcher/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "claude-switcher",
"version": "2.0.0",
"description": "Switch between multiple Claude Code accounts instantly by swapping credential profiles",
"author": {
"name": "Emeric Commenge"
},
"license": "MIT",
"keywords": ["auth", "account", "switch", "profile", "credentials"],
"hooks": "./hooks/hooks.json",
"commands": "./commands/"
}
140 changes: 140 additions & 0 deletions plugins/claude-switcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# claude-switcher

Claude Code plugin for switching between multiple Claude Max accounts. Auto-switches on rate limits and switches back at reset time.

## Why

If you have both a company Claude Max subscription (limited usage) and a personal one, switching accounts normally requires `claude auth logout` then `claude auth login` every time.

claude-switcher saves named profiles and restores them instantly -- zero network calls. Plus it auto-switches to your fallback account when you hit rate limits, and auto-switches back when the primary resets.

## Install

Register as a Claude Code plugin:

```bash
claude --plugin-dir /path/to/claude-switcher
```

Or add to `~/.claude/settings.json`:

```json
{
"plugins": ["/path/to/claude-switcher"]
}
```

**Requires**: bash 4.0+, [jq](https://jqlang.github.io/jq/download/)

## Quick Start

```bash
# Set up rate limit capture
./scripts/claude-switcher.sh setup-plugin

# Save your current account
./scripts/claude-switcher.sh save work

# Log in to the other account
claude auth logout && claude auth login

# Save that one too
./scripts/claude-switcher.sh save personal

# Configure auto-switching
./scripts/claude-switcher.sh auto-config enable
./scripts/claude-switcher.sh auto-config primary work
./scripts/claude-switcher.sh auto-config fallback personal
./scripts/claude-switcher.sh auto-config threshold 97
./scripts/claude-switcher.sh auto-config daily-reset 15:00 Europe/Paris
```

## Slash Commands

Once installed as a plugin, use these in Claude Code sessions:

| Command | Description |
|---------|-------------|
| `/switch <name>` | Switch to a profile |
| `/switch prev` | Switch to previous profile |
| `/profiles` | List all profiles |
| `/limit-hit` | Manually trigger fallback (rate limit) |
| `/auto-config` | View/edit auto-switch configuration |
| `/setup` | Set up rate limit capture in status line |

## Auto-Switch

When enabled, claude-switcher automatically manages account switching:

1. **Preemptive**: A `PostToolUse` hook reads real rate limit data (captured from the status line) and switches at a configurable threshold (default 97%) BEFORE hitting the actual limit
2. **On rate limit**: A `StopFailure` hook detects actual rate limit errors as a safety net
3. **On reset**: A `SessionStart` hook checks if the primary account's limit has reset and switches back
4. **Manual**: Use `/limit-hit` if auto-detection misses a rate limit

### Configuration

```bash
./scripts/claude-switcher.sh auto-config show # View config
./scripts/claude-switcher.sh setup-plugin # Inject rate limit capture into status line
./scripts/claude-switcher.sh auto-config enable # Enable
./scripts/claude-switcher.sh auto-config primary work # Set primary
./scripts/claude-switcher.sh auto-config fallback personal # Add fallback
./scripts/claude-switcher.sh auto-config threshold 97 # Switch at 97% real usage
./scripts/claude-switcher.sh auto-config daily-reset 15:00 Europe/Paris
./scripts/claude-switcher.sh auto-config weekly-reset Monday 10:00
./scripts/claude-switcher.sh auto-config reset-state # Clear state
```

## CLI Reference

All commands are also available via the script directly:

```
./scripts/claude-switcher.sh <command> [options]

Profile Management:
save <name> [--force] Save current auth as a profile
use <name> Switch to a profile
prev, - Switch to previous profile
list List profiles
show <name> Profile details
status Active profile + auto-switch state
delete <name> Delete a profile
rename <old> <new> Rename a profile
setup Interactive first-time setup

Auto-Switch:
auto-config [subcmd] Configure auto-switching
limit-hit Manually trigger fallback

Other:
uninstall Remove plugin registration
help Show help
version Show version
```

## How It Works

**Profile switching**: Copies OAuth tokens from `~/.claude-switcher/profiles/<name>/` back to `~/.claude/.credentials.json` and surgically updates only the `oauthAccount` key in `~/.claude.json`.

**Rate limit capture**: The `/setup` command injects a snippet into your Claude Code status line script. The status line receives real rate limit data from Claude Code (five_hour and seven_day percentages) on every refresh, and the snippet writes this to `~/.claude-switcher/rate-limits.json`.

**Preemptive switching**: The `PostToolUse` hook (async, non-blocking) reads the captured rate limit data after every tool call. When either the 5-hour or 7-day usage exceeds the configured threshold, it switches to the fallback before hitting the actual limit.

**Rate limit detection**: The `StopFailure` hook serves as a safety net. It analyzes errors for rate-limit patterns and switches if the preemptive system missed.

**Time-based switch-back**: The `SessionStart` hook checks if the configured daily reset time has passed. If the primary account was rate-limited but has since reset, it auto-switches back.

## Security

- Profile directories: `chmod 700`
- Credential files: `chmod 600`
- No credentials sent over the network
- Atomic writes (temp file + mv)
- Backup state preserved before every switch

## Uninstall

```bash
./scripts/claude-switcher.sh uninstall
```
37 changes: 37 additions & 0 deletions plugins/claude-switcher/commands/auto-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: auto-config
description: "View or configure auto-switching settings for Claude Code account profiles. Use when the user asks about auto-switch configuration, wants to change primary/fallback profiles, or adjust reset times."
argument-hint: "[show | enable | disable | primary <name> | fallback <name> | threshold <pct> | daily-reset <HH:MM> [tz] | weekly-reset <day> [HH:MM] | reset-state]"
allowed-tools: Bash
---

# Auto-Switch Configuration

Manage automatic profile switching configuration.

If no argument provided, show the current config:
```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh auto-config show
```

If argument provided, run the matching subcommand:
```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh auto-config $ARGUMENTS
```

After showing config, explain what each setting means:
- **Primary**: The preferred account, consumed first
- **Fallbacks**: Accounts to switch to when primary hits rate limits
- **Daily reset**: When the primary account's daily session limit resets (from the Claude usage screen)
- **Weekly reset**: When the weekly limit resets

If the user is setting up auto-switch for the first time, guide them through:
1. Run `/setup` first to enable rate limit capture in the status line
2. Enable: `auto-config enable`
3. Set primary: `auto-config primary work`
4. Add fallback: `auto-config fallback personal`
5. Set threshold: `auto-config threshold 97` (switch at 97% real usage)
6. Set daily reset: `auto-config daily-reset 15:00 Europe/Paris`
7. Set weekly reset: `auto-config weekly-reset Monday 10:00`

The **threshold** controls preemptive switching. The PostToolUse hook reads real rate limit data (five_hour and seven_day percentages captured by the status line) and switches to the fallback when either exceeds the threshold.
21 changes: 21 additions & 0 deletions plugins/claude-switcher/commands/limit-hit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: limit-hit
description: "Manually trigger a rate limit fallback switch. Use when Claude Code hits a rate limit and auto-detection didn't catch it, or when the user says they've hit their limit."
allowed-tools: Bash
---

# Rate Limit Hit -- Manual Fallback

The user is reporting they've hit a rate limit. Trigger the fallback switch:

```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh limit-hit
```

After running:
1. Tell the user which profile they've been switched to
2. Explain that the tool will auto-switch back to the primary profile at the configured reset time
3. If it fails (auto-switch not enabled or no fallback configured), help them set it up:
- `$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh auto-config enable`
- `$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh auto-config primary <name>`
- `$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh auto-config fallback <name>`
20 changes: 20 additions & 0 deletions plugins/claude-switcher/commands/profiles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: profiles
description: "List all saved Claude Code account profiles and show which one is active. Use when the user asks about their accounts, profiles, or wants to see available options."
allowed-tools: Bash
---

# List Claude Code Account Profiles

Show the user their saved profiles:

```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh list
```

Present the output to the user. The active profile is marked with `*`.

If the user wants more details about a specific profile:
```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh show <profile-name>
```
21 changes: 21 additions & 0 deletions plugins/claude-switcher/commands/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: setup
description: "Set up claude-switcher rate limit capture by injecting a snippet into the Claude Code status line script. Use when the user first installs the plugin or asks to configure rate limit tracking."
allowed-tools: Bash
---

# Set Up Claude-Switcher

Run the setup command to configure rate limit capture:

```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh setup-plugin
```

This injects a small snippet into the user's Claude Code status line script that captures real rate limit data (five_hour and seven_day percentages) to `~/.claude-switcher/rate-limits.json`. This data is then used by the auto-switch system to preemptively switch profiles before hitting rate limits.

After setup, guide the user through configuring auto-switch if not done already:
1. Save both profiles
2. Enable auto-switch
3. Set primary and fallback profiles
4. Set threshold percentage
26 changes: 26 additions & 0 deletions plugins/claude-switcher/commands/switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: switch
description: "Switch to a different Claude Code account profile. Use when the user wants to change which Claude subscription they're using (e.g., switching between work and personal accounts)."
argument-hint: "[profile-name | prev]"
allowed-tools: Bash
---

# Switch Claude Code Account Profile

The user wants to switch their Claude Code account. Run the switcher command:

```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh use $ARGUMENTS
```

After switching:
1. Report the result to the user (which profile is now active, the email and subscription type)
2. Note that the switch takes effect for NEW Claude Code sessions -- the current session may still use the previous account's tokens until restarted
3. If the user ran `/switch prev` or `/switch -`, explain they switched back to their previous profile

If no argument was provided, show the available profiles:
```bash
$CLAUDE_PLUGIN_ROOT/scripts/claude-switcher.sh list
```

Then ask the user which profile they want to switch to.
20 changes: 20 additions & 0 deletions plugins/claude-switcher/hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"hooks": [
{
"event": "SessionStart",
"type": "command",
"command": "$CLAUDE_PLUGIN_ROOT/scripts/session-start.sh"
},
{
"event": "PostToolUse",
"type": "command",
"command": "$CLAUDE_PLUGIN_ROOT/scripts/on-post-tool-use.sh",
"async": true
},
{
"event": "StopFailure",
"type": "command",
"command": "$CLAUDE_PLUGIN_ROOT/scripts/on-stop-failure.sh"
}
]
}
27 changes: 27 additions & 0 deletions plugins/claude-switcher/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
set -e

echo "=== Prerequisites ==="
if ! command -v jq >/dev/null 2>&1; then
echo "error: jq required but not installed"
if command -v apt >/dev/null 2>&1; then
echo " Install: sudo apt install jq"
elif command -v brew >/dev/null 2>&1; then
echo " Install: brew install jq"
elif command -v dnf >/dev/null 2>&1; then
echo " Install: sudo dnf install jq"
elif command -v pacman >/dev/null 2>&1; then
echo " Install: sudo pacman -S jq"
fi
exit 1
fi
echo "jq $(jq --version)"

echo "=== Smoke test ==="
if [ -f scripts/claude-switcher.sh ]; then
sh scripts/claude-switcher.sh --help >/dev/null 2>&1 && echo "CLI: ok" || echo "CLI: not ready yet"
else
echo "CLI: not built yet"
fi

echo "=== Ready ==="
Loading
Loading