klavy-local-bridge
v0.2.6
Published
Klavy Remote Local Bridge agent for Claude Code, Codex CLI, Gemini CLI, and Kimi CLI.
Readme
klavy-local-bridge
Node CLI agent for the Klavy Remote Local Bridge. It connects to the Klavy
ActionCable WebSocket with a bearer token, reports local Claude/Codex/Gemini/Kimi
health, receives invoke jobs, runs local provider CLIs, and sends job lifecycle
messages back over the cable.
Install
npx klavy-local-bridge install-service --server https://klavy.app --token <token> --profile <profile-id>Or install the command globally:
npm install -g klavy-local-bridgeFor local development in this repository:
cd packages/local-bridge-agent
npm install
npm testCommands
npx klavy-local-bridge install-service --server https://klavy.app --token <token> --profile <profile-id>
npx klavy-local-bridge connect --server https://klavy.app --token <token>
klavy-local-bridge connect --server https://klavy.app --token <token>
klavy-local-bridge status
klavy-local-bridge service-status
klavy-local-bridge disconnect
klavy-local-bridge uninstall-serviceinstall-service is the recommended macOS setup. It upserts the token into
~/.config/klavy-local-bridge/config.json with 0600 permissions and installs
a single LaunchAgent at ~/Library/LaunchAgents/app.klavy.local-bridge.plist.
The plist runs the bridge with --config and does not contain tokens.
Config version 2 supports multiple account profiles in one local service:
{
"version": 2,
"defaults": {
"url": "wss://klavy.app/cable",
"origin": "https://klavy.app",
"channel": "LocalBridgeChannel"
},
"profiles": [
{ "id": "admin-1", "name": "Admin", "token": "klb_...", "enabled": true },
{ "id": "user-6", "name": "User", "token": "klb_...", "enabled": true }
]
}Legacy flat configs with a single token still work and are migrated to the
multi-profile shape the next time install-service runs.
connect also reads these environment variables:
| Variable | Purpose |
| --- | --- |
| KLAVY_CABLE_URL | Full ActionCable WebSocket URL. |
| KLAVY_CABLE_ORIGIN | WebSocket Origin header; inferred from the cable URL by default. |
| KLAVY_URL | Base app URL; /cable is inferred. |
| KLAVY_BRIDGE_TOKEN | Bearer token sent as Authorization: Bearer .... |
| KLAVY_LOCAL_BRIDGE_CHANNEL | ActionCable channel, default LocalBridgeChannel. |
| KLAVY_CLAUDE_BIN | Claude Code binary, default claude. |
| KLAVY_CODEX_BIN | Codex CLI binary, default codex. |
| KLAVY_GEMINI_BIN | Gemini CLI binary, default gemini. |
| KLAVY_GEMINI_CWD | Gemini CLI working directory, default KLAVY_LOCAL_BRIDGE_CWD / current directory. |
| KLAVY_GEMINI_TRUST_WORKSPACE | Whether the agent sets GEMINI_CLI_TRUST_WORKSPACE=true, default true. |
| KLAVY_KIMI_BIN | Kimi CLI binary, default kimi. |
| KLAVY_KIMI_CWD | Kimi CLI working directory, default KLAVY_LOCAL_BRIDGE_CWD / current directory. |
| KLAVY_KIMI_MODEL | Optional Kimi CLI config model alias. If unset, the Kimi CLI default model is used. |
| KLAVY_CODEX_MODEL | Default Codex model, default gpt-5.4. |
Use --url wss://.../cable only when you need to pass a full ActionCable URL
directly.
Wire Protocol
The agent subscribes to LocalBridgeChannel by default. Server frames with
message.type, message.event, or message.action equal to invoke are
treated as jobs.
An invoke job should include:
{
"type": "invoke",
"job": {
"id": "job_123",
"provider": "claude",
"request": {
"system": "You are helpful.",
"messages": [{ "role": "user", "content": "Hello" }],
"model": "gpt-5.4"
}
}
}The agent performs channel actions named:
heartbeatacceptedchunkcompletedfailed
The bridge supports claude, openai, gemini, and kimi. codex is accepted as an
alias for openai; moonshot is accepted as an alias for kimi. Gemini CLI jobs run with GEMINI_CLI_TRUST_WORKSPACE=true
by default so LaunchAgent/headless execution does not get stuck on trusted
folder prompts. Gemini jobs may include request.model; when present, the
agent forwards it to the Gemini CLI as --model <model>. Omit it to use the
Gemini CLI default model.
Kimi jobs use the local Kimi CLI in non-interactive mode. Jobs may include
request.model; when present, the agent forwards it as --model <model>.
For UI/UX design image slots, the server may send an OpenAI job with
request.task set to image_generation:
{
"type": "invoke",
"job": {
"id": "job_img_123",
"provider": "openai",
"payload": {
"task": "image_generation",
"model": "gpt-image-2",
"prompt": "Hero image for a home service intro",
"aspect_ratio": "16:9"
}
}
}The agent handles this with the local Codex subscription path and returns JSON
containing image_base64 and mime_type. The server also accepts future agent
responses with data_url or image_url.
