Skip to main content
Glama

lanbus

CI

One agent entry. Sub-agents everywhere else on your LAN.

English · 中文 · Overview · 中文总览 · Architecture · Protocol

You talk to a single main agent - an A agent CLI, a B agent CLI, a C agent desktop, or anything that speaks MCP. It dispatches work to agents running on your other machines — Windows for the Web UI, WSL for the Linux build, macOS for native packaging — then verifies what actually changed and either accepts the result or sends it back for rework.

Zero mandatory dependencies. Standard library only. Never leaves your LAN. Optional Playwright unlocks real browser actions; Chrome/Edge headless gives fallback screenshots. A built-in scanner finds AI agents already running on the LAN without installing anything on them.

                    you ──► main agent (A agent CLI)
                                  │ MCP: lan_dispatch / lan_logs / lan_result / lan_review
                                  ▼
                        ┌───────────────────┐
                        │  lanbus hub :8788 │  SQLite task table + state machine
                        └───┬───────────┬───┘
              REST (pull)   │           │   REST (pull)
                        ┌───▼────┐  ┌───▼────┐
                        │ win-ui │  │ mac-ui │
                        │windows │  │ macos  │
                        └───┬────┘  └────────┘
                            │ same machine
                        ┌───▼─────┐
                        │wsl-core │
                        │  wsl    │
                        └─────────┘

Workers pull from the hub, so only the hub machine needs an inbound port. Sub-environments need no firewall rules at all.


Why this exists

Running agents in three environments usually means being the human message bus: you ask one agent for a task, then copy its text into the other agent's window, then eyeball the result yourself. lanbus replaces that loop with machine-checkable facts:

Without lanbus

With lanbus

you paste the task across

lan_dispatch(env, prompt, context, cwd, verify)

the remote agent says "done"

verify_ok = exit code of your acceptance command, run on the remote machine

you trust the summary

diff + changed collected from the real working tree

you judge by vibes

lan_review(approve | rework, feedback) — feedback is appended to the retry prompt

you cannot see the remote run

lan_logs / lanbus logs --follow streams stdout+stderr live

"cancel" only changes a database row

lan_cancel signals the worker, which kills the whole process tree

a crashed worker strands the task

lease + reaper requeue it, with a new claim token

A remote agent physically cannot approve its own work: only the caller can call lan_review.


Related MCP server: Crosschat Relay

First: who is already on the LAN?

lanbus discover                 # local processes + services + local /24
lanbus discover --cidr 192.168.1.0/24 --json
lanbus discover --hub http://HUB:8788 --env windows

It combines three evidence sources:

  1. local processes — agent CLI and desktop processes (A agent CLI, B agent CLI, C agent desktop, local model runtimes, image/UI tools), matched by executable name and command line; on Windows it also reads running WSL processes (scope=wsl:<distro>);

  2. local listening ports — PID/process/port mapping;

  3. LAN scan + HTTP fingerprints — local model runtimes (/api/tags), OpenAI-compatible /v1/models, chat/web UIs, inference servers, notebook servers, browser DevTools, MCP serverInfo, lanbus /health, and FastAPI/OpenAPI AI APIs (/openapi.json).

A native Go scanner is included as Phase 0; Python falls back to the pure-Python scanner automatically. Build it once with make go-scan (or make go-scan-all for macOS/Linux cross-builds). The report includes engine: "go" or engine: "python".

A native Go worker is also available as Phase 1.5. It speaks the same hub protocol, streams logs, uploads artifacts, and handles lan_interrupt by killing the process tree:

bin/lanbus-worker --name go-win --env windows --hub http://HUB:8788   --token WORKER_TOKEN --cwd "D:\proj" --agent ADAPTER

Build with make go-worker / make go-worker-all. The Go worker now handles agent, shell, discover, and ask tasks, including native LAN discovery and OpenAI-compatible runtime calls. Browser tasks remain on the Python worker.

Add --pty to run agents on a real PTY (ConPTY on Windows, Unix PTY elsewhere):

bin/lanbus-worker --name tui --env tui --hub http://HUB:8788   --token TOKEN --cwd D:/proj --agent ADAPTER --pty

PTY mode keeps full-screen/TUI CLIs working and still uses the same Job Object/process-group cancellation.

Native Go hub (Phase 2)

A native hub subset is available as lanbusd:

make go-hub
bin/lanbusd --bind 127.0.0.1 --port 8789 --data-dir /tmp/lanbus-go   --token TOKEN --worker-token TOKEN

It implements the worker REST protocol (register/claim/progress/log/submit/recover), SQLite persistence, MCP lan_dispatch / lan_dispatch_many / lan_envs / lan_list / lan_result / lan_await / lan_logs / lan_review / lan_cancel / lan_interrupt / lan_artifact / lan_chat / lan_conversations / lan_discover / lan_ask / lan_shot, SSE /events, artifact storage, and /ui.

Dual-run is covered by tests/test_go_hub.py: the same Python fake worker runs against the Python hub and lanbusd, comparing status, exit code, verify flag, and task result. The Go hub is now the default on port 8788; the Python hub remains available as a fallback (lanbus hub / start-hub-python.cmd) for browser-task and legacy compatibility.

Local multi-agent chat

Start one worker per local agent - a Linux-side A agent CLI, a Windows-side B agent CLI, a C agent desktop, a WSL agent - each with its own env name, then let the hub relay a conversation:

lanbus worker --name win-a-cli --env win-a-cli --hub http://127.0.0.1:8788 --agent ADAPTER_A --cwd D:/proj
lanbus worker --name win-b-cli --env win-b-cli --hub http://127.0.0.1:8788 --agent ADAPTER_B --cwd D:/proj
lanbus worker --name win-c-ui  --env win-c-ui  --hub http://127.0.0.1:8788 --agent ADAPTER_C --cwd D:/proj

lanbus chat --envs win-a-cli,win-b-cli,win-c-ui --message "introduce your strongest capability" --rounds 2

The same feature is the MCP tool lan_chat (2–4 envs, 1–6 rounds) and POST /chat. Every turn is a normal lanbus task, so lan_logs, lan_result, lan_interrupt, and review still work on the individual turn.

Conversations are persisted. List them, read one, or continue it:

lanbus chat --list
lanbus chat --conversation c123abc --message "继续,总结刚才的结论" --rounds 1

MCP: lan_conversations(conversation_id=...). REST: GET /conversations, GET /conversations/<id>.

Web dashboard

The hub serves a zero-dependency dashboard at http://HUB:8788/ui (public HTML; APIs use the agent token):

  • online environments and capabilities

  • persisted conversation list and transcript

  • start a new 2–4 agent conversation

  • resume an existing conversation

The UI uses the same endpoints as MCP/CLI: GET /api/envs, GET /conversations, POST /chat.

Human confirmation for remote agents

Cross-machine targets require an explicit human approval before a task or conversation can start. The hub keeps local envs on the fast path and puts remote-target tasks in waiting_confirmation.

lanbus confirm list
lanbus confirm approve --env macos-a-cli --ttl 1800
lanbus confirm revoke --env macos-a-cli

The approval token is separate from the main-agent token:

~/.lanbus/operator-token.txt

The Web dashboard / GUI shows remote targets with hostname, agent, and cwd; use the "确认此 agent" button. The agent token cannot approve targets. For multiple agents in the same project, give each worker a different env and name, with the same or different --cwd; the human chooses the exact env in the approval panel.

Desktop GUI / tray (Windows)

make go-gui
bin/lanbus-gui.exe --hub http://127.0.0.1:8788

Wails/WebView2 window + tray menu. It embeds the same dashboard and proxies authenticated API calls to the running hub. Closing the window hides it to the tray; the tray menu reopens it, opens /ui in the default browser, or quits.

lanbus web          # open the dashboard in the default browser
lanbus gui          # launch bin/lanbus-gui.exe
make package        # portable Windows zip under dist/

The portable package and optional Inno Setup installer are under packaging/windows/. Signing (sign.ps1) and a SHA-256 update helper (update.ps1) are included.

Persistent local workers

lanbus local init          # write ~/.lanbus/local.json
lanbus local up            # start configured workers if their env is offline
lanbus local status
lanbus local down

local up skips workers whose env is already online, so it is safe to run from login startup. It supports Go workers, Python workers, and WSL entries ("wsl": "Ubuntu-24.04"). See examples/local/README.md.

No lanbus/MCP installation is required on the discovered machines. For endpoints that expose an HTTP API you can immediately query them:

lanbus ask --endpoint 192.168.1.50:11434 --prompt "用一句话介绍自己"
lanbus ask --endpoint 192.168.1.60:1234 --prompt "review this diff" --model qwen2.5

Important limit: a GUI-only agent that opens no port (a C agent desktop) can only be seen as a process on the machine where it runs. To see it from another machine, run a lanbus worker there or run lanbus discover on that host. Remote discovery is inherently limited to what the network exposes.

Quick start (3 minutes)

1. Hub — on the always-on machine (usually Windows)

pip install .
make go-hub
bin/lanbusd --bind 0.0.0.0 --port 8788 --data-dir ~/.lanbus   --token choose-a-secret --worker-token a-different-worker-secret

lanbusd is the default hub. The Python hub remains available for browser/legacy compatibility: lanbus hub --port 8789 ... (or start-hub-python.cmd).

--worker-token is optional. If omitted, workers use the same token as the main agent (simplest single-secret setup). With it, a worker token can only call /worker/*, never /mcp or /events; the agent token can still operate workers. For true per-worker identity, pass --worker-tokens '{"win-ui":"token1","wsl-core":"token2"}' (or --worker-tokens-file); a token then only works for its registered name.

New-NetFirewallRule -DisplayName "lanbus" -Direction Inbound -Protocol TCP `
  -LocalPort 8788 -Action Allow -Profile Private

Data (SQLite + artifacts + generated token) goes to ~/.lanbus. Override with LANBUS_DATA_DIR or --data-dir. TLS is available with --tls-cert / --tls-key.

Or with Docker:

LANBUS_TOKEN=... LANBUS_WORKER_TOKEN=... docker compose up -d

2. Worker — one per environment

# Windows
lanbus worker --name win-ui --env windows --hub http://HUB_LAN_IP:8788 `
  --token a-different-worker-secret --cwd D:\proj\webui --agent ADAPTER
# WSL
lanbus worker --name wsl-core --env wsl --hub http://HUB_LAN_IP:8788 \
  --token a-different-worker-secret --cwd /mnt/d/proj --agent ADAPTER
# macOS
lanbus worker --name mac-ui --env macos --hub http://HUB_LAN_IP:8788 \
  --token a-different-worker-secret --cwd ~/proj --agent ADAPTER

--agent selects a built-in adapter for a common agent CLI (see the adapter reference); shell runs the prompt as a command and echo is a connectivity check. --cmd accepts any CLI you already have: {prompt_file} expands to a temp file holding the prompt, otherwise the prompt goes to stdin. Use --cmd for a C agent desktop's bundled CLI, a vendor-specific wrapper, or an agent whose flags differ from the built-in adapters.

Each worker also gets:

  • Streaming logs — agent stdout/stderr is uploaded line by line; watch with lan_logs or lanbus logs --follow.

  • Real cancellation — lan_cancel signals the worker, which kills the whole process tree; late submissions are rejected by claim token.

  • Lease + auto-requeue — crash the worker mid-task and the hub requeues after the lease expires (default 120s, configurable per task).

  • Artifact upload — screenshots/logs are base64-uploaded to the hub, so separate machines no longer need a shared filesystem.

  • Browser helper — pip install playwright && playwright install chromium (or install Chrome/Edge) lets lan_shot click, fill forms and screenshot. lanbus doctor reports what is available.

  • Discovery — lanbus discover / lan_discover finds AI agents on the LAN without touching them; lan_ask can query OpenAI-compatible model endpoints directly.

  • Context handoff — context + local .lanbus/context.md + git state are composed into the prompt automatically.

3. Main agent — A agent CLI (or any MCP client)

cd your-project
cp -r /path/to/lanbus/integrations/mcp-client-preset/.mcp.json.example .mcp.json
# set HUB_LAN_IP + token, then point your MCP client at it
cp -r /path/to/lanbus/integrations/mcp-client-preset/agents   .mcp/agents
cp -r /path/to/lanbus/integrations/mcp-client-preset/commands .mcp/commands

integrations/mcp-client-preset is only a ready-made preset (sub-agent prompts and slash-command text) that you can adapt to your client. Any MCP client works: register http://HUB_LAN_IP:8788/mcp with the agent token and the same tools appear. Approve the project MCP server once when your client asks, then:

/lan windows change the login button radius from 4px to 12px, run npm run build, screenshot when green

It resolves the environment, dispatches, watches logs, reads verify_out and diff, judges, sends back with feedback if needed, and reports when accepted.

{
  "mcpServers": {
    "lanbus": {
      "type": "http",
      "url": "http://HUB_LAN_IP:8788/mcp",
      "headers": { "Authorization": "Bearer choose-a-secret" }
    }
  }
}

MCP tools

Tool

Purpose

lan_envs

online workers, caps (browser), available env values — call before dispatching

lan_dispatch

dispatch one task; context is composed into the prompt; wait_s>0 blocks until review

lan_dispatch_many

fan out to several environments in one call

lan_shot

browser task: URL + click/fill/evaluate actions + screenshot

lan_await

wait for tasks to reach a reviewable state

lan_result

full record: output, log tail, diff, changed, verify_out, artifacts; images as MCP image content

lan_logs

incremental real-time logs (since / wait_s long-poll)

lan_artifact

list/read artifacts; images and text returned inline

lan_discover

LAN AI-agent reconnaissance without preinstall: local processes + ports + HTTP fingerprints; env scans from a worker

lan_ask

send a prompt to a discovered OpenAI-compatible model endpoint and get its reply

lan_review

the gate: approve / rework (+feedback) / fail

lan_list

filter by status / env / kind

lan_cancel

cancel; stops the remote process tree

lan_interrupt

Ctrl+C-equivalent for a lanbus task: kill the worker process tree, independent of window focus/background state

Task states:

queued ──claim──► claimed ──► running ──submit──► submitted
  ▲                     │                         │
  │                     └─ lease lost ──► queued  ├─ approve ─► approved
  │                        (recoveries+1)         ├─ fail ────► failed
  └──────── rework (feedback, retry+1) ───────────┘
                                                  └─ cancel ──► cancelled

rework requeues with retry+1; past max_retry (default 2) the task becomes failed instead of looping forever. A lost worker lease requeues with recoveries+1; past max_recoveries (default 3) it fails. cancelled is terminal: the worker is signalled to kill its process tree, and any late submit carrying the old claim token is ignored.


HTTP surface (for scripts and dashboards)

All endpoints except /health require Authorization: Bearer <token>.

Method

Path

Purpose

GET

/health

status counts, no auth

GET

/events

SSE stream of task/worker/log events (Last-Event-ID supported)

GET

/tasks/<id>/logs?since=N

incremental execution logs

GET

/discover?cidr=...&ports=...

zero-preinstall discovery (also ?env=windows; /agents alias)

POST

/ask

prompt a discovered AI endpoint

GET

/artifacts/<task_id>/<name>

authenticated artifact download

POST

/mcp

MCP (stateless streamable HTTP)

POST

/worker/register

worker registration + capabilities

POST

/worker/claim

atomic claim; returns claim_token

POST

/worker/progress

lease renewal + cancellation poll

POST

/worker/log

batched streaming log lines

POST

/worker/submit

submit result + verify + diff + inline/base64 artifacts

POST

/worker/heartbeat

liveness + cancellation hints

POST

/worker/recover

worker restart hands back its lost tasks

Discovery itself is not a network listener on the scanned hosts: it runs on the hub/worker/CLI side and only probes standard TCP/HTTP surfaces.


Security

  • Two roles: agent token (--token) for MCP/read/artifacts; worker token (--worker-token) for /worker/* only. If no worker token is set, both roles share one token for backward compatibility. Optional per-worker tokens (--worker-tokens) bind a token to one worker name.

  • Worker ownership: submit/progress/log only work for the task currently assigned to that worker name and its random claim_token; a stale worker cannot resurrect a requeued/cancelled task.

  • Host header allowlist: only localhost/loopback and IP literals, which blocks DNS-rebinding style attacks (a hostname resolving to your LAN IP).

  • Optional TLS: --tls-cert + --tls-key on the hub; workers use normal verification, --ca FILE for a private CA, or --insecure only on a trusted LAN.

  • Workers are outbound-only — no listening port on Windows/WSL/macOS.

  • lanbus discover performs an active TCP/HTTP scan. Run it only on networks you are allowed to inspect; it does not exploit services or modify remote state.

  • Do not publish port 8788 to the internet. For cross-network use, put it behind WireGuard/Tailscale.


Reliability model

  • Execution transport: prefer worker tasks (lan_dispatch) over UI keystroke injection. Worker tasks have a process tree, a claim token, and a real cancellation path; UI automation only observes/notifies a desktop and is not the execution mechanism.

  • Ctrl+C: lan_cancel / lan_interrupt sets a cancellation flag; the worker kills the whole process tree (Windows Job Object or POSIX process group). This works while the window is unfocused or the task is in the background.

  • Lease: claim sets lease_expires_at; the worker renews every ~3s via /worker/progress while the agent, verify command, or browser runs.

  • Reaper: hub requeues expired claimed/running tasks, up to max_recoveries; then fails them with evidence.

  • Claim token: every claim gets a random token; submits from the old execution are rejected after requeue/cancel.

  • Outbox: if the hub is unreachable when a task finishes, the worker writes the submission under ~/.lanbus/outbox/<name>/ and retries until accepted. If the lease expired meanwhile, the hub still accepts the late result while the task is queued and not yet re-claimed.

  • Logs: streamed in batches; sequence numbers make retries idempotent. A local copy is kept under ~/.lanbus/logs/.


Context handoff

A remote agent is a fresh CLI process, so lanbus composes a self-contained prompt:

  1. task id / env / cwd / kind / retry / verify / artifact globs;

  2. context you pass to lan_dispatch (background, paths, constraints, acceptance criteria);

  3. worker-local .lanbus/context.md, .lanbus/rules.md, optional --context-file, plus git branch/status;

  4. your prompt;

  5. previous feedback;

  6. non-interactive execution rules.

lan_result returns the exact composed prompt, so you can see what the remote agent actually received.


Known limits

  1. Conversation context is not magically shared. lanbus injects structured context, local .lanbus/context.md, and git state, but if a detail only exists in your local chat you must pass it explicitly.

  2. Workers use each CLI's non-interactive one-shot mode (-p / exec / headless); anything needing interactive approval fails instead of prompting. Put the required permission mode or pre-authorization in that CLI's own config. Built-in adapters already pass a non-interactive permission mode where the CLI supports one.

  3. If WSL uses /mnt/d/... and Windows uses D:\..., that is one filesystem — no syncing needed, but concurrent edits to the same file will collide. Partition tasks by file.

  4. WSL→Windows needs either mirrored networking (networkingMode=mirrored in .wslconfig, then wsl --shutdown) or the host IP, which changes across reboots.

  5. Headless browser fallback only supports goto + screenshot. Click/fill/evaluate requires Playwright (pip install playwright && playwright install chromium).

  6. Browser tasks require a worker with a browser capability; lan_envs reports has_browser and caps.

  7. Remote discovery can only see hosts that answer on scanned TCP ports or expose an HTTP(S) API. GUI-only agents are visible only in local process scans; run a lanbus worker or lanbus discover on that host for full coverage. Port 443 is fingerprinted over HTTPS; custom HTTPS ports are not probed by default.

  8. Discovery is heuristic: a port can be open for unrelated software, and an OpenAI-compatible endpoint may be an inference server rather than a full tool-using agent. Verify before sending sensitive prompts.

  9. An agent CLI on macOS needs a worker running on the Mac (--agent ADAPTER or --cmd) or a local lanbus discover; a Windows scanner cannot see a GUI/CLI process on the Mac without one of those. macOS Local Network permission must allow Terminal/the worker.

  10. UI-only desktop windows have no stable programmable input/interrupt API. lanbus uses CLI/headless/worker for task execution; GUI automation is best-effort notification only.

macOS worker

If an agent CLI is already installed on macOS but is not reachable from Windows, it has no worker. Run this on the Mac:

export PATH="$HOME/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"
lanbus doctor
lanbus worker --name mac-a-cli --env macos --hub http://HUB_LAN_IP:8788 --token WORKER_TOKEN --cwd /Users/me/proj --agent ADAPTER

Or use the native Go worker without Python: bin/lanbus-worker-darwin-arm64 (Apple Silicon) or bin/lanbus-worker-darwin-amd64, with the launchd template examples/macos/com.lanbus.worker-go.plist (native Go worker) or examples/macos/com.lanbus.worker.plist (Python worker); set ADAPTER and paths.

Or run examples/macos/start-worker.sh in the foreground for a quick self-check. After it connects, lan_envs shows mac-a-cli with the adapter capability, and lan_dispatch(env="macos", ...) runs in the current project. lan_discover from Windows can only see the Mac's open ports; process-level agent detection happens on the Mac via its worker or local lanbus discover.


Development

pip install -e ".[dev]"
pytest -v                     # 39 tests: protocol, dispatch/rework, logs, cancel/interrupt, lease recovery, artifacts, roles, discovery, chat, web UI, local supervisor, Go hub tools/dual-run, remote confirmation
make go-test                  # Go scanner + worker tests
make go-scan                  # native bin/lanbus-scan; Python auto-detects it
make go-worker                # native bin/lanbus-worker
python -m pip wheel . --no-deps --no-build-isolation -w dist

Tests spin up a real hub and real workers on free ports and drive actual MCP JSON-RPC — no mocks.

Docs

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables coding agents from different vendors on the same machine to delegate tasks to each other over the A2A protocol, while also allowing the machine to act as an A2A peer.
    7
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Lets AI agents in different harnesses hand each other concrete tasks, claim and report on them, and continue after restarts via a live dashboard and unattended workers.
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    Enables a host coding agent to launch and coordinate real subagent sessions in other agent CLIs and accounts, sharing existing MCP servers, skills, plugins, and instructions. Supports two-way messaging, automatic account failover, and mixed-CLI delegation while leaving credentials with the vendor CLIs.
    8
    11
    Apache 2.0