@elvatis_com/openclaw-cli-bridge-elvatis
v1.3.1
Published
Bridges gemini, claude, and codex CLI tools as OpenClaw model providers. Reads existing CLI auth without re-login.
Readme
openclaw-cli-bridge-elvatis
OpenClaw plugin that bridges locally installed AI CLIs (Codex, Gemini, Claude Code) as model providers — with slash commands for instant model switching, restore, health testing, and model listing.
Current version: 1.3.1
What it does
Phase 1 — Auth bridge (openai-codex)
Registers the openai-codex provider by reading OAuth tokens already stored by the Codex CLI (~/.codex/auth.json). No re-login needed.
Phase 2 — Request bridge (local proxy)
Starts a local OpenAI-compatible HTTP proxy on 127.0.0.1:31337 and configures OpenClaw's vllm provider to route calls through gemini and claude CLI subprocesses.
Prompt delivery: always via stdin (never CLI args or @file) — avoids E2BIG for long sessions and Gemini agentic mode. Each message batch is truncated to the last 20 messages + system message (MAX_MESSAGES/MAX_MSG_CHARS in src/cli-runner.ts).
| Model reference | CLI invoked | Latency |
|---|---|---|
| vllm/cli-gemini/gemini-2.5-pro | gemini -m gemini-2.5-pro -p "" (stdin, cwd=/tmp) | ~8–10s |
| vllm/cli-gemini/gemini-2.5-flash | gemini -m gemini-2.5-flash -p "" (stdin, cwd=/tmp) | ~4–6s |
| vllm/cli-gemini/gemini-3-pro-preview | gemini -m gemini-3-pro-preview -p "" (stdin, cwd=/tmp) | ~8–10s |
| vllm/cli-gemini/gemini-3-flash-preview | gemini -m gemini-3-flash-preview -p "" (stdin, cwd=/tmp) | ~4–6s |
| vllm/cli-claude/claude-sonnet-4-6 | claude -p --output-format text --model claude-sonnet-4-6 (stdin) | ~2–4s |
| vllm/cli-claude/claude-opus-4-6 | claude -p --output-format text --model claude-opus-4-6 (stdin) | ~3–5s |
| vllm/cli-claude/claude-haiku-4-5 | claude -p --output-format text --model claude-haiku-4-5 (stdin) | ~1–3s |
Phase 3 — Slash commands
All commands use gateway-level commands.allowFrom for authorization (requireAuth: false at plugin level).
Claude Code CLI (routed via local proxy on :31337):
| Command | Model |
|---|---|
| /cli-sonnet | vllm/cli-claude/claude-sonnet-4-6 |
| /cli-opus | vllm/cli-claude/claude-opus-4-6 |
| /cli-haiku | vllm/cli-claude/claude-haiku-4-5 |
Gemini CLI (routed via local proxy on :31337, stdin + cwd=/tmp):
| Command | Model |
|---|---|
| /cli-gemini | vllm/cli-gemini/gemini-2.5-pro |
| /cli-gemini-flash | vllm/cli-gemini/gemini-2.5-flash |
| /cli-gemini3 | vllm/cli-gemini/gemini-3-pro-preview |
| /cli-gemini3-flash | vllm/cli-gemini/gemini-3-flash-preview |
Codex CLI (via openai-codex provider — OAuth auth, calls OpenAI API directly, not through the local proxy):
| Command | Model | Notes |
|---|---|---|
| /cli-codex | openai-codex/gpt-5.3-codex | ✅ Tested |
| /cli-codex-spark | openai-codex/gpt-5.3-codex-spark | |
| /cli-codex52 | openai-codex/gpt-5.2-codex | |
| /cli-codex54 | openai-codex/gpt-5.4 | May require upgraded OAuth scope |
| /cli-codex-mini | openai-codex/gpt-5.1-codex-mini | ✅ Tested |
Utility:
| Command | What it does |
|---|---|
| /cli-back | Restore the model active before the last /cli-* switch |
| /cli-test [model] | One-shot proxy health check — does NOT switch your active model |
| /cli-list | Show all registered CLI bridge models with commands |
/cli-back details:
- Before every
/cli-*switch the current model is saved to~/.openclaw/cli-bridge-state.json /cli-backreads it, callsopenclaw models set <previous>, then clears the file- State survives gateway restarts — safe to use any time
/cli-test details:
- Accepts short form (
cli-sonnet) or full path (vllm/cli-claude/claude-sonnet-4-6) - Default when no arg given:
cli-claude/claude-sonnet-4-6 - Reports response content, latency, and confirms your active model is unchanged
/cli-list details:
- Lists all registered models grouped by provider (Claude CLI, Gemini CLI, Codex)
- No arguments required
Requirements
- OpenClaw gateway (tested with
2026.3.x) - One or more of:
@openai/codex—npm i -g @openai/codex+codex login@google/gemini-cli—npm i -g @google/gemini-cli+gemini auth@anthropic-ai/claude-code—npm i -g @anthropic-ai/claude-code+claude auth
Installation
# From ClawHub
clawhub install openclaw-cli-bridge-elvatis
# Or from workspace (development)
# Add to ~/.openclaw/openclaw.json:
# plugins.load.paths: ["~/.openclaw/workspace/openclaw-cli-bridge-elvatis"]
# plugins.entries.openclaw-cli-bridge-elvatis: { "enabled": true }Setup
1. Enable + restart
// ~/.openclaw/openclaw.json → plugins.entries
"openclaw-cli-bridge-elvatis": { "enabled": true }openclaw gateway restart2. Verify (check gateway logs)
[cli-bridge] proxy ready on :31337
[cli-bridge] registered 14 commands: /cli-sonnet, /cli-opus, /cli-haiku,
/cli-gemini, /cli-gemini-flash, /cli-gemini3, /cli-gemini3-flash,
/cli-codex, /cli-codex-spark, /cli-codex52, /cli-codex54, /cli-codex-mini,
/cli-back, /cli-test, /cli-list3. Register Codex auth (optional — Phase 1 only)
openclaw models auth login --provider openai-codex
# Select: "Codex CLI (existing login)"4. List available models
/cli-list
→ 🤖 CLI Bridge Models
Claude Code CLI
/cli-sonnet claude-sonnet-4-6
/cli-opus claude-opus-4-6
/cli-haiku claude-haiku-4-5
Gemini CLI
/cli-gemini gemini-2.5-pro
/cli-gemini-flash gemini-2.5-flash
/cli-gemini3 gemini-3-pro-preview
/cli-gemini3-flash gemini-3-flash-preview
Codex (OAuth)
/cli-codex gpt-5.3-codex
/cli-codex-spark gpt-5.3-codex-spark
/cli-codex52 gpt-5.2-codex
/cli-codex54 gpt-5.4
/cli-codex-mini gpt-5.1-codex-mini
Utility
/cli-back Restore previous model
/cli-test [model] Health check (no model switch)
/cli-list This overview
Proxy: 127.0.0.1:313375. Test without switching your model
/cli-test
→ 🧪 CLI Bridge Test
Model: vllm/cli-claude/claude-sonnet-4-6
Response: CLI bridge OK
Latency: 2531ms
Active model unchanged: anthropic/claude-sonnet-4-6
/cli-test cli-gemini
→ 🧪 CLI Bridge Test
Model: vllm/cli-gemini/gemini-2.5-pro
Response: CLI bridge OK
Latency: 8586ms
Active model unchanged: anthropic/claude-sonnet-4-66. Switch and restore
/cli-sonnet
→ ✅ Switched to Claude Sonnet 4.6 (CLI)
`vllm/cli-claude/claude-sonnet-4-6`
Use /cli-back to restore previous model.
... test things ...
/cli-back
→ ✅ Restored previous model
`anthropic/claude-sonnet-4-6`Configuration
In ~/.openclaw/openclaw.json → plugins.entries.openclaw-cli-bridge-elvatis.config:
{
"enableCodex": true, // register openai-codex from Codex CLI auth (default: true)
"enableProxy": true, // start local CLI proxy server (default: true)
"proxyPort": 31337, // proxy port (default: 31337)
"proxyApiKey": "cli-bridge", // key between OpenClaw vllm provider and proxy (default: "cli-bridge")
"proxyTimeoutMs": 120000 // CLI subprocess timeout in ms (default: 120s)
}Model Allowlist
routeToCliRunner enforces DEFAULT_ALLOWED_CLI_MODELS — only models registered in the plugin are accepted by the proxy. Unregistered models receive a clear error listing allowed options.
To disable the check (e.g. for custom vllm routing): pass allowedModels: null in RouteOptions.
Architecture
OpenClaw agent
│
├─ openai-codex/* ──────────────────────────► OpenAI API (direct)
│ auth: ~/.codex/auth.json OAuth tokens
│ /cli-codex, /cli-codex-spark, /cli-codex52, /cli-codex54, /cli-codex-mini
│
└─ vllm/cli-gemini/* ─┐
vllm/cli-claude/* ─┤─► localhost:31337 (openclaw-cli-bridge proxy)
│ ├─ cli-gemini/* → gemini -m <model> -p ""
│ │ stdin=prompt, cwd=/tmp
│ │ (neutral cwd prevents agentic mode)
│ └─ cli-claude/* → claude -p --model <model>
│ stdin=prompt
Slash commands (requireAuth=false, gateway commands.allowFrom is the auth layer):
/cli-sonnet|opus|haiku|gemini|gemini-flash|gemini3|gemini3-flash
/cli-codex|codex-spark|codex52|codex54|codex-mini
└─► saves current model → ~/.openclaw/cli-bridge-state.json
└─► openclaw models set <model>
/cli-back → reads state file, restores previous model, clears state
/cli-test → HTTP POST → localhost:31337, no global model change
/cli-list → formatted table of all registered modelsKnown Issues & Fixes
spawn E2BIG (fixed in v0.2.1)
Symptom: CLI error for cli-claude/…: spawn E2BIG after ~500+ messages.
Cause: Gateway injects large values into process.env at runtime. Spreading it into spawn() exceeds Linux's ARG_MAX (~2MB).
Fix: buildMinimalEnv() — only passes HOME, PATH, USER, and auth keys.
Claude Code 401 / timeout on OAuth login (fixed in v0.2.21)
Symptom: /cli-test cli-claude/* times out after 30s; logs show 401 Invalid authentication credentials.
Cause: buildMinimalEnv() did not forward XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS to the spawned claude subprocess. Claude Code authenticated via claude.ai OAuth (Claude Max plan) stores its tokens in the system keyring (Gnome Keyring / libsecret) and needs these env vars to access it.
Affects: Only systems using claude auth OAuth login (Claude Max / Teams). API-key users (ANTHROPIC_API_KEY) are not affected.
Fix: Added XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS to the forwarded env keys in buildMinimalEnv().
Gemini agentic mode / hangs (fixed in v0.2.4)
Symptom: Gemini hangs, returns wrong answers, or says "directory does not exist".
Cause: @file syntax (gemini -p @/tmp/xxx.txt) triggers agentic mode — Gemini scans the working directory for project context and treats prompts as task instructions.
Fix: Stdin delivery (gemini -p "" with prompt via stdin) + cwd=/tmp.
Development
npm run typecheck # tsc --noEmit
npm test # vitest run (45 tests)Changelog
v1.3.1
- fix: /claude-login, /gemini-login, /chatgpt-login now bake cookies into persistent profile dirs
- fix: After gateway restart, providers auto-reconnect from saved profile (no browser tabs needed)
- fix: Better debug logging when persistent headless context fails (Cloudflare etc.)
v1.3.0
- fix: Browser persistence after gateway restart — each provider launches its own persistent Chromium if OpenClaw browser is unavailable
- feat:
ensureAllProviderContexts()— unified startup connect for all 4 providers - feat: Lazy-connect fallback to persistent context when CDP unavailable
v1.2.0
- fix: Fresh page per request — no more message accumulation across calls
- feat: ChatGPT model switching via URL param (?model=gpt-4o, o3, etc.)
- chore: Gemini model switching: TODO (requires UI interaction)
v1.1.0
- feat: Auto-connect all providers on startup (no manual login after restart if browser is open)
- feat:
/bridge-status— all 4 providers at a glance with expiry info - fix: Removed obsolete CLI models: gpt-5.2-codex, gpt-5.3-codex-spark, gpt-5.1-codex-mini, gemini-3-flash-preview
- fix: Removed duplicate cli-gemini3-flash (was same as gemini-3-flash-preview)
- chore: Cleaned up CLI_MODEL_COMMANDS (8 models, down from 13)
v1.0.0 — Full Headless Browser Bridge 🚀
All four major LLM providers are now available via browser automation. No CLI binaries required — just authenticated browser sessions.
v1.1.0
- feat: Auto-connect all providers on startup (no manual login after restart if browser is open)
- feat:
/bridge-status— all 4 providers at a glance with expiry info - fix: Removed obsolete CLI models: gpt-5.2-codex, gpt-5.3-codex-spark, gpt-5.1-codex-mini, gemini-3-flash-preview
- fix: Removed duplicate cli-gemini3-flash (was same as gemini-3-flash-preview)
- chore: Cleaned up CLI_MODEL_COMMANDS (8 models, down from 13)
v1.0.0
- feat:
chatgpt-browser.ts— chatgpt.com DOM-automation (#prompt-textarea+[data-message-author-role]) - feat:
web-chatgpt/*models: gpt-4o, gpt-4o-mini, gpt-o3, gpt-o4-mini, gpt-5 - feat:
/chatgpt-login,/chatgpt-status,/chatgpt-logout+ cookie-expiry tracking - feat: All 4 providers headless: Grok ✅ Claude ✅ Gemini ✅ ChatGPT ✅
- test: 96/96 tests green (8 test files)
- fix: Singleton CDP connection, cleanupBrowsers() on plugin stop
v0.2.30
- feat:
gemini-browser.ts— gemini.google.com DOM-automation (Quill editor + message-content polling) - feat:
web-gemini/*models in proxy (gemini-2-5-pro, gemini-2-5-flash, gemini-3-pro, gemini-3-flash) - feat:
/gemini-login,/gemini-status,/gemini-logoutcommands + cookie-expiry tracking - fix: Singleton CDP connection — no more zombie Chromium processes
- fix:
cleanupBrowsers()called on plugin stop — all browser resources released - test: 90/90 tests green (+6 gemini-proxy tests)
v0.2.29
- feat:
claude-browser.ts— claude.ai DOM-automation (ProseMirror +[data-test-render-count]polling) - feat:
web-claude/*models in proxy (web-claude/claude-sonnet, claude-opus, claude-haiku) - feat:
/claude-login,/claude-status,/claude-logoutcommands - feat: Claude cookie-expiry tracking (
~/.openclaw/claude-cookie-expiry.json) - test: 84/84 tests green (+7 claude-proxy tests, +8 claude-browser unit tests)
v0.2.28
- feat:
/grok-loginscans auth cookie expiry (sso cookie) and saves to~/.openclaw/grok-cookie-expiry.json - feat:
/grok-statusshows cookie expiry with color-coded warnings (🚨 <7d, ⚠️ <14d, ✅ otherwise) - feat: Startup log shows cookie expiry and refreshes the expiry file on session restore
- fix: Flaky cli-runner test improved (was pre-existing)
v0.2.27
- feat: Grok persistent Chromium profile (
~/.openclaw/grok-profile/) — cookies survive gateway restarts - feat:
/grok-loginimports cookies from OpenClaw browser into persistent profile automatically - fix:
verifySessionreuses existing grok.com page instead of opening a new one (avoids Cloudflare 403) - fix: DOM-polling strategy instead of direct fetch API — bypasses
x-statsig-idanti-bot check completely - fix: Lazy-connect:
connectGrokContextcallback auto-reconnects on first request after restart
v0.2.26
- feat: Grok web-session bridge integrated into cli-bridge proxy — routes
web-grok/*models through grok.com browser session (SuperGrok subscription, no API credits needed) - feat:
/grok-login— opens Chromium for X.com OAuth login, saves session to~/.openclaw/grok-session.json - feat:
/grok-status— check session validity - feat:
/grok-logout— clear session - fix: Grok web-session plugin removed as separate plugin — consolidated into cli-bridge (fewer running processes, single proxy port)
v0.2.25
- feat: Staged model switching —
/cli-*now stages the switch instead of applying it immediately. Prevents silent session corruption when switching models mid-conversation./cli-sonnet→ stages switch, shows warning, does NOT apply/cli-sonnet --now→ immediate switch (use only between sessions!)/cli-apply→ apply staged switch after finishing current task/cli-pending→ show staged switch (if any)/cli-back→ restore previous model + clear staged switch
- fix: Sleep-resilient OAuth token refresh — replaced single long
setTimeoutwithsetInterval(10min)polling. Token refresh no longer misses its window after system sleep/resume. - fix: Timer leak in
scheduleTokenRefresh()— old interval now reliably cleared viastopTokenRefresh()before scheduling a new one. - fix:
stopTokenRefresh()exported fromclaude-auth.ts; called automatically viaserver.on("close")when the proxy server closes.
v0.2.23
- feat: Proactive OAuth token management (
src/claude-auth.ts) — the proxy now reads~/.claude/.credentials.jsonat startup, schedules a refresh 30 minutes before expiry, and callsensureClaudeToken()before everyclaudesubprocess invocation. On 401 responses, automatically retries once after refreshing. Eliminates the need for manual re-login after token expiry in headless/systemd deployments.
v0.2.22
- fix:
runClaude()now detects expired/invalid OAuth tokens immediately (401 in stderr) and throws a clear actionable error instead of waiting for the 30s proxy timeout. Error message includes the exact re-login command.
v0.2.21
- fix:
buildMinimalEnv()now forwardsXDG_RUNTIME_DIRandDBUS_SESSION_BUS_ADDRESSto Claude Code subprocesses — required for Gnome Keyring / libsecret access when Claude Code is authenticated viaclaude.aiOAuth (Claude Max). Without these, the spawnedclaudeprocess cannot read its OAuth token from the system keyring, resulting in401 Invalid authentication credentialsand a 30-second timeout on/cli-testand all/cli-claude/*requests.
v0.2.20
- fix:
formatPromptnow defensively coercescontentto string viacontentToString()— prevents[object Object]reaching the CLI when WhatsApp group messages contain structured content objects instead of plain strings - feat:
ChatMessage.contentnow acceptsstring | ContentPart[] | unknown(OpenAI multimodal content arrays supported) - feat: New
contentToString()helper: handles string, OpenAI ContentPart arrays, arbitrary objects (JSON.stringify), null/undefined
v0.2.19
- feat:
/cli-listcommand — formatted overview of all registered models grouped by provider - docs: Rewrite README to reflect current state (correct model names, command count, requireAuth, test count, /cli-list docs)
v0.2.18
- feat: Add
/cli-gemini3-flash→gemini-3-flash-preview - feat: Add
/cli-codex-spark→gpt-5.3-codex-spark,/cli-codex52→gpt-5.2-codex,/cli-codex54→gpt-5.4 - fix: Update
DEFAULT_ALLOWED_CLI_MODELSwithgemini-3-flash-preview
v0.2.17
- fix:
/cli-gemini3model corrected togemini-3-pro-preview(wasgemini-3-pro, returns 404 from Gemini API)
v0.2.16
- feat(T-101): Expand test suite to 45 tests — new cases for
formatPrompt(mixed roles, boundary values, system messages) androuteToCliRunner(gemini paths, edge cases) - feat(T-103): Add
DEFAULT_ALLOWED_CLI_MODELSallowlist;routeToCliRunnernow rejects unregistered models by default; passallowedModels: nullto opt out
v0.2.15
- docs: Rewrite changelog (entries for v0.2.12–v0.2.14 were corrupted); all providers verified working end-to-end
v0.2.14
- fix: Strip
vllm/prefix inrouteToCliRunner— OpenClaw sends full provider path (vllm/cli-claude/...) but proxy router expected barecli-claude/... - test: Add 4 routing tests (9 total)
v0.2.13
- fix: Set
requireAuth: falseon all/cli-*commands — plugin-level auth uses different resolution path thancommands.allowFrom; gateway allowlist is the correct security layer - fix: Hardcoded
version: "0.2.5"in plugin object now trackspackage.json
v0.2.9
- fix: Critical — replace
fuser -k 31337/tcpwith safe health probe to prevent gateway SIGKILL on hot-reloads
v0.2.7–v0.2.8
- fix: Port leak on hot-reload —
registerServicestop() hook +closeAllConnections()
v0.2.6
- fix:
openclaw.extensionsadded topackage.json; config patcher auto-adds vllm provider
v0.2.5
- feat:
/cli-codex+/cli-codex-mini(Codex OAuth provider, direct API)
v0.2.4
- fix: Gemini agentic mode — stdin delivery +
cwd=/tmp
v0.2.3
- feat:
/cli-back+/cli-test
v0.2.2
- feat: Phase 3 —
/cli-*slash commands
v0.2.1
- fix:
spawn E2BIG+ unit tests
v0.2.0
- feat: Phase 2 — local OpenAI-compatible proxy, stdin delivery, prompt truncation
v0.1.x
- Phase 1: Codex CLI OAuth auth bridge
License
MIT
