一个 Go 二进制 · 前端嵌在里面

对着 agent 说话,
平板也是生产力

不用装 app。安卓、苹果、平板,扫个码就连上。

不另做一个手机版:网页里是整个 TUI,键盘那套操作一个字都没变。 补的只是手指够得着的那一层 —— 一个真正的输入框、一排自己排的键、 一块能挪开输入法的面板。

$npm i -g @bysir/herdr-web

需要一个已经在跑的 herdr。MIT,源码在 GitHub。

zsh 42×28
herdr-web git:(main) make test
ok internal/auth 0.8s
ok internal/server 1.9s
herdr-web git:(main)
⟳ w9:pE · claude working
把发件箱那个轮询间隔改成可配的,默认别动,然后跑一遍 make test。
↑ 取回上一条投稿 ⌘↵
^B 前缀CtrlEscTab
01/ 06能力

安全

谁摸到那个地址,谁就有你的机器。

在 README 里细看

Cloudflare Tunnel、Tailscale、frp —— 穿透搭得越好,安全风险就越大

没有鉴权这一层,具体是这三件事:
穿透那头直接就是一个登录 shell

穿透只负责把包送到,不做鉴权 —— 连上来的是谁,它不问。

地址或 token 泄露一次,就一直有效

浏览器历史、一张截图、一份 frp 配置、tailnet 里任何一个节点。泄露之后,没有任何一步会再拦你。

丢了一台手机,只能把整条通道换掉

所有设备共用一份凭据,就没法只踢那一台。

所以鉴权这一层 herdr-web 自己做,按「这条路可能已经不安全」来做

扫一次码

一次性配对码换一份 per-device 凭据,放 HttpOnly cookie。URL 里不留秘密。

服务端只存哈希

磁盘上没有任何能直接登录的明文 —— 防止坏 agent 把你的凭证发出去。

能撤销

一条命令踢掉一台设备,下一个请求就 401。

herdr-web 的配对页:提示在机器上执行 herdr-web pair,可以用相机扫二维码或手输 8 位配对码
一台设备只见这页一次。只有坐在机器前的人能出码 —— 网页上(包括已配过对的设备)都不行。

为什么推荐使用 passkey

配对码给的是第一层,passkey 是第二层。 差别在这儿:
只有第一层
  • 凭据就是一份 cookie —— 谁拿到,谁就是你
  • 泄露之后一直有效,直到你想起来撤销
  • 没有任何一步会再问一次「还是你吗」
加上 passkey
  • 私钥锁在设备里出不来,服务端只存公钥 —— 被读也没用
  • 默认每 24 小时重验一次,cookie 就算泄露,窗口最多一天
  • 签名绑着 origin,钓鱼站点拿不到能用的那一份
代价是得有个域名:passkey 的签名认的是域名,裸 IP 注册不了 —— 用 IP 连只有第一层,配个域名才有第二层。哪一档要准备什么,见放在哪儿跑
02/ 06能力

双向同步的发件箱

按了 Tab 补全、上下翻历史 —— 终端里已经有字,框里还空着。这时候投出去,两段叠一起。

在 README 里细看

所以框里那段和终端的输入行是双向的:终端那边多出来的字,框里跟着有。 框本身也是终端给不了的东西 —— 终端是字节流,没有选区,输入法只能一路往里灌字符; 落在一个真正的可编辑框里,才能说完一整段再投,说错的字框选重说就改掉。

发件箱:状态行写着这段话会投给哪个 pane,框里有四个字被选中,底下是软键条
真实截图。选中的那四个字,再说一遍就被替换掉;状态行一直写着这段话会投给谁、投得出去投不出去。
投给谁不用选

默认跟着 herdr 当前 pane,也能在下拉里钉死一个。

整段投递 ⌘↵

先清空远端输入行再提交。Enter 只换行 —— 说到一半不会被回车打断。

拉回来改

把远端输入框里已有的内容抓回来编辑,默认 500ms 一拍。

图片也能投

存到跑 herdr 那台机器上,把绝对路径插进提示词,agent 自己去读。

03/ 06能力

软键条

手机键盘上没有 Ctrl,herdr 的快捷键一个都按不出来。

在 README 里细看

herdr 的快捷键全靠 ^B 前缀,所以键做成一条自己排的横条 —— 排什么、排几个都归你。 按键存在服务端,手机 / 平板 / 电脑共用一份,网页上改完三台一起变。

一个键可以是一串

ctrl+b c 一下点出来。具名键、组合键、原样文本都行。

Ctrl / Alt 是粘滞的

点一下亮起,再敲个字母就发出组合键 —— 手机 keydown 不可靠,这层做在数据流上。

危险的键点两下

关 pane、关标签、/clear 默认就带。软键条上键挨得近,误触没法撤销。

六十多个预设

一键灌进「我的按键」,之后每个都能改名字、改谱、改宽度。

手机上的复制粘贴也在这儿

herdr 复制到的是跑 herdr 那台机器的剪贴板,手机上哪儿都粘不出来。📋 取把它拿到手机剪贴板,📥 粘反过来 —— 浏览器只在点击里给剪贴板,所以只能是两个键。

设置里的软键条编辑器:上面是条上的键,下面是「我的按键」库,六十多个预设铺在里面
上面是条,下面是「我的按键」。条上放的是引用 —— 拖上去,库里那个不动。
04/ 06能力

面板一览

十几个 agent 在跑,哪个在等你回话?一个个翻是翻不过来的。

在 README 里细看

软键条发的是按键,而按键只会说「下一个 tab」。 想直接跳到 w5:p3,说不出来,只能一步步走过去 —— 中间每一屏, 正好是手机上根本读不了的那个平铺状态。

面板一览:一行一个 pane,带 tab 名、路径和 pane id,上面能筛能切排序
真实截图。一行一个 pane,上面能筛(tab / 标题 / 路径)、能只看跑着 agent 的。
跳过去就自动全屏

电脑上你习惯分屏 —— 一屏铺四个 pane,扫一眼就知道哪个在干什么。 同一个会话切到手机上,那四格每格只剩巴掌大:字看不清,更别说在里面操作。 所以点面板里那一行,跳过去的同时就把它铺满整屏,不用你再手动放大一次。

等你的排最上面

等你回答 > 跑完了 > 在跑 > 闲着。红点=等你,绿=跑完了,黄=在跑,闲着不上色。

有变化就弹一张卡

卡上带 agent 说的那段话 —— herdr 的接口里没有这个字段,是读屏抽出来的。点一下跳过去。

角标带未读数

顶栏和软键条那个键上各一个,写着还有几条没看。开一次面板就算看过,刷新页面不丢。还能发系统通知,页面切到后台也收得到。

每行都带 pane id

一个 tab 分成两个 pane 时,两行的标签和路径一模一样,只有 id 不同。

点完看的还是同一个 herdr 终端,键盘那套操作一个字都没变。 这张表只管带你过去,不在上面改东西。

05/ 06能力

文件浏览

手机上没有文件浏览器 —— agent 生成的那张图,你打不开。

在 README 里细看

agent 说「图生成在 /tmp/plot-3.png」—— 终端里那行路径就是个链接,点一下图就开了。 想翻文档、翻别的图,点顶栏的 📁。

文件面板:顶上一个粘绝对路径的框,下面是各 pane 的 cwd、家目录、临时目录
📁 里的起点是各 pane 的 cwd + 家目录 + 临时目录,一路往上能走到 /。也能直接粘一条路径进去。
文件查看器:顶上是文件名、绝对路径、大小和类型,右边能复制路径、打开所在目录、新标签打开、投给 agent
看图这一屏。右上角能复制路径、开所在目录、新标签打开(那儿能长按存到相册),以及直接投给 agent。
默认没有边界

能打开这页的人已经有一个登录 shell,白名单挡不住他、只会天天挡路(agent 往 /tmp、~/Downloads 写东西是常态)。要边界就配 FILE_ROOTS。

图直接看,别的只给下载

按魔数认类型,改后缀骗不过去。

SVG 也直接看,但只在 <img> 里

SVG 是能跑脚本的图片。放进 <img> 就落进规范的 secure static mode —— 脚本不跑、外部资源不加载,而且这条不看任何响应头,前面的代理把 CSP 剥了也还在。

绝不以 text/html 吐

同源的 HTML 就是一个能调接口的跳板:agent 写个 html,你点开就把 herdr 交出去了。

看完能投给 agent

把绝对路径插进发件箱,和传图完全同一个模型 —— 让它自己去读那个文件。

06/ 06能力

布局

平板卡在中间:屏够大,值得排一套自己的;可它没有键盘。

在 README 里细看

为了适配平板,软键条做成能拖的 —— 配系统的悬浮键盘正好, 横屏竖屏都好用。

herdr-web 的界面:左边是两个 pane 的终端,右下角是缩到半边的底部面板
真实截图。整块面板缩到了右半边,左边让给输入法 —— 键那排上边缘三条把手就是拖的地方。
横屏竖屏各存一套

平板横过来是一种用法,竖过来是另一种。两套分开存,调横屏那套不会动到竖屏那套。

平板上配悬浮键盘最顺

把系统键盘捏成悬浮那种(游戏键盘),挪到顺手的一边,中间让给终端。软键条照常在 —— 打字、语音、Ctrl / Esc / 方向键,三样同时在手边。

适配触屏

能滚、能点、能拖 pane

单指滑动按行高换算成滚轮上报发给程序
单击发一次鼠标点击(点 pane、点 tab 都好使),当场就发、不弹键盘
长按拖动 pane抓住不松手(≈380ms),之后滑动就是拖 —— pane 边框靠这条挪。
放在哪儿跑

不用域名、不用公网,同一个 Wi-Fi 下就能连

代价只是每台设备第一次点一下「继续访问」。嫌这一下麻烦, 加个域名走 C;出了门也想连,再加个公网入口走 D。 要手机连就必须有 TLS,herdr-web 已内置 ACME 走 DNS-01 认证 —— Cloudflare、AWS Route53、阿里云、腾讯云、华为云、DigitalOcean 六家都能签。 所以 NAT 后面、域名指到内网地址,照样签得出受信任证书。

场景怎么用要准备什么授权方式
A只本机访问 127.0.0.1不用准备什么配对码(IP 下没有 passkey)
B局域网 · 用 IP访问局域网 IP不用准备什么,第一次点一下「继续访问」配对码(IP 下没有 passkey)
C局域网 · 用域名访问域名一个域名 + DNS 的 API token第一次配对码,后续 passkey
D公网在哪儿都访问域名域名 + DNS token,外加 Cloudflare Tunnel / Tailscale / frp 之一第一次配对码,后续 passkey
管理页只绑 127.0.0.1

看证书、点一下续期、出配对码、踢设备,全在一个公网上不存在的口上。

在同一个 Wi-Fi 上就自动走直连

从公网那个地址进来时,网页探一下能不能直接连到这台机器 —— 能就切过去,按键不再绕一趟 VPS。交接走的是单独的一次性短令牌(60 秒、只能在直连口兑),踢掉上级会级联撤销。

断线自动重连

手机切前后台、地铁里断一下,回来自己接上,不用去点那个「连接」。

要从公网连得自己声明

为了安全,默认不开启公网访问,需要显式设置 HERDR_WEB_EXPOSED=1

开始

安装并使用

有 node
npm i -g @bysir/herdr-web
herdr-web

只听 127.0.0.1:7788,连上自动敲 herdr。管理页在 7789。

没 node
curl -fsSL https://raw.githubusercontent.com/zbysir/herdr-web/master/install.sh | sh

装到 ~/.local/bin。强制校验 sha256 —— 这东西后面挂着一个登录 shell。

手机连局域网
HERDR_WEB_HOST=0.0.0.0 herdr-web

自动自签证书,终端里画一个二维码给手机扫。

常驻 + 自更新
herdr-web service install
herdr-web update

user 级:macOS launchd / Linux systemd。配置是装那一刻从 shell 抄进去的 —— 改完要重新 install(幂等,覆盖 + 重启)。

地址栏里加一段路径就是另一个 herdr session/work/scratch)—— 存两个书签就是两套工作现场,关掉浏览器再回来还在。

Windows 没有原生版,在 WSL 里装 —— 浏览器里那个终端要一个真 PTY。 全部配置项(只认环境变量)看 README

Render diagnostics