letterbox
Letterbox
📌 为内部生产使用而构建。 架构经过数月日常 AI 开发的验证。作为参考实现开源。
简单来说: 如果你在终端中使用 AI 编程助手,通常一次只能使用一个——而让两个助手协作意味着你自己在窗口之间复制粘贴消息。Letterbox 让两个助手(比如 Claude 和 Gemini,或 Gemini 和 Mistral 的 Vibe)直接互相交谈,并一起完成任务,无需手动操作。
结果: 一个智能体可以规划,另一个可以审查,或者两者分工协作——在你观看的同时自主协作,而不是手动转发每条消息。
一个基于文件的小型通信协议,让两个 AI 智能体在各自的终端中实时对话。
Letterbox 让两个终端编程智能体——Claude Code、Gemini CLI、Antigravity 或 Mistral 的 Vibe——通过共享目录传递消息文件,实现实时对话。当一个智能体发言时,一个 📬 通知会被注入到另一个的终端中,唤醒它读取并回复。无需网络、无需服务器、无需共享内存:只需文件夹中的 JSON 文件和操作系统的原子重命名。它是为内部规划循环构建的消息层,于 2026 年提取为独立的、带版本的工具。如果你曾希望两个 CLI 智能体协作完成任务,而不必在窗口之间复制粘贴,那么这个工具就是为你准备的。它会偶尔根据作者的意愿更新(启动器会告诉你何时有新版本)——但它不受支持:没有路线图,不接受功能请求,也不是社区项目。
该桥接真正跨工具:一边是 Claude,另一边是 Gemini,通过同一通道对话,已经过实际验证。唯一的小问题是设置——Claude 会自动配置,而 Gemini 和 Antigravity 从各自的设置中加载 letterbox。设置 部分会介绍这两种方式。
为什么存在
我每天与两个 AI 协作者一起工作——Claude 和 Gemini——每个都生活在各自的终端工具中(Claude Code、Gemini CLI、Antigravity CLI,现在还有 Mistral 的 Vibe)。Letterbox 是我让它们彼此对话而不是通过我中转的方式。
这有两种模式。有时是手动的:我们在头脑风暴,我想把另一个模型拉进对话。有时是自动的——在规划循环中,Claude 起草计划,每个计划作为内置阶段路由给 Gemini 审查。Letterbox 以相同方式承载两者。
它设计为与工具无关——Claude Code ↔ Gemini CLI ↔ Antigravity CLI ↔ Vibe 任意组合——同模型配对同样有效:两个 Claude 标签页,或两个 Gemini 标签页,通过一个通道对话。
Related MCP server: CC2CC
它是什么
每次 letterbox <harness> 启动都在一个终端内运行两个协调的进程:
letterbox claude --channel demo --as alice
│
├─ PTY-Parent (the foreground letterbox process)
│ • spawns the harness CLI as a PTY child
│ • watches the channel directory for peer writes
│ • injects 📬 notifications into the PTY on arrival
│
└─ the harness spawns:
└─ letterbox mcp (stdio MCP server, agent-spawned)
• send_message / check_messages / acknowledge
• check_latest_message / channel_info / list_channels
Both sides coordinate ONLY through the filesystem:
~/.letterbox/channels/demo/
msg-*.json ← one file per message
.read/alice.json ← per-agent read markers
.read/bob.json没有守护进程、没有 IPC、没有后台服务。文件系统就是协调媒介——PTY-Parent 的监视器看到新的 msg-*.json 出现并渲染通知;通道目录是持久的、可检查的、可 cat 的。崩溃恢复很简单,因为内存中没有有价值的东西。
智能体获取 letterbox 工具的方式因工具而异,这是你只需配置一次的事情:
Claude Code 接受启动标志,因此 letterbox 会自动接线——它生成一个临时的 MCP 配置,并将
--mcp-config传递给claude。你无需设置任何东西。Gemini CLI 和 Antigravity 不接受该标志;它们从自己的设置文件中加载 MCP 服务器。你在那里添加一个一行、与通道无关的
letterbox条目,启动器在启动时通过环境变量将通道和身份传递给每个会话——因此你永远不需要按通道编辑设置。Vibe 从
~/.vibe/config.toml加载 MCP 服务器。其 MCP 子进程只继承精简的环境,因此需要一次性桥接脚本,将LETTERBOX_CHANNEL/LETTERBOX_SENDER从 Vibe 自身的进程环境转发。一旦就位,任何通道都像 Gemini 一样工作。参见 Vibe 设置 部分。
适用人群
运行终端编程智能体的人,希望在一台机器上进行自主 AI↔AI 对话,无需在窗口之间复制粘贴。
重视文件作为真相来源的人——可审计、可 grep、无晦涩协议、无魔法。
不适用人群
想要托管或网络化聊天服务的人——消息协议仅限文件系统本地,绝不接触网络。(启动器在启动时做一次可选的、尽力而为的版本检查;用
LETTERBOX_NO_UPDATE_CHECK=1禁用它。)想要多用户平台的人——它是单台机器上智能体之间的点对点桥接,不是多用户中心(参见为两人构建)。
Windows 原生用户——v1 仅限 POSIX(参见我们不支持的内容)。
想要受支持产品的人——letterbox 有版本,偶尔根据作者意愿更新(启动器会告诉你何时有新版本),但没有路线图、没有 SLA、不承诺接受功能请求或持续维护。按原样使用;如果有帮助,拉取更新版本。
为两人构建
Letterbox 本质上是双向桥接——一个对等体与另一个对等体对话是它设计和调优的目标。三个或更多智能体可以共享一个通道:定向寻址(send_message(to="<label>"))和 participants 列表使其可行,同通道广播可到达所有人。但共享通道是广播总线——每条消息唤醒每个参与者。如果没有编排(轮流发言、指定协调者或关于谁何时发言的规则),N 方房间会变成通知风暴,可能很快耗尽模型的消息/使用限制。如果你想要三个或更多,请自带指挥者。底层诚实地显示谁在房间里;礼仪由你负责。
安装
Letterbox 从源码安装(可构建 wheel;目前未发布到 PyPI)。从仓库根目录:
pip install -e . # or: pip install -e ".[dev]" for the test extras这会将 letterbox 命令放在你的 PATH 上。该命令必须按名称解析——每个智能体自己会生成 letterbox mcp——因此这是关键。确认它:
which letterbox # note this absolute path; Gemini/Antigravity setup needs it你还需要安装你要启动的工具(claude、gemini、antigravity 或 vibe),放在 PATH 上并登录。Letterbox 会为你启动它。
更新
Letterbox 有版本(letterbox.__version__,唯一真相来源);由于没有 PyPI 发布,git main HEAD 就是发布版本。在面向人类的启动时,CLI 会做一次尽力而为的检查(每天最多一次,缓存在 ~/.cache/letterbox/ 下),如果存在新版本则打印一行通知。要更新:
pip install --upgrade "git+https://github.com/dovahkiin-v/letterbox"这是 letterbox 唯一一次网络调用——消息协议完全保持本地。它使用严格的超时,并且完全静默失败:如果无法访问 GitHub,它只是什么都不打印,绝不会延迟你的启动。它永远不会为 letterbox mcp(智能体的 stdio 服务器)运行。用 LETTERBOX_NO_UPDATE_CHECK=1 完全禁用它。
按工具设置
每个工具只需设置一次。跳过你不会使用的工具。
Claude Code — 无需操作
Letterbox 自动接线 Claude:启动时它写入一个临时的 MCP 配置(模式 0600)并将 --mcp-config <path> 传递给 claude。letterbox 工具出现在该会话中,不会出现在其他地方。没有需要编辑的设置文件。
Gemini CLI — 两个一次性步骤
1. 注册 MCP 服务器 在 ~/.gemini/settings.json 中(如果文件不存在则创建)。使用你安装的 letterbox 的绝对路径(来自上面的 which letterbox),并且只传递 ["mcp"]——没有通道,没有身份:
{
"mcpServers": {
"letterbox": {
"command": "/absolute/path/to/letterbox",
"args": ["mcp"]
}
}
}这个条目故意与通道无关。 启动器在启动时将 LETTERBOX_CHANNEL、LETTERBOX_SENDER 和 LETTERBOX_INSTANCE_ID 导出到 Gemini 的环境中,MCP 服务器读取它们——因此同一个条目服务于所有通道,你永远不需要再编辑它。(这反映了 Forge 编排器如何通过环境变量传递通道。)
2. 信任你启动的文件夹。 Gemini 拒绝在不受信任的目录中运行,除非有交互式的*“你信任这个文件夹吗?”*提示——而阻塞的 TUI 提示会阻碍自动化。在 ~/.gemini/trustedFolders.json 中预先信任启动目录(或父目录):
{
"/home/you/projects": "TRUST_PARENT"
}TRUST_FOLDER 信任恰好该目录;TRUST_PARENT 信任它及其下所有内容,因此一个条目覆盖你所有的项目文件夹。(提示:不要使用 Gemini 的 --skip-trust 标志来绕过这一点——它会强制进行工作区系统提示查找,即使在已信任的目录中也会崩溃。请信任文件夹。)
Antigravity (agy)
以 letterbox agy … 启动它(长形式 letterbox antigravity … 也可以——agy 只是匹配二进制名称的别名)。Antigravity 通过与 Gemini 相同的环境变量接收每次启动的通道和身份;不同之处在于你如何注册 MCP 服务器。agy 从插件加载 MCP 服务器,因此你将 letterbox 安装为一个小型本地插件(一个包含两个 JSON 文件的目录):
# 1. Build the plugin (one directory, two files). Use the absolute
# `letterbox` path from `which letterbox`.
mkdir -p ~/.letterbox/agy-plugin/letterbox
cat > ~/.letterbox/agy-plugin/letterbox/plugin.json <<'JSON'
{ "name": "letterbox", "version": "1.0.0",
"description": "Letterbox file-based AI-to-AI comms bridge." }
JSON
cat > ~/.letterbox/agy-plugin/letterbox/mcp_config.json <<'JSON'
{ "mcpServers": { "letterbox": {
"command": "/absolute/path/to/letterbox", "args": ["mcp"] } } }
JSON
# 2. Install it (and confirm).
agy plugin install ~/.letterbox/agy-plugin/letterbox
agy plugin listmcp_config.json 与通道无关,原因与 Gemini 的设置条目相同——启动器在启动时通过环境传递通道和身份。与 Gemini 一样,agy 也受文件夹信任限制:它遵循 ~/.gemini/antigravity-cli/settings.json 中的 trustedWorkspaces 列表,因此如果启动目录不在其中,请添加。
状态: PTY 层(通知 + 消息传递,双向)已实际验证,上述插件安装干净地接线了工具。完整的
agy工具往返刚刚可用且经过轻度测试——将 Antigravity 视为三者中最新的,如有任何异常请报告。
Vibe (Mistral)
以 letterbox vibe … 启动它。Vibe 从 ~/.vibe/config.toml 加载 MCP 服务器,但其 MCP 子进程只继承精简的环境(HOME、PATH、SHELL、TERM、USER、LOGNAME)——因此 LETTERBOX_CHANNEL 等无法通过正常继承到达它。一个小的一次性桥接脚本通过在生成时从 /proc 读取 Vibe 的进程环境来解决这个问题。之后,任何通道都像 Gemini 一样工作——无需按通道编辑配置。
1. 安装桥接脚本(随 letterbox 提供):
cp "$(python3 -c 'import letterbox.data, pathlib; print(pathlib.Path(letterbox.data.__file__).parent / "vibe-mcp-bridge.sh")')" \
~/.letterbox/vibe-mcp-bridge.sh
chmod +x ~/.letterbox/vibe-mcp-bridge.sh2. 在 ~/.vibe/config.toml 中注册它。 将任何现有的 letterbox 条目替换为:
[[mcp_servers]]
name = "letterbox"
transport = "stdio"
command = "/home/YOU/.letterbox/vibe-mcp-bridge.sh"
args = []使用你的实际主目录路径(不是 ~——Vibe 可能不会展开它)。该条目故意与通道无关:桥接脚本在运行时从 Vibe 的进程环境读取通道和身份,就像 Gemini 从其环境读取一样。
3. 完成。 任何通道都有效:
letterbox vibe --channel blueberry-fields --as mistralVibe 还以 --yolo(自动批准)启动,因此注入的通知可以唤醒它,而不会阻塞在每个工具提示上。
注意: 桥接脚本使用
/proc/$PPID/environ读取 Vibe 的环境——仅限 Linux,这与 letterbox 的 POSIX-only 立场一致。macOS 支持需要不同的机制(ps -p $PPID -Ewww);目前未提供。
状态: 📬 唤醒注入已确认可用(STEP 0 已验证 Vibe 的
ChatTextArea会覆盖 Enter 键来提交,因此标准 PTY 注入路径适用)。将 Vibe 视为四个中最新的一个,如有任何异常请报告。
快速开始
打开两个终端,各自以不同的身份指向同一个频道。在没有配置文件的情况下,letterbox 的内置默认值提供共享的全局状态目录(~/.letterbox)。
一个真正的跨框架桥接——Claude 与 Gemini 对话(先完成 Gemini 设置):
# Terminal 1
letterbox claude --channel demo --as claude
# Terminal 2
letterbox gemini --channel demo --as gemini或者两个相同框架的实例,如果你更想保持简单:
# Terminal 1
letterbox claude --channel demo --as alice
# Terminal 2
letterbox claude --channel demo --as bob两个会话都会启动并安静地等待。现在在终端 1 中轻推一下代理——例如,"给你的对等方发一条消息。" 此后,每条 📬 通知都会唤醒另一个代理来阅读和回复:这种交接就是全部意义所在。--as <label> 名称让对话记录可读;在底层,消息过滤使用的是每次启动的实例 ID,而不是标签。
几点坦诚的说明:
你永远不需要自己运行
letterbox mcp。 该子命令是 stdio MCP 服务器,由框架生成——它是给代理用的,不是给你用的。在终端中手动运行它,它会告诉你这一点然后退出。启动参数在设计上就是自主的。 Claude 适配器以
--dangerously-skip-permissions启动,Gemini 适配器以--yolo启动,因为注入的消息无法唤醒一个被逐操作审批提示阻塞的代理。如果你不想要这个权衡,letterbox 不适合你——在letterbox.toml中覆盖参数,或者干脆不用。
如需完整的分步讲解(两个 Claude 争论热狗是不是三明治),请参阅 examples/two-claudes-debating/ 下的示例项目。
了解桥接状态
由于配置了设置的框架会在每次会话中加载 letterbox,代理可能拥有 letterbox 工具但没有活动的桥接——例如,一个你从未通过 letterbox 启动的普通 Gemini 会话。Letterbox 会冷静地处理这种情况,并给代理一种检查方式:
普通会话是休眠的,不是损坏的。 没有频道时,MCP 服务器仍然会连接(框架会显示平静的"已连接"),但消息工具保持安静——它们只有在实际被调用时才会以清晰、可操作的错误消息失败,绝不会自行触发。有意的普通会话永远不会被垃圾消息打扰;真正配置错误的桥接会在代理尝试通信的那一刻暴露出来。
channel_info是代理的桥接神谕。 调用它会从服务器端回答:桥接是否处于活动状态?在哪个频道上,以什么身份?对等方是谁(从其最近的消息中观察得出),有多少未读消息,以及它最后一次发言是什么时候?不确定自身处境的代理可以在发送前询问——"对等方 90 秒前发言" 与 "从未发言" 读起来截然不同。
观察和列出频道
从任何终端,观察原始对话或查看存在哪些频道:
letterbox tail --channel demo --follow # stream messages as JSON, one per line
letterbox list-channels # list channels with last-activity要生成一个起始的 letterbox.toml 而不是依赖默认值:
letterbox init --channel demo # writes ./letterbox.toml (project-local)
letterbox init --global # writes ~/.letterbox/config.toml instead操作
读取会让你赶上进度;收件箱会自动清空。
check_messages返回未读的对等方消息,并在读取过程中推进该代理的读取标记——因此连续调用会分页浏览积压消息,而清空后的收件箱保持清空状态,无需手动记账。check_latest_message是一个不推进标记的窥视操作,用于常见的*"他们刚才说了什么?"*场景,acknowledge则用于显式的单条消息控制。重启是全新开始,不是重放。 启动时,代理的读取标记会对齐到磁盘上已有的最新消息,因此它只会看到加入之后到达的消息——不会被之前会话的整个频道历史淹没。历史记录仍然存在,可以按需访问(使用
since_id游标的check_messages);只是不会强制推送给你。保留是手动的。 消息一直存在于频道目录中,直到你清理它们;没有自动删除(在通信基础设施中,意外删除是不可接受的)。每个代理的
.read/标记跟踪读取状态——它们只推进标记,从不触碰文件,也从不影响对等方的视图。实际上限:每个频道约 10,000 条未清理消息。 超过这个数量,
check_messages和list-channels可能会出现明显的延迟。超过该点请进行清理。letterbox prune是回收空间的安全方式。 它默认是试运行——只打印将要发生的事情,不触碰任何东西。--yes-i-am-sure将匹配的文件移动到可逆的cold/子目录;--delete --yes-i-am-sure(双重门控)则永久删除。这是 letterbox 中唯一的破坏性命令。
letterbox prune --channel demo --keep-last 100 # preview (dry run)
letterbox prune --channel demo --keep-last 100 --yes-i-am-sure # move to cold/
letterbox prune --help # all selection rules频道只是一个文件夹,所以 rm -rf ~/.letterbox/channels/demo 也可以——letterbox 不锁定任何东西。
安全模型
完整的威胁模型位于 docs/PROTOCOL.md。简要说明:
频道上的对等代理是不可信的。 其消息正文可能携带提示注入载荷、ANSI 转义序列或 shell 元字符。Letterbox 将双方都视为不可信。
通知仅从可信上下文渲染。
📬通知模板替换的变量来自观察者自身的配置和观察结果({channel}、{sender}、{message_id}、{timestamp})——绝不来自对等方的消息载荷。恶意对等方可以在其文件中写入任何内容;其中没有任何内容会到达注入的通知。消息正文仅在代理显式调用check_messages时才会呈现。channel_info的对等方字段也是如此:它们是从流量中观察到的信息性内容,绝不会被送入通知。无执行路径。 Letterbox 从不
exec、eval或通过 shell 执行消息正文或元数据字段。子进程使用 argv 列表生成(绝不使用shell=True),且仅用于启动letterbox.toml中配置的框架。路径安全。 频道名称和消息 ID 在任何文件系统操作之前都会经过严格模式验证——
../etc或任何包含斜杠的内容都会被拒绝。文件系统权限。
~/.letterbox/和频道目录以0700(仅限用户)创建;生成的 MCP 配置为0600。
Letterbox 不防御的内容: 被攻破的本地用户账户(文件系统权限是唯一的屏障)、消费框架自身的提示注入漏洞,或跨机器同步(NFS、syncthing)引入的信任边界。它不是静态加密或网络信任层——这些在设计上就不在范围内。
范围与反范围
Letterbox 刻意不做的事情正是重点,而不是缺陷:
无 LLM 调用。 Letterbox 从不调用语言模型、不消耗 token、不持有 API 密钥。通知模板是渲染的文本,不是提示词。
无遥测、无指标、无分析。 不收集任何内容,没有仪表板,没有使用跟踪。
无回传、无自动更新、无版本检查。 Letterbox 从不联系任何服务器。首次运行是静默的。
无网络。 它仅限文件系统本地。跨机器使用是你文件系统同步的事,不是 letterbox 的事。
正是这种反范围让 letterbox 能够保持小巧、惰性、可审计和持久。
可访问性
默认纯文本(
--format=plain)——适合管道和屏幕阅读器;tail向 stdout 输出消息 JSON 供jq使用。结构化/彩色输出是可选加入的(--format=rich)。无纯颜色信号。
--color=auto|always|never独立控制颜色;颜色绝不是传达状态的唯一方式。stdout 是数据,stderr 是日志——命令可以干净地管道化。
全程 UTF-8。 工具自身的字符串是英文;消息正文可以是任何你书写的语言。
平静的表面。 没有旋转动画、没有遥测横幅、没有升级提示。安静的成
This server cannot be deployed
Maintenance
Related MCP Connectors
Shared memory and mail for your AI agents. Verified with Claude Code; other MCP clients in testing.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Durable agent-to-agent handoffs and shared scratchpad for multi-agent workflows.
End-to-end encrypted messaging and work coordination for autonomous AI agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables two or more Claude Code terminals on the same machine to communicate by registering and sending messages via the local filesystem.51MIT
- AlicenseNot gradedqualityDmaintenanceEnables file-based agent-to-agent communication between Claude Code instances on the same machine, using MCP channels and plain JSON files.7 npm14MIT
- AlicenseAqualityDmaintenanceLocal inter-agent messaging for AI coding agents via filesystem relay.42MIT
- AlicenseNot gradedqualityDmaintenanceEnables multi-agent coordination for Claude Code and Claude.ai through file-based JSON communication, eliminating the human bottleneck of message relaying.9 npmMIT