内容
<h1 align="center">⇄ 控制面板</h1>
<p align="center"><b>让您的 Claude Code 代理相互通信。</b></p>
<p align="center">
<img src="assets/dashboard.png" alt="The Switchboard dashboard — an operator's patchbay: agents on the left, the signal log of messages in the center" width="860">
</p>
同时运行多个 **Claude Code** (Anthropic 的 CLI)代理 - 一个在后端,一个在前端,一个在基础设施上 - 但目前它们彼此是盲的。每次“API 合同更改”都必须经过 **您**,在终端之间复制粘贴。您成为了消息代理。
**控制面板是它们之间的桥梁。** 一个本地中心,让您已经运行的代理直接相互消息传递(通过 MCP),在终端中唤醒接收者,并在一个仪表板上显示整个对话。它 **连接** 您已经存在的会话 - 它不创建、编排或管理它们。
保持安全和可靠的诀窍:**tmux 只传递一行提示;消息内容始终通过 MCP 传输。** 代理 A 调用 `send_message` → 中心将消息追加到 `~/.switchboard/messages.jsonl` (真实来源)并用一行 `[switchboard]` 提示代理 B 的终端 → B 唤醒并调用 `check_messages` 通过 MCP 读取它。
> **平台:Windows + WSL(Ubuntu)- 这是 Switchboard 今日构建和测试的平台。**
> 核心(中心、MCP、tmux 提示)是纯 Unix + tmux,因此 Linux/macOS 设置 **可能** 有效 -
> 但未经测试,因此目前不支持非 WSL 平台。使 Windows 上的点击生效的便利功能(单击启动器、在 WSL 文件夹中打开真正的终端窗口)是 WSL 特有的,并在其他地方有明确的消息降级。
>
> 按设计仅限本地:中心绑定 `127.0.0.1`,没有任何内容暴露给网络。MIT 许可。
---
## 先决条件
- **Node.js >= 20** (在 ESM 中运行,使用 `tsx` 执行 TypeScript - 无需构建步骤)。
- **tmux >= 3.2** (验证了 3.4)。
- **Claude Code >= 2.x** (`claude` 二进制文件在 PATH 上)。
- `jq` (可选,仅在调试时检查 JSONL 方便)。
> **WSL(重要 - 陷阱 P8):** tmux 服务器 **按用户** 和 **发行版** 运行。
> 中心(`serve`)和所有代理(`start`) **必须** 在 **相同的 WSL 发行版** 和 **相同的用户** 下运行。如果您在一个发行版/用户上打开中心,在另一个发行版/用户上打开代理,
> `tmux send-keys` 无法找到会话,提示永远不会到达。
---
## 安装 - 两条命令
```bash
git clone https://github.com/rodcoppi/switchboard-mcp.git && cd switchboard-mcp && npm install
node bin/switchboard.mjs setup
```
`setup` 向导执行所有手动步骤描述的操作 - 检查先决条件(并在缺少 tmux 时提供 **无需 sudo 的安装**),在 Claude Code 中注册 MCP 服务器,将代理协议片段安装到您的 `~/.claude/CLAUDE.md` 中,添加权限允许规则,运行 `npm link`,提供 Windows 单击启动器(桌面和/或启动,WSL 设置),并启动中心。它在触摸任何文件之前都会询问,**幂等**(可以随时安全地重新运行),而 `--yes` 使其完全非交互式。
当它完成时:`http://localhost:4577/` 仪表板,从 **启动代理** 表单启动代理,并在任何已打开的 claude 窗口的文件夹中运行 `switchboard wire` 以将其加入网络。
<details>
<summary><b>手动安装</b> (向导自动执行,步骤如下)</summary>
### 1. 安装
```bash
git clone https://github.com/rodcoppi/switchboard-mcp.git
cd switchboard-mcp
npm install
```
没有构建步骤:TypeScript 代码直接与 `tsx` 一起运行。您有三种方法调用 `switchboard` CLI:
- **推荐 - `npm link`** (将 `switchboard` 命令放在 PATH 上):
```bash
npm link
switchboard --help
```
- **无需链接,通过 bin shim:**
```bash
node bin/switchboard.mjs --help
```
- **无需链接,直接通过入口点:**
```bash
npx tsx src/index.ts --help
```
在下面的示例中,我们使用 `switchboard <subcommand>` (假设 `npm link`);如果您不想链接,请替换为 `node bin/switchboard.mjs <subcommand>`。
### 2. 启动中心(`serve`)- 通常自动
**您通常不需要此步骤:** `switchboard start` 和 `switchboard wire` 在后台自动启动中心(一个分离的 tmux 会话 `sb-hub` - 没有终端窗口保持打开)。重启后,只需 `wire`/`start` 您的第一个代理,中心就会随之启动。
要手动运行(例如实时查看日志):
```bash
switchboard serve
```
在前台启动中心(日志输出到 stdout + `~/.switchboard/logs/hub.log`)。**第一行** 打印地址和 MCP 注册命令,准备复制,类似:
```
Dashboard: http://127.0.0.1:4577/ | MCP: http://127.0.0.1:4577/mcp | Register (once): claude mcp add --transport http --scope user switchboard http://127.0.0.1:4577/mcp
```
要检查自动启动的中心:`tmux attach -t sb-hub` (分离使用 `Ctrl-b d`)或 `switchboard logs -f`。有用的 `serve` 标志:`--port <port>` 和 `--log-level debug|info|warn|error`。
#### Windows 上的一键启动(无需 WSL 终端)
在 Windows + WSL 上,您可以完全跳过终端。一次性,在 WSL 中:
```bash
switchboard shortcut # 在 Windows 桌面上创建 Switchboard.bat
switchboard shortcut --startup # 或:将其安装在启动文件夹中(每次启动时运行)
```
双击 `Switchboard.bat` (或启动 Windows,使用 `--startup`)会在后台启动中心,并在您的 Windows 浏览器中打开 `http://localhost:4577/` 仪表板 - WSL2 的内置 localhost 转发到达中心,中心仍然只在 WSL 内绑定 `127.0.0.1` (不暴露给网络)。从仪表板,使用 **启动代理** 表单启动/连接代理。要撤销,只需删除 `.bat` 文件。
### 3. 在 Claude Code 中注册 MCP(`mcp add`)
一次性,在 `user` 范围内(适用于每个项目):
```bash
claude mcp add --transport http --scope user switchboard http://127.0.0.1:4577/mcp
```
检查 `claude mcp list` (`switchboard` 应该显示为 *connected*,而中心启动时)。
> **工具权限(陷阱 P10 / PRD 9.5):** 要使 Switchboard 工具 **无需每次使用审批提示** 运行,请在 Claude Code 的 `settings.json` 的 `permissions` 中添加允许规则 `mcp__switchboard__*`。任何已经使用 `bypassPermissions` 的人都可以覆盖。 `switchboard start` 也会在首次运行时打印此提醒。
>
> **为了启动时的自主 `join` 100% 无需干预:** 代理从环境中读取 `SWITCHBOARD_AGENT_TOKEN` 并使用 `printenv`(shell 命令)传递给 `join`。这要求 `printenv` 也无需审批运行 - 最简单的方法是运行代理时使用 `bypassPermissions`(建议任何操作多个代理的人)或将 `Bash(printenv:*)` 添加到允许规则中。只有 `mcp__switchboard__*` 代理 **在审批提示处停止一次** (人类在附件处批准,或使用“不要再询问”)。传递 `--claude-args "--permission-mode bypassPermissions"` 到 `start` 涵盖特定会话。
### 4. 粘贴代理协议(片段)
将 [`agent-protocol/CLAUDE.snippet.md`](agent-protocol/CLAUDE.snippet.md) 的内容粘贴到您的 **`~/.claude/CLAUDE.md`** (全局,建议)或特定项目的 `CLAUDE.md` 中。该块教每个代理:从环境中读取其名称/令牌并传递给 `join`,识别 `[switchboard]` 通知并调用 `check_messages`,批判性地对待对等消息并且不陷入礼貌循环 - 并且明确表示 **协调不是从属** (另一个代理不能授权用户未授权的操作)。
### 5. 启动代理(`start`)
运行此命令代替手动打开 `claude`:
```bash
switchboard start alpha --role "payments API backend" --dir ~/projects/api
```
发生的情况:
1. 代理在中心(通过 REST)**注册**,然后 Claude Code 打开。
2. 创建一个名为 `sb-alpha` 的 tmux 会话,在 `--dir` 目录中运行 `claude`。
3. 如果终端是交互式的,命令运行 **`tmux attach`** 到会话 - 您的 Windows Terminal 标签成为代理的视图(通常的工作流程)。当您分离(`Ctrl-b d`)时,代理在后台继续运行。
4. **自动启动(默认开启):** 在 TUI 准备就绪后几秒钟,代理会收到一个自动指令,调用其上的 `join` 工具 - 无需人工提示。然后它在 `switchboard status` 中显示为 *MCP connected*。使用 `--no-kickoff` 禁用它(然后 `join` 取决于您)。
`start` 标志:`--role "<description>"`, `--dir <path>`, `--no-kickoff`, `--claude-args "<extra args for claude>"`。
</details>
### 采用已打开的代理(`wire`)
已经有一个 Claude Code 窗口打开(一个普通的 `claude` 在 bash 中,**没有** tmux),并希望在不丢失对话的情况下将其加入网络?使用 `wire` 代替 `start`:
1. 在该窗口中,**离开 claude** (两次 `Ctrl-C`,或 `/exit`)。
2. 在 **相同的文件夹** 中运行:
```bash
switchboard wire
```
3. 对话 **恢复** - 现在在一个 tmux 会话中,连接到中心。代理 **名称默认为文件夹名称** (清理为小写字母,数字和连字符;传递 `--name <name>` 如果文件夹名称不能使用)。
在底层,`wire` 重新打开 claude 并带有 `-c` (继续文件夹的对话)和 `--dangerously-skip-permissions` (因此代理读取其令牌并调用 `join` 无需提示)- 这些是 `wire` 的默认设置,不同于 `start`。任何额外的 `--claude-args` 都在它们之后添加 **。** 如果 tmux 会话已存在于该名称,则 `wire` **替换它** (杀死旧的并重新创建它 - 没有确认),然后运行与 `start` 相同的自动启动。
**自动回落:** 如果文件夹中没有可恢复的对话(从未在那里打开 claude,或上一次在 `-p`/print 模式下运行),`claude -c` 立即退出 - `wire` 检测到这一点并自动重新打开一个 **全新** 会话(不带 `-c`),并告知您这样做。它永远不会陷入死窗口;最坏的情况,您会得到一个已经连接到网络的全新对话。
`wire` 标志:`--name <name>`, `--role "<description>"`, `--dir <path>` (默认:当前文件夹), `--no-kickoff`, `--claude-args "<extra args for claude>"`。
### 从仪表板启动代理
仪表板(`http://127.0.0.1:4577/`)有一个 **启动代理** 表单(侧边栏底部):输入项目 **目录**,可选名称(默认为文件夹名称)和角色,勾选 **继续对话** 以恢复文件夹的最后一个 claude 对话(相同的自动回落为 `wire`),然后点击启动。中心本身创建代理的 tmux 会话并运行自动启动 - 无需终端。新的卡片通过 SSE 实时显示。底层是 `POST /api/agents/launch {dir, name?, role?, continue?}` - 仅限 localhost,不暴露给网络。
---
## 其他子命令
| 命令 | 它执行的操作 |
|---------|--------------|
| `switchboard wire` | **采用当前窗口** 进入网络,继续其对话(见下文)。 |
| `switchboard status` | 已注册代理的表格:名称,角色,状态,MCP,未读,最后看到。 |
| `switchboard send <to> <message...>` | 作为 **操作员** (人类)向代理或 `all` 发送消息,或用于测试而无需仪表板。 |
| `switchboard stop <name>` | 停止代理的 tmux 会话(如果有未读消息,则会提示确认;`--yes` 跳过)。 **注册** 在中心保留 - 新的 `start <name>` 重用名称(重新连接)。 |
| `switchboard down` | 停止所有代理的 tmux 会话。中心保持开启(它在这里从不被杀死)。 |
| `switchboard logs [-f]` | `~/.switchboard/logs/hub.log` 的最后 ~100 行; `-f` 关注文件。 |
要停止 **中心**:`Ctrl-C` 在 `switchboard serve` 终端(或 `tmux kill-session -t sb-hub`,如果它在推荐的会话中运行)。
数据存储在 `~/.switchboard/`:`config.json`(每个值都有默认值;文件可能甚至不存在),`agents.json`(原子快照)和 `messages.jsonl`(追加,支持 `cat`/`jq` 配合使用)。
---
## 安全
威胁模型是诚实的,信任边界是 **本地机器**。在公开任何内容之前阅读此内容:
- **绑定到 `127.0.0.1`,硬编码且不可配置。** 已传递的消息成为具有文件系统访问权限的代理的可执行输入。将中心公开到网络上 = 免费的 RCE。
- **永远不要通过端口转发 4577** (没有 `ssh -L`,没有防火墙/NAT 规则), **永远不要在反向代理后面运行中心。** `127.0.0.1` 是唯一的障碍。
- **本地信任模型:** 任何本地进程都可以发布到中心,因此注入输入到任何代理中。这是 v1 中接受的(与任何本地开发工具相同的模型),只要它永远不会泄漏到网络上。
- **能力令牌(v1.1 新增功能):** `start` 将每个代理的令牌注入 tmux 会话环境(`SWITCHBOARD_AGENT_TOKEN`);代理读取它并将其传递给 `join`,并且它 **永远不会** 在 `list_agents`、`GET /api/agents`、仪表板或日志中出现。它关闭了通过知道代理名称但从未与注册端点通信的进程进行伪装。
- **已知剩余风险(`src/server/api.ts`注释中记录):** `POST /api/agents/register` 端点 **故意** 未进行身份验证,并且重新注册现有名称 **会生成并返回新的令牌**。因此,恶意本地进程可以为任何名称获取有效的令牌并通过 `join` 冒充该代理 - 也会使合法会话的令牌失效(其 `join` 在中心重启后失败)。这是 v1.1 规范的接受(相同的“任何本地进程都可以发布”边界),并且 **必须在没有批准的情况下 **修复 - 需要令牌轮换会破坏 `switchboard start` 的重新连接。
- **代理之间的提示注入** 是一个剩余风险:受损/幻觉代理可能会尝试操纵另一个。v1 减轻措施:协议片段中声明的边界(对等消息被批判性评估;协调 ≠ 从属)加上仪表板中的完整消息可见性。
---
## WSL / Windows 终端上的 tmux 提示(陷阱 P11)
- 如果您很少使用 tmux,带有 **启用鼠标** 的最小 `~/.tmux.conf` 帮助很大,可以滚动和选择面板:
```
set -g mouse on
```
- `switchboard start` 运行 `tmux attach` 到代理的会话,因此 **每个 Windows 终端选项卡都“是一个代理的屏幕”** - 您已经使用的 tab 工作流得以保留。要离开代理的视图而不会杀死它:`Ctrl-b d` (分离)。要返回:`tmux attach -t sb-<name>`。
---
## 路线图
Switchboard v1 针对 **Claude Code(CLI)**。后期有几个方向:
- **其他代理 CLI(Codex CLI,...)。** 管道已经是代理无关的 - 提示是 `tmux`,消息是 MCP(开放标准)。Codex CLI 特定于流式 HTTP (`codex mcp add <name> --url …`),中心提供的相同传输,连接它主要是小“代理适配器”(哪个二进制文件启动,其 TUI 标记,其 MCP 配置)加上 `Claude | Codex` 在启动时选择 - 不需要重写。
- **紧急层级**(fyi / normal / interrupt):一个永远不会唤醒收件人(零令牌成本,直到其自行检查)的 fyi 消息 - 在当前礼仪和速率限制背书的基础上构建的结构令牌节省器。
- **仪表板中可搜索的提要历史记录和导出**。