Skip to content

ArchitectVS7/switch-ex

Repository files navigation

Switch-Ex Orchestrator

Automatic LLM provider switching with Git isolation. Keep coding even when rate limits hit by automatically rotating through configured providers (Claude, OpenRouter, Gemini, Groq, Ollama), preserving work through nested git branches.

What It Does

  • Automatic Provider Switching: Detects 429/quota errors and rotates through configured providers
  • Git Isolation: Creates nested branches (devdev-openrouterdev-gemini) to isolate work per provider
  • Test Integration: Optionally runs tests before switching to ensure code quality
  • Smart Notifications: Discord webhooks and handoff callbacks to resume sessions on new providers
  • Offline Fallback: Supports local Ollama models when network providers are down
  • Session Management: HTTP server for managing sessions, rollback, and merge operations

Quick Start

Prerequisites

  • Python 3.9+ - Required for orchestrator
  • Node.js 16+ - Required for UI and Electron app
  • Git 2.20+ - Required for branch management
  • API Keys - At least one LLM provider:

Installation

1. Clone and Install Dependencies

# Clone repository
git clone https://github.com/your-org/switch-ex.git
cd switch-ex

# Install Python orchestrator
pip install -e .
pip install -e ".[dev]"  # Include development tools

# Install UI dependencies (optional)
cd ui
npm install
cd ..

# Install Electron app dependencies (optional)
cd electron
npm install
cd ..

2. Configure Orchestrator

# Copy sample configuration
cp orchestrator/config/config.sample.yaml orchestrator/config/config.yaml

# Edit configuration (or use environment variables)
# Set your provider API keys and preferences

3. Set Environment Variables

Create a .env.local file (gitignored) or set environment variables:

# Required for notifications
export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."

# Provider API keys (at least one required)
export ANTHROPIC_API_KEY="sk-ant-..."       # Claude
export OPENROUTER_API_KEY="sk-or-..."      # OpenRouter
export GOOGLE_API_KEY="..."                # Gemini
export GROQ_API_KEY="gsk_..."              # Groq
export OLLAMA_HOST="http://localhost:11434"  # Ollama (optional)

# Optional webhooks
export ATTENTION_ISSUE_URL="..."           # Attention callback
export RESPONSE_ROUTER_URL="..."           # Handoff callback

Windows PowerShell:

$env:ANTHROPIC_API_KEY = "sk-ant-..."
$env:DISCORD_WEBHOOK_URL = "https://discord.com/api/webhooks/..."

4. Edit Configuration

Edit orchestrator/config/config.yaml:

providers:
  # Ordered tier list - will try in this order
  - name: claude
    enabled: true
    models:
      - id: claude-3-sonnet
        notes: primary

  - name: openrouter
    enabled: true
    models:
      - id: openrouter/mistralai/mistral-7b-instruct
        notes: free tier fallback

  - name: gemini
    enabled: true
    models:
      - id: gemini-2.5-flash
        notes: free tier

  - name: ollama
    enabled: true
    models:
      - id: gemma:2b
        notes: offline/local fallback

notifications:
  discord_webhook: "${DISCORD_WEBHOOK_URL}"
  callback_url: "${RESPONSE_ROUTER_URL:-}"
  attention_issue: false
  include_diffs: false

git:
  base_branch: dev
  branch_prefix: dev-
  commit_message: "auto: before switch to {provider}"
  push: true

tests:
  command: ""  # e.g., "pytest" or "npm test"
  block_on_fail: true

behavior:
  wait_mode: false
  offline_allowed: true

Running

Orchestrator Server

# Start HTTP server (default: localhost:8080)
python -m orchestrator.src.server

# Or with custom host/port
python -m orchestrator.src.server --host 0.0.0.0 --port 8080

# Or use the installed command
switch-ex-server --host 0.0.0.0 --port 8080

UI Dashboard (Optional)

cd ui
npm run dev    # Development server on http://localhost:3000
npm run build  # Production build

Electron Desktop App (Optional)

cd electron
npm run dev    # Development mode
npm run build  # Build UI and orchestrator
npm run dist   # Create distributable packages

Basic Usage

Once the orchestrator server is running:

  1. Start a coding session - The orchestrator monitors Claude Code or other LLM sessions
  2. Hit rate limit - When a provider hits a rate limit (HTTP 429)
  3. Auto-switch - Orchestrator:
    • Commits current work
    • Creates new branch: dev-<next-provider>
    • Switches to next enabled provider
    • Sends notifications
    • Resumes session
  4. Continue coding - Work continues on new provider/branch

Development

Running Tests

# Python orchestrator tests
pytest                          # All tests
pytest -v orchestrator/tests/test_switch_controller.py  # Specific file
pytest -m unit                  # Unit tests only
pytest -m integration           # Integration tests only
pytest --cov                    # With coverage

# UI tests
cd ui
npm run test                    # Vitest unit tests
npm run test:e2e                # Playwright E2E tests

Linting and Type Checking

# Python
ruff check orchestrator/
ruff format orchestrator/
mypy orchestrator/

# UI
cd ui
npm run lint

Building

# Build orchestrator executable (PyInstaller)
cd orchestrator
pyinstaller switch-ex-orchestrator.spec

# Build Electron app
cd electron
npm run build           # Build UI and orchestrator
npm run dist            # Create platform packages
npm run dist:win        # Windows only
npm run dist:mac        # macOS only
npm run dist:linux      # Linux only

Architecture

Components

  1. Python Orchestrator (orchestrator/) - Core switching logic, HTTP server, provider adapters
  2. Next.js UI (ui/) - Dashboard for monitoring sessions and configuring providers
  3. Electron App (electron/) - Desktop application wrapper (optional)

Directory Structure

switch-ex/
├── orchestrator/           # Python orchestrator backend
│   ├── src/
│   │   ├── adapters/      # Provider adapters (Claude, OpenRouter, etc.)
│   │   ├── controllers/   # Core logic (switching, sessions, git, notifications)
│   │   ├── monitor/       # Claude CLI monitor
│   │   ├── webhooks/      # Inbound webhook handlers
│   │   └── server.py      # HTTP server
│   ├── config/            # Configuration files
│   └── tests/             # Unit and integration tests
│
├── ui/                     # Next.js dashboard
│   ├── app/               # Next.js app router pages
│   ├── components/        # React components
│   ├── lib/               # Utilities and API client
│   └── tests/             # Vitest and Playwright tests
│
├── electron/               # Electron desktop app
│   ├── main.js            # Electron main process
│   ├── preload.js         # Preload script
│   ├── orchestrator-manager.js  # Orchestrator subprocess
│   └── first-run.js       # First-run setup wizard
│
├── scripts/                # Installation and utility scripts
│   ├── install.sh         # Unix installation
│   ├── install.ps1        # Windows installation
│   └── run-integration-tests.sh  # Test runner
│
└── docs/                   # Documentation

How It Works

  1. Provider Tier System: Providers are ordered by priority (configured in config.yaml)
  2. Rate Limit Detection: Adapters detect HTTP 429 errors from provider APIs
  3. Nested Branching: Each provider switch creates a new branch:
    • Start: dev
    • First switch: dev → dev-openrouter
    • Second switch: dev-openrouter → dev-openrouter-gemini
  4. Session State: Persisted to .switch-ex-sessions/ for recovery
  5. Rollback/Merge: Manual operations available via API to manage branch hierarchy

Configuration

Provider Configuration

Each provider in config.yaml can be configured with:

  • name: Provider identifier (claude, openrouter, gemini, groq, ollama)
  • enabled: Whether to use this provider in rotation
  • models: List of models to use
    • id: Model identifier for the provider API
    • notes: Optional notes

Git Configuration

  • base_branch: Starting branch (default: dev)
  • branch_prefix: Prefix for provider branches (default: dev-)
  • commit_message: Template for auto-commits (can use {provider})
  • push: Auto-push branches to remote (default: true)

Notification Configuration

  • discord_webhook: Discord webhook URL for notifications
  • callback_url: Handoff callback URL for resuming sessions
  • attention_issue: Enable attention issue creation (default: false)
  • attention_issue_url: URL for attention webhook
  • include_diffs: Include code diffs in notifications (default: false, not recommended for security)

Test Configuration

  • command: Test command to run before switching (e.g., pytest, npm test)
  • block_on_fail: Block switch if tests fail (default: true)

HTTP API

The orchestrator exposes an HTTP API (default port 8080):

Session Management

  • GET /health - Health check
  • GET /sessions - List all sessions
  • GET /session/{id} - Get session details
  • POST /session/{id}/restart - Restart session with specified provider

Git Operations

  • POST /session/{id}/rollback - Rollback to parent branch
  • POST /session/{id}/merge - Merge current branch to parent

Human Decision Points

  • GET /decisions - List pending decisions
  • POST /decision/request - Create decision request
  • POST /decision/{id}/respond - Respond to decision

Webhooks

  • POST /webhook/callback - Receive session callbacks
  • POST /webhook/human-decision - Receive human decision responses

Server-Sent Events

  • GET /events - Subscribe to real-time events (session start, provider switch, etc.)

Notifications

Discord Webhook

Sends notifications on:

  • Provider switch (with reason, e.g., "rate limit")
  • Session start/stop
  • Errors

Payload includes:

  • session_id
  • provider (current and next)
  • branch (current and next)
  • event (switch, start, stop, error)
  • severity (info, warning, error)

Security Note: Does NOT include code diffs or secrets by default.

Handoff Callback

POST to callback_url when provider switches, allowing external systems to resume sessions:

{
  "session_id": "abc123",
  "provider": "openrouter",
  "branch": "dev-openrouter",
  "event": "switch_complete"
}

Advanced Usage

Programmatic API

from orchestrator.src.main import run

# Run orchestrator programmatically
result = run(
    messages=[{"role": "user", "content": "Hello"}],
    session_id="my-session",
    provider="claude"
)

Custom Adapters

Create custom provider adapters by extending BaseAdapter:

from orchestrator.src.adapters.base import BaseAdapter, ProviderLimitError

class MyAdapter(BaseAdapter):
    def send_message(self, messages, model):
        # Implementation
        # Raise ProviderLimitError on rate limits
        pass

Register in orchestrator/src/adapters/__init__.py.

Git Hooks

Pre-commit and pre-push hooks are available:

# Pre-commit: Compile check
python -m compileall orchestrator

# Pre-push: Compile and test
python -m compileall orchestrator && pytest

Troubleshooting

Orchestrator won't start

# Check port availability
lsof -i :8080  # macOS/Linux
netstat -ano | findstr :8080  # Windows

# Check logs
tail -f logs/orchestrator.log  # If logging configured

Provider switches not working

  1. Check API keys: Verify environment variables are set
  2. Check provider config: Ensure providers are enabled in config.yaml
  3. Check rate limits: Verify you have quota with the provider
  4. Check git: Ensure git is configured (git config user.name, git config user.email)

Tests failing

# Run specific test
pytest -v orchestrator/tests/test_switch_controller.py::test_name

# Check test output
pytest -s  # Show print statements

# Debug test
pytest --pdb  # Drop into debugger on failure

Electron app won't launch

# Check verification
cd electron
node verify-install.js

# Check logs
# Windows: %APPDATA%\switch-ex\logs
# macOS: ~/Library/Logs/Switch-Ex
# Linux: ~/.config/switch-ex/logs

Documentation

Installation Scripts

Platform-specific installation scripts are available in scripts/:

Windows:

.\scripts\install.ps1 -CreateShortcut -RunAfterInstall

macOS/Linux:

chmod +x scripts/install.sh
./scripts/install.sh

See scripts/README.md for detailed usage.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make changes with tests
  4. Run linting and tests
  5. Submit pull request

License

MIT License - see LICENSE file

Support

  • GitHub Issues: Bug reports and feature requests
  • Documentation: See docs/ directory
  • Claude Code: See CLAUDE.md for AI-assisted development

Roadmap

See FURTHER-DEVELOPMENT.md for planned features and enhancements.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •