Tu gateway personal de LLMs, self-hosted. Una sola app que:
- Sirve modelos locales grandes con llama.cpp gestionado (multi-GPU AMD/NVIDIA vía Vulkan, tensor-split automático, descarga de modelos desde Hugging Face en la UI).
- Gestión inteligente (2.13): clasifica cada request por complejidad y lo enruta al destino con cuota y capacidad (modo shadow para probar sin riesgo), y delega tareas de código a los CLIs instalados (Claude Code, Codex, Copilot, Antigravity, Ollama) según tier y cuota.
- Habla los dos idiomas: Anthropic Messages API (
/v1/messages) y OpenAI (/v1/chat/completions) — cualquier herramienta que use Claude o un endpoint OpenAI-compatible puede apuntar aquí. - Enruta por escenario: tareas background → modelo chico, código → modelo grande local, razonamiento pesado → Anthropic real. Con failover automático si un provider local está caído.
- Gestiona providers cloud (Copilot, Anthropic, NVIDIA NIM, OpenRouter, DeepSeek…) con cambio de un clic, chat con streaming, tracking de uso/costos.
Claude Code / OpenClaw / VS Code / Cursor / bot Telegram
│ (Anthropic API u OpenAI API + tu API key)
▼
bipolar-code :8000 ──routing──► llama-server local (tus GPUs)
──routing──► GitHub Copilot / Anthropic / NIM / …
-
Descarga el ejecutable de la página de Releases:
bipolar-code-windows.exe— Windowsbipolar-code-linux— Linuxbipolar-code-macos— macOS
-
Ejecútalo:
- Windows: doble clic en
bipolar-code-windows.exe - Linux/macOS:
chmod +x bipolar-code-linux && ./bipolar-code-linux
Al primer arranque crea solo su directorio de configuración (Windows:
C:\litellm\, Linux/macOS:~/.litellm/) y genera una API key propia — no necesitas crear nada a mano. - Windows: doble clic en
-
Abre http://localhost:8000. La UI te pedirá la API key la primera vez: está en
Settings → Acceso y Seguridad → Copiar API Key completa(o en el archivo.envdel directorio de configuración, variableUI_API_KEY). -
Elige un provider en la pestaña Providers y pulsa Activar. Para probar sin GPU ni cuentas de pago:
NVIDIA NIM(gratis con registro) uOpenRouter(tiene modelos free). Las keys de cada provider se pegan en Settings. -
(Solo si vas a usar providers cloud vía proxy — Copilot/Anthropic): instala litellm una vez:
pip install litellm
Para modelos locales (llama.cpp, LM Studio, Ollama) no hace falta: bipolar-code les habla directo.
Listo. Todo lo demás son casos de uso.
En este PC: Dashboard → Routing de Claude Code → Proxy. Eso escribe ANTHROPIC_BASE_URL/ANTHROPIC_API_KEY por ti (settings.json + registro en Windows). Reinicia Claude Code y ya está pasando por bipolar-code. Volver a Anthropic directo = un clic (Direct).
En otros PCs de tu red: Settings → Conectar PCs remotas muestra el snippet exacto con tu IP LAN:
Un portátil sin GPU usa los modelos del PC grande. Fuera de tu LAN: VPN (Tailscale/WireGuard), nunca expongas el puerto a internet.
- Descarga un release Vulkan de llama.cpp y descomprímelo (o pon
llama-serveren el PATH). - Providers → tarjeta llama.cpp (Local multi-GPU):
- Pega la ruta de
llama-server(si no está en PATH). - Modelos (buscar / descargar): busca un GGUF en Hugging Face (ej.
Qwen3-Coder-Next Q4_K_M), descárgalo con barra de progreso y pulsa Usar. Modelos gated: variableHF_TOKENen Settings. - Pulsa Iniciar y luego Activar el provider.
- Pega la ruta de
- El panel detecta tus GPUs y reparte el modelo proporcionalmente a la VRAM libre (
--tensor-splitautomático — dos AMD distintas mezcladas funcionan, ej. R9700 32GB + RX 7800 XT 16GB = pool de 48GB).
Extras del panel:
- Auto-arranque: levanta llama-server al abrir bipolar-code.
- Router mode: sirve TODOS los GGUF descargados a la vez con carga/descarga dinámica — cada request elige modelo por nombre (combínalo con el routing por escenario).
- Logs del servidor en la propia UI para diagnosticar cargas/OOM.
- Granja multi-PC (avanzado):
rpc_serversen la config del provider suma GPUs de otros PCs corriendoggml-rpc-server(--rpc). Solo vale la pena para modelos que no caben en un solo PC; usa cable 2.5GbE+ y el mismo build de llama.cpp en todos los nodos.
OpenClaw quema tokens con ganas (system prompt grande, heartbeats). Apuntado a bipolar-code, eso sale gratis en tu GPU:
- Provider Anthropic de OpenClaw →
ANTHROPIC_BASE_URL=http://<ip-de-bipolar>:8000+ANTHROPIC_API_KEY=<tu API key>. - Alternativa OpenAI-compat:
baseUrl http://<ip>:8000/v1(mismo camino que OpenClaw usa para Ollama/LM Studio). - Recomendado: routing por escenario (abajo) para que sus heartbeats vayan al modelo chico y el trabajo real al grande. Nota: los agentes exigen tool-calling sólido — modelos clase Qwen3-Coder, no 7B genéricos.
Cualquier cliente BYOK con proveedor "OpenAI compatible":
- URL:
http://<ip>:8000/v1 - API key: la de bipolar-code
- En VS Code: Copilot Chat → Manage models → OpenAI compatible.
El request llega al provider activo (o al que diga el routing).
Providers → Routing por escenario. Reglas primer-match-gana sobre el nombre de modelo que pide el cliente:
| Patrón | Min tokens | Provider destino | Para qué |
|---|---|---|---|
haiku |
0 | llamacpp → GGUF chico | Background de Claude Code (gratis y rápido) |
opus |
0 | Anthropic real | Solo razonamiento pesado |
| (vacío) | 60000 | provider con contexto largo | Prompts gigantes |
| (sin match) | — | provider activo | Todo lo demás |
Failover (mismo panel): lista de providers de respaldo — si el destino local no responde, el request cae al primero alcanzable. Ej: copilot, anthropic = si apagaste llama-server, todo sigue funcionando solo.
Chatea con tu stack desde el teléfono. En Settings (o el .env):
TELEGRAM_BOT_TOKEN=<token de @BotFather>
TELEGRAM_ALLOWED_CHAT_IDS=123456789
Allowlist vacía = bot inerte (default seguro). El bot responde con el provider activo/ruteado.
bipolar-plugin-cc: subagente bipolar-rescue que lanza un Claude Code headless contra tu modelo local — delega tareas mecánicas-medias (renames, specs, boilerplate) gratis y desde cualquier PC de la LAN:
/plugin marketplace add santiquiroz/bipolar-plugin-cc
/plugin install bipolar@bipolar-plugin-cc
/bipolar:setup http://<ip>:8000 <api-key>
Providers → Routing inteligente. Cada request a /v1/messages o /v1/chat/completions se clasifica en un tier (trivial, simple, standard, complex) con señales deterministas (tokens, tools, tool_result en curso, intención del último mensaje, hint del modelo pedido, thinking) y va al primer destino elegible de la tabla tier → providers: se descartan los que estén en cooldown por 429/cuota, sin capacidad (tools, visión, contexto), fuera de presupuesto o inalcanzables. Las reglas explícitas del caso 5 siguen ganando.
- Shadow primero: en modo shadow no cambia ningún destino, solo registra qué habría elegido. Cada respuesta lleva la cabecera
X-Bipolar-Routey la decisión queda en Usage → Decisiones de routing (acuerdo legacy↔smart, motivos, rechazos). Cuando te convenza, pásalo a Activo. - Explicable:
POST /api/smart/explaincon un body de ejemplo devuelve tier, puntaje, motivos y destino sin llamar a nadie;X-Bipolar-Tier: complexfuerza el tier desde el cliente. - Presupuestos por destino y ventana (día, semana, mes) sobre
usage.db.
Pestaña Agentes: bipolar-code detecta los CLIs instalados en el host (claude, codex, copilot, agy de Antigravity, ollama), muestra versión, auth y estado de cuota (Antigravity expone sus dos pools con agy -p "/usage", gratis) y delega tareas de código al mejor disponible:
curl -sS -H "x-api-key: $KEY" -H "content-type: application/json" -d '{"task":"Genera tests para src/pagos.py (firmas abajo) ...","workspace":"C:/repos/miapp"}' http://localhost:8000/api/delegate/jobs- El broker clasifica la tarea, recorre el orden de agentes de ese tier y salta los agotados, no instalados u ocupados. Si un intento muere por cuota (
429,out of credits,RESOURCE_EXHAUSTED, elstream was interruptedde agy) marca al agente comoexhaustedhasta su reset (5 h, diario o semanal) y reintenta en el siguiente; Antigravity prueba primero su otro pool. - Cada job corre como subproceso acotado (timeout, kill del árbol de procesos) dentro de un workspace de la lista blanca, vacía por defecto, así que nada corre hasta que la configures. Los flags de seguridad de cada CLI son fijos: claude
acceptEditssinTask/Agent, codexworkspace-write, copilot con deny list derm,git push,reset,cleanycheckout, agy solo si existe tu deny list global. El log se sigue por SSE enGET /api/delegate/jobs/{id}/stream; al terminar, el job traefiles_touched. - Los CLIs autentican con sus propias sesiones: el hijo recibe un entorno mínimo sin claves del gateway ni
ANTHROPIC_BASE_URL, para que unclaudehijo no vuelva a entrar por bipolar.
/v1 enruta solo entre providers HTTP; los agentes CLI reciben tareas por la API de jobs (un CLI trae su propio loop de herramientas y no puede devolver tool_use a Claude Code a mitad de turno).
- Compresión semántica (Settings, opt-in): al acercarse al límite de contexto, resume el historial viejo con el provider activo en vez de truncarlo.
- Uso y costos: pestaña Usage — tokens, costo estimado por provider/modelo.
- Chat integrado con streaming y visión.
- Token de Copilot se auto-refresca en background.
docker compose up -d --buildGateway + UI en :8000, config en el volumen bipolar-data. llama-server NO va dentro (necesita las GPUs del host): córrelo en el host y apunta el provider llamacpp a http://host.docker.internal:4002.
- Todo (
/api/*y/v1/*) exige tu API key — nada queda anónimo en la LAN. - Rate limiting por IP configurable (
RATE_LIMIT_RPM).X-Forwarded-Forse ignora salvo que la conexión venga de un proxy listado enTRUSTED_PROXIES. - El plano de control (
/api/*) responde 403 a cualquier IP que no sea loopback, LAN privada (RFC1918/ULA), link-local o Tailscale (100.64.0.0/10), aunque traiga la key. Se mira solo la IP de la conexión, nuncaX-Forwarded-For./v1/*no se filtra. En Docker, si el reenvío de puertos no conserva la IP de origen (Docker Desktop,userland-proxy), las conexiones llegan con la IP privada del gateway y el filtro no distingue el tráfico público. - Fuera de la LAN: VPN. No abras el puerto al internet público.
Requisitos: Python 3.11+, Node 20+.
# Backend
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# Frontend (dev, proxy a :8000)
cd frontend
npm install
npm run dev # http://localhost:5173
# Tests
cd backend && pytest
cd frontend && npm testEl backend lee .env del directorio de configuración (C:\litellm\ / ~/.litellm/, override con LITELLM_CONFIG_DIR). Variables principales:
| Variable | Para qué |
|---|---|
UI_API_KEY |
API key del gateway (se autogenera si falta) |
ANTHROPIC_API_KEY |
Provider Anthropic real |
GITHUB_OAUTH_TOKEN |
Auto-refresh del token de Copilot |
NVIDIA_NIM_API_KEY, OPENROUTER_API_KEY, DEEPSEEK_API_KEY |
Providers cloud |
HF_TOKEN |
Descargas de modelos gated en Hugging Face |
SEMANTIC_COMPRESSION |
true activa la compresión de contexto |
TELEGRAM_BOT_TOKEN, TELEGRAM_ALLOWED_CHAT_IDS |
Bot de Telegram |
RATE_LIMIT_RPM, ALLOWED_ORIGINS |
Endurecimiento de red |
TRUSTED_PROXIES |
Proxies inversos (IPs o CIDR, separados por coma) cuyo X-Forwarded-For se respeta en el rate limit; vacío = ninguno |
CONTROL_PLANE_ALLOWED_CIDRS |
Redes CIDR (separadas por coma) que pueden usar /api/*; reemplaza al default (loopback, LAN privada, link-local y Tailscale) |
Ver backend/.env.example para la lista completa.
- Frontend: React 18 + Vite + TypeScript + Tailwind CSS + TanStack Query
- Backend: Python FastAPI + structlog + httpx + pydantic-settings
- Inferencia local: llama.cpp (
llama-server, backend Vulkan) gestionado por la app - Providers cloud vía proxy: LiteLLM
MIT