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.
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.
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.
- Bun ≥1.2.0
- OpenRouter API key
git clone https://github.com/yourusername/sbfbl-router.git
cd sbfbl-routerCopy and edit the config:
cp config.example.json config.jsonEdit config.json with your preferences:
{
"port": 3456,
"upstream": "https://openrouter.ai/api",
"defaultModel": "z-ai/glm-5.2",
"visionModel": "qwen/qwen3.6-27b"
}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"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]On macOS, install the proxy as a login daemon:
# Creates a launchd plist to auto-start the proxy on login
./scripts/install-daemon.shThis 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.shAdd the following to your .claude/settings.json:
{
"env": {
"ANTHROPIC_BASE_URL": "http://localhost:3456"
}
}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 logsOnce installed, the proxy runs automatically. To check its status:
bun run proxy.ts status
tail -f ~/.cache/sbfbl-router/router.logThe 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
The proxy includes a SessionStart hook that ensures the proxy is running before any tool calls. The hook:
- Checks if the proxy process is running
- Verifies the health endpoint is accessible
- 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.
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.
├── 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
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.
- Bun ≥1.2.0
- Node.js ≥18 (for type checking, optional)
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# 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"}]}'bun run test # Run all tests
bun run test run # Run only unit tests
bun run test e2e # Run end-to-end tests