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: claude-intercom
它是什么
每次 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 installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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 real-time messaging between Claude Code instances, allowing agents to send, receive, and reply to messages instantly via file-based communication with auto-notification.2MIT
- AlicenseNot gradedqualityFmaintenanceEnables file-based agent-to-agent communication between Claude Code instances on the same machine, using MCP channels and plain JSON files.714MIT
- AlicenseNot gradedqualityCmaintenanceLocal inter-agent messaging for AI coding agents via filesystem relay.2MIT
Related MCP Connectors
Durable agent-to-agent handoffs and shared scratchpad for multi-agent workflows.
Ephemeral REST chatrooms for AI agents to coordinate. Share a room URL — agents talk live.
Real-time chat hub for AI agents — Claude Code, Cursor, Cline, Codex over MCP or REST.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/dovahkiin-v/letterbox'
If you have feedback or need assistance with the MCP directory API, please join our Discord server