Skip to content

Repository files navigation

sbfbl-router

Anthropic-style image-routing proxy for text-only LLMs. Routes image-bearing requests to a vision-capable model while forwarding text-only requests to the primary model.

Why

Some openrouter models (like z-ai/glm-5.2) are text-only. When Claude Code sends images — Playwright screenshots, pasted images, file attachments — the model can't process them and errors out. This proxy intercepts those requests, detects image content blocks, and routes them to a vision-capable model automatically.

Architecture

Claude Code ──(localhost:3456)──▶ Proxy (proxy.ts) ──(OpenRouter)──▶ Model
  • Text-only → passthrough to z-ai/glm-5.2
  • Image-bearing → routed to qwen/qwen3.6-27b (or your vision model of choice)

The proxy forwards the Authorization header — it never reads or stores the API key.

Requirements

  • Bun ≥1.2.0
  • OpenRouter API key

Installation

1. Clone & Install

git clone https://github.com/yourusername/sbfbl-router.git
cd sbfbl-router

2. Configure

Copy and edit the config:

cp config.example.json config.json

Edit config.json with your preferences:

{
  "port": 3456,
  "upstream": "https://openrouter.ai/api",
  "defaultModel": "z-ai/glm-5.2",
  "visionModel": "qwen/qwen3.6-27b"
}

3. Set API Key

Set the ANTHROPIC_AUTH_TOKEN environment variable:

# In your shell profile (~/.zshrc, ~/.bash_profile, etc.)
export ANTHROPIC_AUTH_TOKEN="sk-or-v1-your-key-here"

4. Install Claude Code Hook (Optional)

The proxy auto-starts via a Claude Code SessionStart hook. Install it:

# Creates/updates .claude/settings.json in your project
./scripts/install-hook.sh [your-project-dir]

5. Create System Daemon

On macOS, install the proxy as a login daemon:

# Creates a launchd plist to auto-start the proxy on login
./scripts/install-daemon.sh

This will create a launchd plist that:

  • Starts the proxy on login
  • Restarts it if it crashes
  • Logs output to ~/.cache/sbfbl-router/router.log

Uninstall the daemon:

./scripts/uninstall-daemon.sh

6. Configure Claude Code

Add the following to your .claude/settings.json:

{
  "env": {
    "ANTHROPIC_BASE_URL": "http://localhost:3456"
  }
}

Usage

CLI

bun run proxy.ts          # Run the proxy
bun run proxy.ts stop     # Stop the proxy
bun run proxy.ts status   # Check status
bun run proxy.ts logs     # View recent logs

As a Daemon

Once installed, the proxy runs automatically. To check its status:

bun run proxy.ts status
tail -f ~/.cache/sbfbl-router/router.log

API

The proxy implements the Anthropic Messages API v2023-06-01. It supports:

  • POST /v1/messages — Main endpoint (image-aware routing)
  • POST /v1/messages/count_tokens — Token counting (passthrough)
  • GET /__health — Health check

Claude Code Hooks

The proxy includes a SessionStart hook that ensures the proxy is running before any tool calls. The hook:

  1. Checks if the proxy process is running
  2. Verifies the health endpoint is accessible
  3. Starts the proxy with a health check timeout if needed

The hook is installed in .claude/settings.json and runs via bash scripts/install-hook.sh.

Claude Code Commands

bun run proxy.ts install  # Install the proxy and config
bun run proxy.ts start    # Start the proxy
bun run proxy.ts stop     # Stop the proxy
bun run proxy.ts restart  # Restart the proxy
bun run proxy.ts status   # Check status
bun run proxy.ts logs     # Show logs

Files

.
├── config.example.json    # Example configuration
├── config.js              # Configuration (gitignored, for your settings)
├── proxy.ts               # The routing proxy (Bun+Hono)
├── scripts/
│   ├── install-hook.sh    # Claude Code hook installer
│   ├── install-daemon.sh  # macOS launchd daemon installer
│   └── pre-check.sh       # SessionStart hook script (auto-starts proxy)
├── LICENSE
├── package.json           # Bun package
├── tsconfig.json          # TypeScript config
└── README.md

License

MIT License

Architecture

This proxy is minimal and focused:

  • No dependencies beyond Bun's built-in HTTP server
  • No state — request routing is stateless
  • No secrets — API keys passed through, never stored
  • TypeScript with strict mode
  • macOS launchd daemon included

It's designed to be auditable and simple.

Development

Prerequisites

  • Bun ≥1.2.0
  • Node.js ≥18 (for type checking, optional)

Commands

bun run install     # Install dependencies (none for the proxy itself)
bun run dev         # Start the proxy in dev mode
bun run test        # Run tests
bun run lint        # Type check
bun run proxy       # Run the proxy

Running Locally

# Start the proxy
bun run proxy.ts

# Verify it's working
curl http://localhost:3456/__health

# Test with a sample request
curl -X POST http://localhost:3456/v1/messages \
  -H "Content-Type: application/json" \
  -d '{"model": "z-ai/glm-5.2", "max_tokens": 100, "messages": [{"role": "user", "content": "Hello"}]}'

Tests

bun run test        # Run all tests
bun run test run     # Run only unit tests
bun run test e2e    # Run end-to-end tests

About

This is a local server that makes any image requests in claude code go through a dedicated vision model. Powerful, open source models like GLM5.2 and Deepseek are text based only. PLaywright MCP testing cases become obsolete without vision capabilities, and this is a way around that through an existing openrouter plan

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages