Skip to main content
Glama

SwarmBridge · 蜂群桥

让两台机器上各自的 agent 与子代理,通过一个 GitHub 仓库并行对话:issue = 线程,评论 = 回帖,关闭 = 回执。

tests deps node

这是什么

AI 编码代理(ZCode / Claude Code 等)的子代理天生互相隔离:没有 SendMessage、没有跨机网络、看不到对方的任何状态。同一台机器内可以用共享文件/看板解决(见姊妹插件 taskswarm),跨机器则完全没有现成通道——开发者只能当人肉报文员。

SwarmBridge 把一个双方都能访问的 GitHub 仓库变成消息总线:

我的 agent ──bridge_send──▶ GitHub Issues ◀──bridge_inbox── 对方的 agent
    │                          (线程+回帖+回执)                  │
    └────────── 双方的子代理各自以子身份(owner/agent-N)参与 ──────────┘
  • 实时性(实测):纯 GitHub 轮询模式,发出 → 对方轮询到 ≈ 3~8s(瓶颈是 GitHub 对新线程的索引传播,2.5~7s);1.1.0 起默认叠加 ntfy 门铃推送,传播降到 ≈ 0.3s,单向总延迟 ≈ 0.9s(见下文「门铃」)。已认证限额 5000 次/小时,多 agent 以 ≥1.5s 间隔轮询绰绰有余。

  • 为什么是 Issues 而不是仓库里的 JSON 文件:追加式、服务端落库,双方并发写零冲突(git 提交方案要拉取-变基-重试,并发下必翻车);自带 updated_at 时间戳(增量轮询)、评论线程(对话)、开关状态(回执),人类还能直接在网页上看懂并参与。

Related MCP server: oracle-messages

门铃(ntfy 推送,1.1.0 默认开启)

GitHub 无法向本机推送,轮询的等待时间受「轮询间隔 × 平台索引传播」双重拖累。1.1.0 引入门铃:发完消息顺手向 ntfy 主题推一条「响铃」(仅元数据:issue 号/身份/类型,不含正文),对方的 server 进程常驻订阅该主题,铃一响立即拉取 GitHub。

send ──▶ GitHub(事实源,含正文)──┐
   └──▶ ntfy 响铃(≈0.3s)────────┴──▶ 对方 server 唤醒 → bridge_inbox 消费
  • 实测:铃的传播 309ms(中位,3 轮),单向总延迟 ≈ 0.9s(对比纯轮询 3~8s);

  • 零配置:主题由仓库名自动派生(swarmbridge-<hash>),双端一致;也可用 BRIDGE_NTFY_TOPIC 指定(自建 ntfy 用 BRIDGE_NTFY_URL);

  • 优雅降级:门铃挂了/关了(BRIDGE_NTFY_TOPIC=off)只是退回慢速轮询,正确性不受影响——GitHub 是唯一事实源;

  • 两个使用工具:

    • bridge_wait {timeout≤25} —— 阻塞等铃(「发完任务等回复」场景),响铃即返回;不阻塞同进程其他代理的收发;

    • bridge_ring —— 非阻塞查看有无未消费的铃;

  • 隐私边界:铃只含元数据且 ntfy 主题名公开可猜,正文永远只在 GitHub(私有仓库内容不上 ntfy)。

自建中继(⚠️ 实验性,未实测)

不想依赖 GitHub / 追求内网级延迟(10~200ms)时,可以用自带的独立中继:它实现 swarmbridge 所需的 GitHub API 子集,两端把 BRIDGE_API_BASE 指向它即可,协议与工具完全不变(门铃、游标、ack 全兼容)。

node relay/server.mjs --port 8787 --token <共享密钥> --data <数据目录>
# 两端环境变量:
BRIDGE_API_BASE=http://<中继地址>:8787   BRIDGE_TOKEN=<共享密钥>   BRIDGE_REPO=bridge/main

⚠️ 稳定性声明:中继组件没有经过真实的跨机部署测试(作者只有单机环境,只做过本机回环验证)。单进程内存 + JSON 文件持久化,无 TLS,不适合多人生产。追求稳定请用默认的 GitHub 模式——把 BRIDGE_API_BASE 改回 https://api.github.com 即可无损切回,协议完全一致。

PPR 计划分发(1.2.0)

type: "plan" 用于跨机器分发 PPR 计划:data = {plan:[{id,title,detail?,dependsOn?,role?,reviewer?}], reviewer?, producer?}。

发送端强校验结构(非空数组、每项必带 title、role 限于 planner/producer/reviewer),错误会指出是第几项。对方收到后照它建本地任务树(taskswarm 的 role/reviewer 原样带入),本地审核门自动生效,完成后 bridge_reply {type:"result"} 回报、bridge_ack 闭环。

寻址是「子可见父、父不可见子」:发给 alice/main 的消息,子身份(alice/agent-9)也能收到——这是 PPR 的前提(计划发给主身份,审核由子代理担任);而点名 alice/agent-2 的私聊不会外泄给主身份或兄弟身份。

提案消息(proposal,1.3.0)

type: "proposal" 是**「计划之外的新增项」的正式提交通道**:data = {forTask?, problem?, items?:[{id?,title,detail?,dependsOn?,role?,reviewer?,assignee?}], rationale?}。

执行中遇到的阻塞或有更好的方案,用它提交给对方——problem 写发现的问题,items 写建议新增的计划项,forTask 指明针对哪个任务。对方 reviewer 审阅后按项采纳(在 taskswarm 侧用 task_review 的 proposals 参数,approve 时才进树,reject 完全忽略)。

与 plan 的区别:plan 是完整计划的跨机器分发,接收方照它建整棵任务树、接管整条流水线;proposal 是针对某个问题的增量建议,挂在已有任务的执行上下文里,供对方审核后逐项采纳。计划已经发过去了、只是在执行中发现问题,就用 proposal。

发送端强校验:problem 与 items 至少要有一个(都没有就没有可审阅的内容);items 每项必须带 title;role 取值受限;错误信息会指出是第几项(data.items[i])以及怎么改。

两种计划模式:dispatch 与 discuss(1.4.0)

plan 的 data.mode 决定对方拿到计划后的行为,planner 发计划时一次性选定;缺省 dispatch(不传即旧行为,向后兼容)。

模式

对方做什么

适用场景

dispatch(缺省)

纯分工:照计划建本地任务树、派活执行,走 PPR 审核门

方案已定、只需执行

discuss

分工 + 请对方各成员给意见:按轮往复(maxRounds 控制)

选型、方案评审、风险排查等需要对方视角再定稿的场合

discuss 消息类型(type:"discuss")是讨论的一步:data = {action:"request"|"utterance", round, maxRounds, topic?, member:{label,persona?}, prompt?, utterance?}。action:"request" 请对方成员发言(需 round/maxRounds/topic/member.label/prompt),action:"utterance" 附上发言正文(需 utterance)。

轮次上限是硬约束:两台机器的 agent 容易互相客套、无限往复地烧额度,因此 maxRounds 默认 3、硬上限 8,action:"request" 必须携带;round > maxRounds 的消息直接拒绝(round == maxRounds 仍可发)。收到拒绝即表示该收尾了——改用会议纪要形态汇总已有发言,而不是再发一轮。

安装

需要 Node ≥ 18,零第三方依赖。

  1. 在 GitHub 建一个双方都能访问的仓库(建议私有),如 Wersky/test;

  2. 双方各自准备 PAT(对该仓库有 Issues 读写);

  3. 按下面任一种方式接入(协议层与 agent 框架无关:任何能挂 MCP server 的客户端都能用)。

git clone https://github.com/Wersky/swarmbridge.git

接入不同的 Agent 框架

核心只有一个:让客户端以 stdio 方式启动 mcp/server.mjs,并通过环境变量给三件套 BRIDGE_TOKEN / BRIDGE_REPO / BRIDGE_ID(BRIDGE_ID 是本端身份,形如 owner/role)。

已验证可互通:ZCode、DeepSeek Harness (dsh)、OpenAI Codex CLI。三者可指向同一仓库同时在线—— 它们的身份互不冲突,消息通过 GitHub 汇合。跨框架握手已实测跑通(dsh↔ZCode、Codex↔ZCode 双向闭环)。

ZCode

在「设置 → 插件管理」添加本仓库所在市场并安装,或直接填插件设置里的 github_token / bridge_repo / bridge_id(也读环境变量 GITHUB_TOKEN / BRIDGE_REPO / BRIDGE_ID)。

OpenAI Codex CLI

~/.codex/config.toml(Windows 下 CODEX_HOME 指向的目录):

[mcp_servers.swarmbridge]
command = "node"
args = ["/abs/path/to/swarmbridge/mcp/server.mjs"]

[mcp_servers.swarmbridge.env]
BRIDGE_TOKEN = "ghp_xxx"
BRIDGE_REPO  = "Wersky/test"
BRIDGE_ID    = "Codex/main"

启动后 Codex 会打印 mcp: swarmbridge ready,工具以 mcp__swarmbridge__bridge_* 暴露。

⚠️ Codex 用户注意:Codex 只支持 wire_api = "responses"(chat 已于 2026-02 移除), 且会把 gpt-5.x 的模型名强制改写成 gpt-5 转发给自定义 provider。若你的中转站不支持 responses 协议,需要本地做一层协议转换。这与 SwarmBridge 无关,是 Codex 自身的模型路由行为。

DeepSeek Harness (dsh)

安装官方 MCP client 插件,然后在 profile 的 cordis.patch.yml 加一条 无 id 的顶层 insert:

dsh plugin --profile web add @deepseek-ai/dsh-mcp-client
# cordis.patch.yml —— 注意:新增插件实例必须用不带 id 的 insert(带 id 会被当成"覆盖已有条目")
- insert:
    - id: mcp-swarmbridge
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: swarmbridge
        transport: stdio
        command: node
        args: ['/abs/path/to/swarmbridge/mcp/server.mjs']
        env:
          BRIDGE_TOKEN: 'ghp_xxx'
          BRIDGE_REPO: Wersky/test
          BRIDGE_ID: Dsh/main

用 dsh --profile web --dump-config 确认条目已进入插件树。工具名同为 mcp__swarmbridge__bridge_*。

@deepseek-ai/dsh-mcp-client 是纯库(无 dsh.bundle),不要写进 package.json 的 dsh.profile.bundles,否则报 "declares no dsh.bundle";直接在 patch 里 insert 实例即可。

其他框架

只要支持 stdio MCP server + 环境变量,配置形状都一样(Claude Code 用 claude mcp add, 其他客户端填 mcpServers JSON)。唯一硬要求是子代理能调 MCP 工具——这是协议的前提。

⚠️ Claude Code 用户注意:已知问题(#13898、 #37353):.claude/agents/ 下的自定义 子代理拿不到 MCP 工具(甚至幻觉出假结果),只有 general-purpose 内置 agent 稳定可用。 多身份场景请先用 general-purpose 承载子身份。

workspace 参数:所有工具都要求显式传 workspace(游标落盘目录)。其他框架没有这个概念, 约定用一个固定的工作目录即可,务必保持稳定——换了目录等于换了收件箱。

工具

工具

作用

bridge_status

配置与连通性自检(check:true 实测一次 GitHub)

bridge_send

发消息建线程。to 支持 Alice/main(精确)、Alice/*(对方全体)、*(广播);from 可覆盖为子身份

bridge_inbox

增量收件箱:游标幂等、按身份落盘(<workspace>/.swarmbridge/)、会话恢复不丢进度

bridge_read

读线程全文(首帖 + 全部回帖,人类普通评论也能读出)

bridge_reply

线程内回帖(自动回给发起方)

bridge_ack

确认已处理:回帖 + 关闭线程,对方看到 closed 即闭环

bridge_wait

阻塞等铃(ntfy 推送):对方发消息即唤醒,≤25s,不阻塞同进程其他代理

bridge_ring

非阻塞查看未消费的门铃

消息信封(自动组装,人类可直接阅读):

{
  "bridge": 1,
  "id": "uuid",
  "from": "Wersky/main",
  "to": "Alice/main",
  "type": "task",
  "subject": "实现登录接口",
  "body": "约定见 docs/api.md",
  "data": { "goal": "登录接口", "detail": "含 429 退避" },
  "ts": "2026-09-12T13:00:00.000Z"
}

类型约定:hello 握手 / chat 沟通 / task 委派 / status 进展 / result 结果 / file 交付 / bye 收工(可自定义)。

典型流程

委派任务给对方:bridge_send {type:"task", data:{goal,detail}} → 对方轮询收到 → 对方本地执行(可再开自己的蜂群)→ bridge_reply {type:"result", data:{artifacts}} → 我方轮询看到 → 任何一方 bridge_ack 闭环。

子代理并行参与:我方子代理以 from:"Wersky/agent-1" 发消息;对方可以点名 to:"Wersky/agent-1" 精确投递(主代理不代收),或 to:"Wersky/*" 群发。这样两边的"主代理 + N 个子代理"可以同时多条线程并行沟通。

姊妹插件(蜂群套件)

三个插件同属一套「蜂群」套件,各司其职,可独立使用、组合互通:

插件

职责

仓库

TaskSwarm

同机任务蜂群:拆解、并行派发、共享看板、PPR 审核门

Wersky/taskswarm

SwarmBridge(本仓库)

跨机器消息桥:以 GitHub Issues 为总线,plan / proposal / discuss 结构化消息

本仓库

Roundtable

圆桌讨论:多 Agent 按序发言交锋、输出会议纪要,远端成员经本桥同席

Wersky/roundtable

taskswarm 解决本机编排(主代理 ↔ 子代理,共享看板);SwarmBridge 解决跨机器通信(本方 ↔ 对方,GitHub 总线);Roundtable 解决结构化讨论(定方案,跨机发言经本桥传递)。组合用法:对方的 task 消息 → 本地主代理把它 task_add 进自己的任务树 → 本地蜂群执行 → 收波后 bridge_reply {type:"result"} → bridge_ack 闭环。

设计取舍

  • 零依赖:只用 Node 内置模块(含内置 fetch),没有 SDK、没有供应链面。

  • 声明式身份:MCP 协议层无法验证"你是谁",真正的安全边界是仓库写权限(token 能写仓库才能发消息)。消息对仓库成员可见,勿传敏感信息。

  • 游标按身份隔离落盘:同一工作区多身份(主代理 + 子代理)各自轮询互不干扰;同一身份同时只应有一个活跃轮询者。

  • 刻意不给 bridge_inbox 加类型过滤:轮询游标会推进,被过滤掉的消息将不会再出现——类型筛选由调用方在返回结果里自行做(消息带 type 字段),避免"查看一下就弄丢消息"的坑。

  • 错误信息全部"发生了什么 + 下一步怎么做":401 指向 token、404 指向仓库名与权限、403 指向限额与重置时间、网络失败指向代理配置。

测试

65 个离线测试全绿(npm test):本地 stub 模拟 GitHub API,覆盖收发闭环、寻址与通配、广播、排除自己、排除人类帖子、子身份、游标持久化与会话恢复、401/404/网络失败/消息过大等错误路径,以及 plan(含 mode/maxRounds)、proposal、discuss(含轮次上限强制)三类结构化消息的发送端强校验。测试基础设施自带进程收割,异常退出不留孤儿 node 进程。

另有真机验证脚本(默认跳过,避免无 token 环境跑挂):

BRIDGE_LIVE=1 BRIDGE_REPO=Wersky/agent-bridge GITHUB_TOKEN=*** npm run live

License

MIT © 2026 Wersky


SwarmBridge lets agents and their subagents on two different machines talk in parallel through a shared GitHub repository: an issue is a thread, a comment is a reply, closing is an ack.

Subagents in coding agents (ZCode / Claude Code) are inherently isolated — no SendMessage, no cross-machine network. Within one machine a shared board works (see sister plugin taskswarm); across machines nothing exists. SwarmBridge fills that gap with zero dependencies (Node built-in fetch only). The three form one "swarm" suite: TaskSwarm (on-machine orchestration) · SwarmBridge (this repo, cross-machine messaging) · Roundtable (structured multi-agent discussion, remote members riding this bridge).

Measured latency: GitHub cannot push to a local machine (webhooks need a public endpoint), so SwarmBridge polls incrementally with a per-identity cursor. Live roundtrip: send → visible to peer ≈ 5.3s at a 1.5s polling interval; reply → visible ≈ 0.9s. Authenticated rate limit (5000/h) comfortably supports several agents.

Why Issues instead of a JSON file in the repo: appends are server-side with zero merge conflicts (a git-commit bus requires pull–rebase–retry and breaks under concurrency), updated_at enables cheap incremental polling, and comments/state give you threads and acks for free — plus humans can read and join on the web.

65 offline tests (a local stub fakes the GitHub API) plus gated live scripts.

MIT © 2026 Wersky

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables two coding agents on separate machines to communicate directly via a private git repo, with end-to-end encryption and no server required. Provides tools for joining rooms, sending/receiving messages, and managing side channels.
    58
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Use a fmsg address for a fmsg host. Tools for inbox, threads, send and reply, reactions, attachments, delivery status and wait-for-message over the host's WebSocket so agents can hold conversations with people or other agents. Runs over stdio locally or as a Streamable HTTP endpoint where each user authenticates with their own fmsg API key.
    14
    282 npm
    1
    MIT