llms.txt 完整文档索引请参见 llms.txt
工具
xiaohui
于收录

Frog | 面向 AI 编码时代的 SSH 终端,多端共用一个 tmux 会话

Frog 是面向 AI 编码时代的 SSH 终端,手机、浏览器与电脑共用机器上的同一条 tmux 会话。它没有自研同步协议:真源在 tmux,传输跑在 iroh 的 QUIC 打洞上,密钥与片段走端到端加密的 vault。

Frog — 官网首页。

Frog 官网首页

Frog 是一款面向 AI 编码时代的 SSH 终端:手机(iOS / Android)、浏览器和电脑共用机器上的同一条 tmux 会话。它没有自研的终端同步协议——真源在 tmux,传输跑在 iroh 的 QUIC 打洞上,密钥与片段走端到端加密的 vault。这个组合值得拆开看。

手机打开的不是新连接,是同一条会话

大部分手机 SSH 客户端解决的问题是「在外面也能连上服务器」。换到 Frog,产品定义换了一句话:每一台设备都只是同一条 tmux 会话的又一个客户端。

官方文档原话是「每个标签页就是机器上的一个 tmux 窗口,分屏就是它的 pane,和你坐在机器前看到的完全一样」。这句话决定了它的所有取舍——你不用在手机上重新 cd 到项目目录、重新启动一次 Claude Code,也不用担心手机掉线把进程带走。进程一直在机器上跑,手机只是换了块屏幕看它。

拆开二进制:同步靠 tmux,不靠自研协议

Frog 的宿主机程序是一个 26 MB 的 Rust 单二进制(当前版本 v0.1.0-alpha.117,同一份程序既是命令行 frog,也是常驻服务 frog serve)。从符号表里能直接读到它跟 tmux 打交道的全部方式:

环节实际执行的动作
发现结构list-panes -a 一次取全会话、窗口、pane 的完整字段(PID、TTY、当前命令、启动时间),渲染成标签页与分屏
打开一个标签页起一条独立的 SSH 通道,attach-session 挂到同一个 tmux 会话,再 select-window / switch-client 定位到目标窗口
首屏内容capture-pane -p -J 先抓一份纯文本快照铺上去,再接实时流
谁在用list-clients 配合 client_pid 跟踪「哪台设备挂在哪个客户端上」

Zellij 走另一条路径:zellij attach --session <名字> --layout-string …,再用 zellij action list-panes 读结构;版本太老、不认识这两个参数的 zellij 会被直接判定为不支持。

所以「多端同步」在 Frog 里不是同步屏幕像素,而是共享会话状态。tmux 服务端本来就支持多个客户端同时挂载、共享窗口内容,Frog 只是把每个标签页变成一次独立的 attach。这也解释了它为什么不需要处理「两台设备同时输入怎么办」——那是 tmux 二十年来一直在做的事。

传输层是 iroh:打洞优先,relay 只搬密文

配对之后,机器不需要开放任何入站端口。底层用的是 iroh(QUIC 的点对点网络库,当前 1.0.3):能直连就直连,打不通洞才回落到官方 relay。配套还带上了 UPnP 端口映射、局域网 mDNS 发现(frog._tcp.local)和换网感知——Wi-Fi 切 4G 时连接会重建,而不是断死。

relay 可以自托管,镜像就是官方的 n0computer/iroh-relay:v1.3.0,需要 TCP 80/443 和 UDP 7842。它的定位很克制:只转发自己读不懂的密文,能看到「两台设备在通信、什么时候、多少流量」,但读不到也改不了内容。

浏览器是个例外。Chrome 里没有 iroh,所以网页端的 SSH 由 Frog 的边缘服务器终结——官方明确说明 Web SSH 走他们的服务器,也因此连不进只在内网 VPN 里可达的地址,那种情况只能先配对机器或走跳板机。网页端的连接诊断被拆成固定几段:relay → WebSocket → SSH → 主机密钥 → 认证 → 终端 → 文件,出问题时能直接看出卡在哪一跳。

浏览器里跑的是 Ghostty 的 WASM 版本

网页终端最容易被忽略的一层,是它没有用 xterm.js。前端加载的是 @wterm/ghostty:把 Ghostty(终端模拟器,当前 1.3.1)的 VT 解析核心编译成 WebAssembly,约 580 KB,再由 wterm 用 DOM 网格渲染。

这个选择在 2026 年基本是唯一正确答案。VT 序列的坑——Unicode grapheme 簇、SGR 属性、Kitty 图形协议、超链接——自己重写一遍几乎必然踩坑,直接复用经过大量真机验证的解析器,前端只负责格子和输入编码,工程量差一个数量级。

密钥、片段与 Agent 状态怎么跟着人走

除了终端本身,Frog 还有一层 vault:SSH 密钥、主机密码、机器列表、代码片段、工具栏、助手配置都存在里面,逐条在客户端加密,服务端只存密文和条目计数。

  • 浏览器侧用 passkey 的 PRF 扩展派生一把密钥来封套主密钥,所以同一台电脑换个浏览器、解锁 vault 就能直接连,不必重新配对;
  • 恢复靠 24 词助记词或自定义主密码(口令派生走 argon2 / scrypt 这类内存硬算法);
  • 配对握手用 HPKE 混合封装,并且把 ML-KEM(后量子)一起打包,加 ECDSA P-256 签名和会话哈希;
  • 新设备免密码接入,是在另一台已解锁的设备上扫码批准,而不是输密码。

跨设备的「看起来实时」则靠一条轻量变更通知:/api/v1/sync/watch 的 WebSocket 推「有变化」,客户端回源拉取;同一浏览器的多个标签页用 BroadcastChannel 和 Web Locks 选出一个主控,避免重复拉取。冲突不做自动合并,逐条让人决定保留哪一边。

面向 Agent 的那一层也在这套结构上:给 Claude Code、Codex、OpenCode、Hermes、Pi 装 hook 后,agent 会在等你审批、干完活、卡住时上报;手机上直接看到列表并点 Allow / Deny。值得注意的克制——推送通知里只带 id,agent 说了什么只走 SSH 通道。

它不适用的场景

诚实地说,这套设计有几处硬约束:

  • 没装 tmux 或 Zellij 就退化。官方文档直写:不装的话「断线即死」,和普通 SSH 客户端没有区别。
  • 多客户端尺寸按最小的走。手机竖屏会把电脑上 vim 的布局挤窄,这是 tmux 的行为,Frog 只提供 capture-pane 快照兜底。
  • 网页端进不了私网。浏览器路径必须经过 Frog 边缘,VPN 内的机器只能走配对。
  • 还是 alpha。版本号仍是 0.1.0-alpha.117,SSH 相关的底层库(ssh-key)还在 RC 阶段,升级会有兼容窗口——产品里那个 needsUpdate 状态就是为这种时候准备的。

定价与入口

官网定价是免费的:$0,最多 100 台配对机器,配对、终端、Agent 审批、加密 vault 同步全包。Pro 是 $5/月、$50/年或 $199 买断,多出来的只有两项:自建 relay,和手机端的干净分享卡片。宿主机程序用一行 curl -fsSL <https://usefrog.app/install> | sh 安装,安装脚本会先校验发布签名再解包。

如果你正在用 Claude Code 或 Codex 跑长任务,「不在电脑前也能看一眼、点一下」这个需求其实很难用别的方式满足——Tailscale 加手机 SSH 客户端能连通,但会话状态还是要靠自己维护 tmux。Frog 把这一步直接做成了产品前提。

关联阅读

来源

复制成功后将正文粘贴到公众号后台即可发布