Run AI Coding Agents from Anywhere — Docker, Cloud, or Hybrid
An HTTP task-queue bridge that lets OpenClaw dispatch tasks to Claude Code, Codex, and Gemini CLI across container boundaries, network boundaries, or both.
English | 简体中文
Status: Maintenance mode. In the author's own setup the OpenClaw plugin's slash-command path is retired; the live path is now containers calling
task-apidirectly over HTTP (see "Two Ways to Connect" below). The plugin still works and remains the recommended entry point for OpenClaw users.
acpx is the official OpenClaw CLI client built on the Agent Client Protocol (ACP). It spawns the CLI as a local child process over stdio. If OpenClaw and Claude Code are on the same machine, acpx is the right choice.
The problem: when OpenClaw runs in Docker or on a remote server, acpx cannot reach a CLI on another machine. ACP is a stdio protocol with no network transport. Remote ACP is still "work in progress" in the spec.
What tunnel does: instead of waiting for remote ACP, tunnel bridges the gap with an HTTP task queue. The plugin (inside Docker) enqueues tasks to task-api. A runner anywhere on the network long-polls for tasks, spawns the CLI, and reports the result back to task-api, which posts it to your chat channel.
| acpx | tunnel | |
|---|---|---|
| Protocol | ACP (JSON-RPC over stdio) | HTTP task queue + server callback |
| Same machine required | Yes | No — works across networks |
| Session model | By git directory | By chat channel |
| Token cost | Zero (protocol layer) | Zero (protocol layer) |
| Best for | OpenClaw on bare metal | OpenClaw in Docker or cloud |
tunnel supports three deployment patterns. Pick the one that fits your setup:
OpenClaw + task-api in Docker on your machine. Runner on the host. Everything on one box.
┌──────────────────────────────────────┐
│ Your Machine │
│ │
│ ┌─────────── Docker ──────────────┐ │
│ │ OpenClaw + plugin │ │
│ │ task-api :3456 │ │
│ └──────────────┬──────────────────┘ │
│ │ long-poll │
│ ┌──────────────┴──────────────────┐ │
│ │ runner │ │
│ │ → Claude Code / Codex / Gemini │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────┘
# Runner connects to localhost (default)
WORKER_URL=http://localhost:3456task-api on a cloud VM (AWS, GCP, any VPS). Runner on your local machine — your CLIs stay local, but orchestration lives in the cloud.
┌───── Cloud VM ──────┐ ┌────── Your Machine ──────┐
│ Docker │ │ │
│ OpenClaw + plugin │ internet │ runner │
│ task-api :3456 │◄──────────│ → Claude Code │
│ │ │ → Codex │
└─────────────────────┘ │ → Gemini │
└───────────────────────────┘
# Runner connects to cloud server
WORKER_URL=http://your-server.com:3456Everything on cloud infrastructure. Ideal for compliance requirements — all AI agent execution contained within managed servers.
┌────────────────── Cloud VM ──────────────────┐
│ │
│ ┌─────────── Docker ──────────────┐ │
│ │ OpenClaw + plugin │ │
│ │ task-api :3456 │ │
│ └──────────────┬──────────────────┘ │
│ │ long-poll (localhost) │
│ ┌──────────────┴──────────────────┐ │
│ │ runner │ │
│ │ → Claude Code / Codex / Gemini │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────────────┘
# Runner and task-api on the same VM
WORKER_URL=http://localhost:3456
# Install CLIs on the VM, run the runner as a systemd service| Feature | Description |
|---|---|
| Three CLIs | /cc for Claude Code, /codex for Codex, /gemini for Gemini |
| Session continuity | Per-channel sessions with auto-resume. Bindings persisted in SQLite |
| Zero-token relay | Protocol layer only — no LLM calls in the plugin or runner |
| Platform agnostic | Discord, Telegram, or any platform OpenClaw supports |
| One-command setup | setup.sh generates .env, updates plugin config, installs LaunchAgent |
| Concurrent execution | Up to 5 parallel tasks with configurable Claude model fallback |
| SDK + CLI modes | Agent SDK (streaming) with automatic fallback to CLI |
| Cloud-ready | Deploy anywhere — local Docker, cloud VM, or hybrid |
git clone https://github.com/AliceLJY/openclaw-tunnel.git
cd openclaw-tunnel
./setup.sh
docker-compose up -d
# Try /cc hello in your chatsetup.sh will:
- Check prerequisites (Docker, Node.js, Claude Code CLI)
- Prompt for port, bot token, and callback channel
- Generate
WORKER_TOKENand write.env - Update
plugin/openclaw.plugin.jsonwith your values - Offer to install the macOS LaunchAgent for the runner
After setup, copy plugin/ into your OpenClaw plugins folder (or reference it in openclaw.json).
task-api/ — Express HTTP server in Docker. Accepts tasks from the plugin, stores them in SQLite, serves them to the runner via long-polling, receives completed results, and posts results back to your chat via bot callback. Default port 3456.
runner/ — Node.js worker on the host (or any machine). Long-polls task-api, spawns Claude Code / Codex / Gemini CLI as child processes (up to 5 concurrent), and reports execution results back to task-api. Prefers Agent SDK with streaming, auto-fallback to CLI mode.
plugin/ — OpenClaw plugin (TypeScript). Registers /cc, /codex, /gemini command families, manages per-channel session bindings in SQLite, and submits tasks to task-api.
| Claude Code | Codex | Gemini | Description |
|---|---|---|---|
/cc <prompt> |
/codex <prompt> |
/gemini <prompt> |
Submit task, continue session |
/cc-new |
/codex-new |
/gemini-new |
Start fresh session |
/cc-recent |
— | — | List recent sessions |
/cc-resume <id> |
/codex-resume <id> |
/gemini-resume <id> |
Resume specific session |
/cc-now |
/codex-now |
/gemini-now |
Show active session ID |
/cli-state |
/cli-state |
/cli-state |
Check connectivity |
task-api is a plain HTTP service. There are two ways to drive it:
1. OpenClaw plugin (slash commands) — install plugin/ into an OpenClaw instance and trigger /cc, /codex, /gemini from chat (see the table above). Best for OpenClaw users.
2. Direct HTTP — any client (a script, a bot, another agent) can POST /claude directly, no plugin required:
curl -X POST http://<task-api-host>:3456/claude \
-H "Authorization: Bearer $WORKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"prompt": "what you want CC to do", "timeout": 600000, "callbackChannel": "<optional channel id>"}'Response: { "taskId": "...", "sessionId": "..." }. With callbackChannel the result is pushed back asynchronously; without it, poll GET /tasks/<taskId>?wait=<ms> for the result. /codex and /gemini work the same way.
Configuration
Copy .env.example to .env (or let setup.sh generate it):
| Variable | Where used | Description |
|---|---|---|
WORKER_TOKEN |
task-api + runner | Shared secret for API auth (min 16 chars) |
PORT |
task-api | Port task-api listens on (default: 3456) |
CALLBACK_BOT_TOKEN |
task-api | Bot token for posting results back |
CALLBACK_API_BASE_URL |
task-api | Bot API base URL (default: Discord) |
CALLBACK_CHANNEL |
task-api | Optional fallback channel/thread ID when a task has no callback channel |
WORKER_URL |
runner | URL to reach task-api (default: http://localhost:3456) |
CLAUDE_PATH |
runner | Path to claude binary (default: claude) |
CODEX_PATH |
runner | Path to codex binary (default: codex) |
GEMINI_PATH |
runner | Path to gemini binary (default: gemini) |
CC_TIMEOUT |
runner | Fallback per-task execution cap when a task omits its own timeout, in ms (default: 1200000) |
CC_MODELS |
runner | Optional comma-separated Claude model list. Empty means use Claude Code's default model |
RUNNER_SESSION_CACHE_FILE |
runner | Optional session cache path. Empty uses the OS temp directory |
CC_LOG_PATH |
runner | Optional Claude live log path. Empty uses the OS temp directory |
MAX_CONCURRENT |
runner | Max parallel tasks (default: 5) |
POLL_INTERVAL |
runner | Polling interval when at capacity (default: 500 ms) |
LONG_POLL_WAIT |
runner | Long-poll wait window (default: 30000 ms) |
WORKER_DIRECT_CALLBACK |
runner | Legacy opt-in for runner-side callback delivery. Keep false for Windows/cloud setups |
DISCORD_PROXY |
runner | HTTPS proxy for legacy runner-side callback delivery (optional) |
The plugin reads apiUrl, apiToken, and callbackChannel from plugin/openclaw.plugin.json — setup.sh populates these automatically.
Runner on Linux / Cloud
setup.sh installs a macOS LaunchAgent automatically. On Linux or cloud VMs, run the runner manually:
cd runner
WORKER_URL=http://localhost:3456 WORKER_TOKEN=your-token node worker.jsOn Windows, run:
cd runner
set "WORKER_URL=http://your-server:3456"
set "WORKER_TOKEN=your-token"
start-worker.batThe Windows launcher uses %TEMP% for the session cache and live log by default. Leave WORKER_DIRECT_CALLBACK=false so Windows only reports results to task-api; the server sends the chat callback.
Or register as a systemd service for always-on operation:
[Unit]
Description=openclaw-tunnel runner
After=network.target
[Service]
ExecStart=/usr/bin/node /path/to/runner/worker.js
Environment=WORKER_URL=http://localhost:3456
Environment=WORKER_TOKEN=your-token
Restart=always
[Install]
WantedBy=multi-user.targetFor cloud deployment (Scenario B), replace localhost with the cloud server's IP or domain.
Why long-polling?
The runner sits on the host (or a remote machine) behind NAT — task-api inside Docker cannot push to it. Rather than requiring the runner to expose a port or set up a reverse tunnel, the runner holds an open HTTP connection to task-api waiting for work. When a task arrives, task-api responds immediately. No inbound firewall rules, no WebSocket server, and the runner works identically on macOS, Linux, localhost, or across the internet.
Prerequisites
- Docker (with Docker Compose)
- Node.js >= 22.5 (required for
node:sqlitebuilt-in) - At least one CLI installed and authenticated: Claude Code, Codex, or Gemini
- OpenClaw instance (Docker deployment)
Built by AliceLJY — a non-programmer who builds AI agent infrastructure with Claude Code. Writes about the journey on WeChat: "My AI Cabin".
This project grew out of real-world pain: running five OpenClaw bots in Docker while needing Claude Code, Codex, and Gemini on the host.
Part of the 小试AI open-source AI workflow:
| Project | Description |
|---|---|
| recallnest | MCP memory workbench (LanceDB + Jina v5) |
| digital-clone-skill | Build digital clones from corpus data |
| telegram-ai-bridge | Telegram bots for Claude, Codex, and Gemini |
| claude-code-studio | Multi-session collaboration platform for Claude Code |
| cc-empire | Complete Claude Code workflow scaffold |
MIT