{
  "markdown": "# Claude Bridge\n\n<!-- mcp-name: io.github.constripacity/claude-code-bridge -->\n\n**A local-first, cross-machine message bus for independent coding agents.**\n\n[![CI](https://github.com/constripacity/Claude-Bridge/actions/workflows/ci.yml/badge.svg)](https://github.com/constripacity/Claude-Bridge/actions/workflows/ci.yml)\n![Python](https://img.shields.io/badge/python-3.10%E2%80%933.13-blue)\n![License](https://img.shields.io/badge/license-MIT-green)\n![MCP](https://img.shields.io/badge/MCP-Streamable_HTTP-orange)\n\nClaude Bridge lets coding-agent sessions on different machines exchange\nordered messages through named channels. The relay is self-hosted, uses SQLite\nby default, and exposes MCP, a small JSON API, a dashboard, and a terminal UI.\n\nIt does not call a model API and does not require agents to share a filesystem\nor process. Claude Code motivated the project, but the core is MCP-based and is\nnot coupled to Anthropic.\n\n> **Forward-build notice:** this source tree identifies as `1.2.0.dev1`. It is\n> a development build beyond the latest stable PyPI release. Review the\n> [changelog](https://github.com/constripacity/Claude-Bridge/blob/main/CHANGELOG.md)\n> and [0.9-to-1.2 migration guide](https://github.com/constripacity/Claude-Bridge/blob/main/docs/MIGRATING-0.9-TO-1.2.md)\n> before replacing a stable deployment.\n\n## Why use it?\n\n- Keep agents on Windows, macOS, Linux, or a remote host in their own sessions.\n- Send work, results, review requests, and artifact references without remote\n  shell access.\n- Use durable history and consumer cursors to recover after a client restart.\n- Retry sends safely with an idempotency key.\n- Observe the same relay through MCP, a browser dashboard, the TUI, or REST.\n- Run locally or across a private LAN/tailnet with an explicit security policy.\n\nClaude Bridge is a transport, not an autonomous orchestrator. Receiving a\nmessage never authorizes an agent to execute it.\n\n## Transports\n\n| Interface | Path or command | Purpose |\n|---|---|---|\n| MCP Streamable HTTP | `/mcp` | Recommended remote MCP transport |\n| MCP stdio | `claude-bridge --stdio` | Local subprocess transport |\n| Legacy MCP HTTP+SSE | `/sse` and `/messages/` | Existing configurations during migration |\n| Channel event SSE | `/events/channel/<channel>` | Dashboard, TUI, and custom listeners; not MCP |\n| JSON API | `/api/*` | Browser, scripts, and integrations |\n\nThe automated suite performs a real MCP SDK handshake against `/mcp`. Vendor\nclients are not launched in CI. See the evidence-based\n[compatibility matrix](https://github.com/constripacity/Claude-Bridge/blob/main/docs/COMPATIBILITY.md).\n\n## Architecture\n\n```mermaid\nflowchart TB\n    A[\"Claude Code / Codex / MCP client\"] -->|\"Streamable HTTP /mcp\"| B[\"Claude Bridge\"]\n    C[\"Local MCP client\"] -->|\"stdio\"| B\n    D[\"Dashboard / TUI / script\"] -->|\"REST + event SSE\"| B\n    B --> E[(\"SQLite\")]\n```\n\nMessages and live-notification records are committed to SQLite in one\ntransaction. HTTP processes poll that durable outbox (500 ms by default), so a\nwrite from a separate stdio process is propagated to connected dashboard/TUI\nevent streams. Durable channel history remains authoritative across restarts.\n\n## Install\n\n```bash\npython -m pip install claude-code-bridge\n```\n\nInstall the terminal UI as well:\n\n```bash\npython -m pip install \"claude-code-bridge[tui]\"\n```\n\nThe PyPI distribution is named `claude-code-bridge` because `claude-bridge`\nwas already assigned to an unrelated project. The command and Python package\nremain `claude-bridge` and `claude_bridge`.\n\nFrom a source checkout:\n\n```bash\ngit clone https://github.com/constripacity/Claude-Bridge.git\ncd Claude-Bridge\npython -m pip install -e \".[dev]\"\n```\n\n## Start safely\n\nLocal-only HTTP mode is the default:\n\n```bash\nclaude-bridge\n```\n\nThis listens on `127.0.0.1:8765`. Open `http://127.0.0.1:8765/` for the\ndashboard or connect an MCP client to `http://127.0.0.1:8765/mcp`.\n\nLocal stdio mode does not open a network listener:\n\n```bash\nclaude-bridge --stdio\n```\n\n### Cross-machine server\n\nNetwork binding is deliberately fail-closed. Supply the address clients put in\ntheir URL as a trusted host and require a token:\n\n```bash\nexport CLAUDE_BRIDGE_AUTH_TOKEN=\"$(openssl rand -hex 32)\"\nclaude-bridge \\\n  --host 0.0.0.0 \\\n  --trusted-host 100.64.0.10\n```\n\nHere `100.64.0.10` might be the server's tailnet address. A DNS deployment\nwould use a value such as `bridge.example.internal`. `--trusted-host` values\nare hostnames or IP addresses, without a URL scheme or path, and the option is\nrepeatable.\n\nTwo independent checks are required:\n\n1. `--trusted-host` controls which HTTP Host names are accepted; and\n2. the Bearer token controls who can use protected endpoints.\n\nFor a deliberately unauthenticated private test network, replace the token\nwith `--allow-unauthenticated-network`. That is an explicit risk acceptance,\nnot the recommended production setup.\n\nUse `--tls-cert` and `--tls-key`, an HTTPS reverse proxy, or an encrypted\noverlay network before sending sensitive content across an untrusted network.\nSee the [security policy](https://github.com/constripacity/Claude-Bridge/blob/main/SECURITY.md)\nfor the complete trust model.\n\n### Container\n\nThe official image also fails closed. A network deployment must provide its\ntrusted host and authentication policy:\n\n```bash\nexport CLAUDE_BRIDGE_AUTH_TOKEN=\"$(openssl rand -hex 32)\"\ndocker run --rm -p 8765:8765 \\\n  -v claude-bridge-data:/data \\\n  -e CLAUDE_BRIDGE_AUTH_TOKEN \\\n  -e CLAUDE_BRIDGE_TRUSTED_HOSTS=\"100.64.0.10\" \\\n  ghcr.io/constripacity/claude-bridge:latest\n```\n\nThe SQLite database is stored in `/data`. Release images use exact and\nmajor/minor tags; `edge` tracks `main`.\n\n## Connect a client\n\n### Claude Code\n\nRemote Streamable HTTP:\n\n```bash\nclaude mcp add --transport http -s user claude-bridge \\\n  http://127.0.0.1:8765/mcp\n```\n\nLocal stdio:\n\n```bash\nclaude mcp add -s user claude-bridge -- claude-bridge --stdio\n```\n\nFor a protected remote endpoint, attach the matching Authorization header\nusing the option supported by the installed Claude Code version. Legacy\nconfigurations can continue to target `/sse` with `--transport sse` while they\nmigrate.\n\n### Codex\n\nLocal stdio in `~/.codex/config.toml`:\n\n```toml\n[mcp_servers.claude_bridge]\ncommand = \"claude-bridge\"\nargs = [\"--stdio\"]\n```\n\nRemote Streamable HTTP:\n\n```toml\n[mcp_servers.claude_bridge]\nurl = \"http://127.0.0.1:8765/mcp\"\nbearer_token_env_var = \"CLAUDE_BRIDGE_AUTH_TOKEN\"\n```\n\nThese examples follow the transports each client documents. The repository's\nCI verifies MCP protocol behavior, not a full vendor-client launch. See\n[compatibility matrix](https://github.com/constripacity/Claude-Bridge/blob/main/docs/COMPATIBILITY.md)\nbefore making support claims.\n\n## MCP tools\n\n| Tool | Purpose |\n|---|---|\n| `bridge_send` | Send legacy text or a protocol-v1 message; supports idempotent retries |\n| `bridge_receive` | Read a bounded page using a message cursor or durable consumer cursor |\n| `bridge_wait` | Wait up to 55 seconds for new messages without rapid polling |\n| `bridge_ack` | Monotonically advance a consumer's channel-scoped cursor |\n| `bridge_channels` | List active channels and counts |\n| `bridge_ping` | Check bridge health and capabilities |\n| `bridge_status` | Summarize recent activity across channels |\n| `bridge_clear` | Delete every message (and task) in one channel |\n| `bridge_enqueue` | Add a task to a channel's work queue (exclusive; claimed once) |\n| `bridge_claim` | Atomically claim the next task with a lease; long-poll with `wait_seconds` |\n| `bridge_complete` | Mark a claimed task done, fenced by its `lease_token` |\n| `bridge_fail` | Fail a claimed task — requeue with backoff, or dead-letter |\n| `bridge_tasks` | Inspect a channel's queue: per-status counts and a task list |\n\nTool results include structured data for clients that support MCP structured\ncontent and a readable text representation for compatibility.\n\n### Reliable task/result example\n\nThe orchestrator sends a structured task with a stable retry key:\n\n```text\nbridge_send(\n  channel=\"payments:worker\",\n  sender=\"windows-orchestrator\",\n  idempotency_key=\"job-802-task\",\n  message={\n    \"schema_version\": 1,\n    \"type\": \"task\",\n    \"content\": {\"action\": \"run_tests\", \"target\": \"payments\"},\n    \"thread_id\": \"payments-42\",\n    \"correlation_id\": \"job-802\"\n  }\n)\n```\n\nThe worker waits using its persisted consumer identity:\n\n```text\nbridge_wait(\n  channel=\"payments:worker\",\n  consumer_id=\"mac-worker\",\n  timeout_seconds=20\n)\n```\n\nAfter applying the task successfully, it advances its cursor:\n\n```text\nbridge_ack(\n  channel=\"payments:worker\",\n  consumer_id=\"mac-worker\",\n  message_id=\"<processed-message-id>\"\n)\n```\n\nIt can then send a result to a return channel using the same `thread_id` and\n`correlation_id`. Acknowledgement supplies at-least-once processing semantics;\nit does not make arbitrary external side effects exactly once.\n\nThe complete envelope, retry, cursor, and retention contract is documented in\n[protocol reference](https://github.com/constripacity/Claude-Bridge/blob/main/docs/PROTOCOL.md).\n\n### Task queue (work distribution)\n\nMessages fan out — every consumer cursor sees every message. A **task queue** is\nthe opposite: each task is claimed by exactly one worker. Point a fleet of worker\nagents at a channel and they share the work without ever double-processing it.\n\nThe orchestrator enqueues tasks (dedup-safe with an idempotency key):\n\n```text\nbridge_enqueue(\n  channel=\"builds\",\n  payload={\"repo\": \"payments\", \"action\": \"run_tests\"},\n  max_attempts=3,\n  idempotency_key=\"build-802\"\n)\n```\n\nEach worker claims the next task, holding a lease (a visibility timeout). Two\nworkers never get the same task; `wait_seconds` long-polls an empty queue:\n\n```text\nbridge_claim(channel=\"builds\", consumer=\"worker-3\", lease_seconds=300, wait_seconds=20)\n# -> { task_id, payload, attempts, lease_token, lease_expires_at }\n```\n\nIt finishes before the lease expires — `complete` on success, `fail` to retry —\nboth fenced by the `lease_token`, so a reclaimed task can't be clobbered:\n\n```text\nbridge_complete(channel=\"builds\", task_id=\"tsk_…\", lease_token=\"…\", result={\"passed\": 105})\nbridge_fail(channel=\"builds\", task_id=\"tsk_…\", lease_token=\"…\", requeue=true, retry_delay_seconds=30)\n```\n\nIf a worker crashes and never resolves its task, the lease expires and the task\nis requeued automatically — or dead-lettered once `max_attempts` is exhausted.\nThis is **at-least-once** delivery, so make task handlers idempotent.\n`bridge_tasks(channel=\"builds\")` shows the queue's per-status counts.\n\n## Channels\n\nChannels are created on first write. A readable convention is\n`<project>:<purpose>`:\n\n```text\npayments:orchestrator\npayments:worker\npayments:events\npayments:review\ngeneral:status\n```\n\nA channel name is routing, not authorization. In the current shared-token\nmodel, any authorized client can read, write, or clear any channel.\n\n## Dashboard, TUI, and JSON API\n\nThe dashboard is served at `/` unless `--no-dashboard` is used. It consumes the\nJSON API and the per-channel event stream. Its React application, fonts, and\nother runtime assets are bundled with the package, so loading the dashboard\ndoes not contact a third-party CDN. A restrictive Content Security Policy is\napplied to the static application.\n\nRun the TUI:\n\n```bash\npython -m claude_bridge.tui\npython -m claude_bridge.tui \\\n  --url http://100.64.0.10:8765 \\\n  --sender mac\n```\n\nThe TUI reads `CLAUDE_BRIDGE_AUTH_TOKEN` from the environment, keeping the\nsecret out of the process command line.\n\nCore HTTP endpoints:\n\n| Endpoint | Purpose |\n|---|---|\n| `GET /status` | Minimal unauthenticated health check |\n| `GET /api/state` | Channel counts, senders, version, and uptime |\n| `GET /api/messages?channel=X&since_id=Y&limit=N` | Bounded channel history |\n| `GET /api/messages/{id}` | One message detail |\n| `GET /api/wait?channel=X&consumer_id=Y` | Bounded long poll using a consumer or message cursor |\n| `POST /api/send` | Send legacy text or a protocol-v1 message, with optional idempotency |\n| `POST /api/ack` | Advance one durable consumer cursor |\n| `POST /api/clear` | Clear one channel |\n| `GET`, `POST`, `DELETE /api/session` | Inspect, create, or revoke an opaque dashboard session |\n| `GET /api/audit?limit=N` | Recent audit events when enabled |\n| `GET /events/channel/<channel>` | Live event stream with bounded replay |\n\nThe event stream can drop a slow subscriber after its buffer fills; durable\nhistory remains authoritative. Reconnect with the last message ID and honor\n`cursor_stale` or `replay_truncated` by fetching history explicitly.\n\n## Authentication and browser boundaries\n\nSet `CLAUDE_BRIDGE_AUTH_TOKEN`, `--auth-token-file`, or `--auth-token`. The\nliteral CLI form can appear in process listings; the environment variable or a\npermission-restricted file is preferred.\n\nWhen enabled, protected REST, MCP, and event endpoints require:\n\n```text\nAuthorization: Bearer <token>\n```\n\n`/status` remains public and deliberately contains minimal information. The\nstatic dashboard shell may be reachable, but protected data APIs still require\nthe token.\n\nUnsafe browser mutations are restricted by Origin, JSON endpoints require a\nJSON media type, and Host headers are allowlisted. Extra browser origins are\nconfigured independently with repeatable `--cors-origin` flags.\n\nThe dashboard submits the Bearer token once to `POST /api/session` and receives\na short-lived opaque `HttpOnly`, `SameSite=Strict` cookie. The master token is\nnot written to local storage or a URL. Event streams authenticate with that\ncookie; `?token=` query authentication is rejected. Logging out revokes the\nsession, and a server restart invalidates all in-memory dashboard sessions.\n\n## Configuration\n\n| CLI/environment | Default | Purpose |\n|---|---|---|\n| `--host` | `127.0.0.1` | HTTP bind interface |\n| `--port` | `8765` | HTTP port |\n| `--db` / `CLAUDE_BRIDGE_DB` | `./claude-bridge.db` | SQLite path |\n| `--trusted-host` / `CLAUDE_BRIDGE_TRUSTED_HOSTS` | loopback hosts | Accepted Host names/IPs |\n| `--auth-token-file` / `CLAUDE_BRIDGE_AUTH_TOKEN` | unset | Shared Bearer authentication |\n| `--allow-unauthenticated-network` | off | Explicit non-loopback auth bypass |\n| `--cors-origin` / `CLAUDE_BRIDGE_CORS_ORIGIN` | same-origin only | Additional browser origins, including another localhost port |\n| `--tls-cert` + `--tls-key` | unset | Direct HTTPS listener |\n| `--retention-days` / `CLAUDE_BRIDGE_RETENTION_DAYS` | `0` | Delete messages older than N days; `0` keeps them |\n| `--audit-log` / `CLAUDE_BRIDGE_AUDIT_LOG` | off | Record security-relevant events |\n| `CLAUDE_BRIDGE_AUDIT_RETENTION_DAYS` | `90` | Bound audit history |\n| `CLAUDE_BRIDGE_SESSION_TTL_SECONDS` | `28800` | Opaque dashboard-session lifetime |\n| `CLAUDE_BRIDGE_EVENT_POLL_MS` | `500` | Cross-process outbox polling interval |\n| `CLAUDE_BRIDGE_EVENT_RETENTION_DAYS` | `7` | Retain delivered outbox records |\n| `--no-dashboard` | off | Do not mount browser assets |\n| `CLAUDE_BRIDGE_MAX_REQUEST_BYTES` | `262144` | Maximum HTTP request body |\n| `CLAUDE_BRIDGE_MAX_MESSAGE_BYTES` | `131072` | Maximum encoded message |\n| `CLAUDE_BRIDGE_MAX_SSE` | `100` | Total channel-event subscribers |\n| `CLAUDE_BRIDGE_MAX_SSE_PER_CHANNEL` | `25` | Subscribers on one channel |\n| `CLAUDE_BRIDGE_SSE_REPLAY_LIMIT` | `500` | Reconnect backlog cap |\n| `CLAUDE_BRIDGE_STATELESS_HTTP` | off | Use stateless Streamable HTTP sessions |\n\nCLI values take precedence where a matching flag exists. Invalid numeric or\nboolean environment values fail during startup with a configuration error.\n\n## Persistence and operational limits\n\n- SQLite runs in WAL mode and is suitable for a personal or small-team relay.\n- The server is not currently a multi-node or high-availability message broker.\n- One HTTP worker plus cooperating stdio processes can share the WAL database;\n  the durable outbox propagates their live events. This remains a small-scale\n  SQLite design, not a multi-node or enterprise broker.\n- Retention can invalidate old cursors. Important work products belong in a\n  repository or artifact store, not only in bridge history.\n- The shared Bearer token does not provide identity or per-channel permissions.\n- No benchmark claim is made without a reproducible benchmark and environment.\n\nThe future operations and authorization milestones are in\n[roadmap](https://github.com/constripacity/Claude-Bridge/blob/main/docs/ROADMAP.md).\n\n## Development\n\n```bash\npython -m pip install -e \".[dev]\"\nruff check claude_bridge tests\npytest -v\npython -m build\n```\n\nCI tests Linux across Python 3.10–3.13 and runs current-version smoke jobs on\nWindows and macOS. The real-socket MCP test covers initialization, tool listing,\nsend, receive, wait, and acknowledgement through the official SDK. A separate\njob builds the sdist and wheel, validates their metadata, installs each artifact\ninto a clean environment, and checks the CLI.\n\nRead the [contribution guide](https://github.com/constripacity/Claude-Bridge/blob/main/CONTRIBUTING.md)\nbefore proposing a new capability. For a vulnerability, use the private process\nin the [security policy](https://github.com/constripacity/Claude-Bridge/blob/main/SECURITY.md),\nnot a public issue.\n\n## Roadmap\n\nThe current sequence is:\n\n1. `1.2` — secure Streamable HTTP, structured messages, idempotency, and durable\n   consumers;\n2. `1.3` — native client diagnostics and an experimental Claude Channels\n   companion;\n3. `1.4` — individual identities, scopes, ACLs, quotas, and token rotation;\n4. `1.5` — observability, operational tooling, and an optional scalable\n   backend; and\n5. `2.0` — federation and an optional A2A adapter if real usage demands them.\n\nEach milestone and its non-goals are defined in the\n[roadmap](https://github.com/constripacity/Claude-Bridge/blob/main/docs/ROADMAP.md).\n\n## License\n\nMIT — see the [license](https://github.com/constripacity/Claude-Bridge/blob/main/LICENSE).\n\nFounded and maintained by **Constripacity**.\n",
  "bytes": 17978,
  "sha": "9626fee15b372686fac1df84a499bd1f201b635b7ddde7d6fe7a7027db274799",
  "repo_slug": "constripacity/claude-bridge",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_constripacity_claude_code_brid_6acffab3/readme"
}