指南
这个 App 就是为这条路存在的。四步:连上主机、把 herdr 装上、起 Claude Code、 在锁屏上回它的权限询问。这一页里出现的每一条命令和每一句提示,都是 App 里真实的那一份, 不是示意。
填 SSH 信息、核一次主机指纹、把这条连接的 Multiplexer 选成 herdr。
在 herdr 的 pane 里敲 claude;或者让 Moshpit 现开一个
git worktree,在里面起 Claude Code。
Claude Code 要人点头的时候,锁屏会告诉你,并且直接给你回它的按钮。
开始之前你得有什么。一台你本来就能 SSH 上去的服务器、一台 iOS 18 以上的 iPhone、以及服务器上已经装好的 Claude Code。Moshpit 不负责装 Claude Code,也不和 Anthropic 通信——它驱动的是一个真实的 shell,Claude Code 只是跑在里面的一个程序。
herdr 不是必需的。它的价值在于把「agent 现在什么状态」从猜变成读,所以这份 指南用它。走 tmux 那条路一样能成,见 用 tmux 和 在锁屏上回应 agent。
第一步
四个字段加一次指纹核对。如果你在电脑上本来就能 ssh 上这台机器,
这一步一分钟就完了。
首页右上角点 +。表单是分组的:
Name、Host、Port
(默认 22)、Username。Name 和 Host 填了,Save 才会亮。Password 或 SSH Key。密钥可以是你在
Settings → SSH Keys 里生成的,也可以直接把 PEM 贴进表单。Multiplexer 选 herdr。下面那个自定义路径除非
你的二进制放在很偏的地方,否则留空:填了路径就等于你替它担保,能力探测会被整个跳过。多路复用器是按连接选的,不做全局默认。你手上的机器本来装的东西就不一样, 一个全局默认只会换来「怎么就这台连不上」。
第一次连的时候握手会停下来,Moshpit 把对方给出的主机密钥摆给你看:
New Host
First connection to your-host:22.
Key fingerprint:
SHA256:…
Verify it matches the server (e.g. `ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub`).
[ Cancel ] [ Trust ]
Moshpit 没法替你验这串指纹,它能做的是把该敲的命令一并写给你。 如果以后某台主机的密钥变了,这个对话框会换成 ⚠️ Host Key Changed,两串指纹都印出来,默认按钮是 Disconnect, Trust New Key 被标成破坏性操作。
这里有条限制,现在就该知道。App 里没有任何一个地方能列出或删掉已信任的主机密钥。 删掉一条连接,它的指纹还留着;信任是按设备存的,而且排除在备份之外——换台手机,每台主机都会 重新问你一遍。主机正当换了密钥之后,唯一的 App 内路径就是在那个 ⚠️ 对话框里接受变更。
还有:直接填在连接表单里的密码和 PEM,保存时没有加 Face ID 门禁;只有在 Add Key 里建、并且开了 Require Face ID 的密钥才会每次读取都验人。 带密码短语加密的私钥则完全用不了。
第二步
herdr 是专门为 CLI coding agent 写的 Rust 单二进制。它把
agent_status 做成了每个 pane 上的协议字段——这就是为什么 Moshpit
不用你在主机上装任何东西,也知道 Claude Code 正等着你。
# macOS / Linuxbrew brew install herdr # 其它情况 curl -fsSL https://herdr.dev/install.sh | sh
这里给不出 apt-get 那一行:herdr 不在任何 Linux 发行版仓库里,
它自己的 packaging 只覆盖 Windows。Moshpit 也拒绝硬凑一条
sudo apt-get install -y herdr——一条以「找不到软件包」收场的命令,
用户只会当成是 App 的 bug。
安装脚本把二进制放进 ~/.local/bin,并且刻意不动你任何 rc 文件。
Moshpit 在探测和拉起 herdr 时都会把这个目录加进 PATH,所以主机那边你什么都不用改。
选了 herdr 却连到一台没装它的主机上,你得到的是一条可关闭的横幅, 而不是一次失败:
这套集成是对着哪个版本写的。设计基准是 herdr main / v0.8.0,protocol 19;
真机验证跑的是 0.7.3,protocol 16——当时 brew install herdr 装到的就是它。
snapshot 解码器按「字段缺了就降级这一处细节,绝不让整份读取失败」写。
0.7.3 上看得见的代价:它不上报 pane 的命令,所以终端面包屑的第三段会回落成
pane N,而不是告诉你里面跑的是什么。这一段仍然保留,因为它是进
Select Pane sheet 的唯一入口。
这份指南请走 SSH,不要走 Mosh。Mosh 传的是渲染后的屏幕差分,会毁掉按行分帧,
所以它扛不动 herdr 的 frame 协议(tmux -CC 走不了 mosh 是同一个原因)。
走 Mosh 时 herdr 跑的是它自己的全屏 TUI,Moshpit 只是个渲染器——在手机上,
herdr 的侧栏大概要吃掉三分之一屏宽。控制面的那些 sheet 仍然可用,走的是另一条 SSH 旁路。
第三步
两条路。在你已有的 pane 里跑,或者让 Moshpit 开一个隔离的 git worktree 在里面跑。后一条才是在手机上真正值得用的那条。
没有新东西要学
一个 worktree、一个 workspace、一个 agent
两条路上 herdr 都是靠屏幕内容推断出这是个 agent。想要它被上报
而不是被推断,在主机上跑一次 herdr integration install claude,
之后 Claude Code 会自己汇报状态。这更权威,但不是必需的——这一页里的一切,
不装它照样成立。
TASK 组,脚注:“Creates a git worktree on the host, then starts the agent inside it. Your working tree is untouched.”
git rev-parse --show-toplevel 反查 git 根;以及按修改时间扫一遍
$HOME。找的过程中菜单写
“Looking for repositories…”;一个都没找到就写
“None found — no panes in repos, and nothing under ~”。最后一项永远是
Other…,点开露出一个 Repository path 输入框。- 或 /、结尾的 /、..、
结尾的 .lock,以及 ~ ^ : ? * [ \ 这些字符,都会被顶回来,
并给一句人话,比如 “No spaces in a branch name”。herdr server agent-manifests --json 读。默认优先
claude,然后 codex,再回落到第一个。(按字母序排的时候,
真机上默认值填进去的是 agy,所以现在不按字母序了。)FIRST MESSAGE 组,脚注:“Optional. Sent to the agent once it's running — leave blank to type it yourself.” 点 Start 之后按钮会变成 Starting…——大仓库 checkout 要几十秒,一个从不变化的按钮读起来就像坏了。
三条命令,按顺序走 SSH。没有任何一步是藏着的;你填的每个标签在靠近 shell 之前都会被单引号包好。
herdr worktree create --cwd '~/code/payments-api' --branch 'fix-webhook-retry' \
--label 'fix-webhook-retry' --focus --json
→ {"type":"worktree_created",
"workspace":{"workspace_id":"w4"},
"root_pane":{"pane_id":"w4:p1",
"cwd":"~/.herdr/worktrees/payments-api/fix-webhook-retry"}}
herdr pane run 'w4:p1' 'claude' <- 把命令敲进去并回车
herdr agent send 'w4:p1' '<第一条消息>' <- 2 秒后,只在你填了的时候
一个新的 git worktree、一个新的 workspace、一个 cwd 已经在里面的 pane,
并且焦点已经过去了。第二步刻意用 pane run 而不是 agent start:
实测 agent start --workspace 不继承 worktree 的目录,新 pane 会落在
发起命令的那个目录里。pane run 敲进去的就是你自己会敲的那一行,而且你看得见。
真机验证那一轮:workspace 起来了,cwd 是
~/.herdr/worktrees/…/fix-scroll-jump,git worktree list
确认分支是真建了,Claude Code 真的起来了,停在它的信任目录提示上。herdr 把这个 pane
标成 agent: claude / status: blocked,首页的 Agents 区随即显示
AGENTS 1 · NEEDS YOU。那第一个提示,就是第四步里你要回的那个。
首页长按那条 workspace → Remove Worktree。这个菜单项只在真的是
linked worktree 的 workspace 上出现。第一条命令绝不带 --force:
payments-api itself is untouched.”--force。这是 herdr 自己的安全网,
不是我们发明的——顺着它比替你做决定好。这一步的边界,摊开讲。
worktree 落在 ~/.herdr/worktrees/<repo>/<branch>,不在仓库旁边,
这一版也没有自定义路径的选项——那不是个值得在手机上打字的东西。大仓库 checkout 要几十秒。
对着一个脏仓库跑 git worktree add 预期没问题(它本来就是独立 checkout),
但还没验证过。
agent 的启动参数不替你选。manifest 里 claude 的默认命令是什么,
跑的就是什么。像 --dangerously-skip-permissions 这种,得你自己在 pane 里敲。
herdr 只看得见自己 pane 里的 agent。你在 Terminal.app 里起的那个
claude 不会出现——herdr 是 runtime,不是进程扫描器。这条实测踩过:
五个 herdr pane 全在空转、另一个终端里 claude 跑得正欢,而 Agents 区诚实地写着
“Nothing running — start a task to isolate one”,用户则确信有东西在跑。
没在设备上验到的一处:长按出来的那个上下文菜单本身。自动化驱动不了 SwiftUI 的长按, 所以「菜单 → 对话框 → 对话框」这段只有编译和单测保证,没有设备录像。
第四步
Claude Code 停下来问你能不能跑某条命令。琥珀色在这个站上只有一个意思—— 「有 agent 在等人」——它出现的地方就是这里。
正卡着的那一条 状态点、等宽字体的命令名、位置写成 主机 · workspace · tab,右边一个在走的计时器。 最紧急的那个排最前,也只有它带按钮。
其余的 headline 以下全部收成一行状态。这是故意的:iOS 会把过高的 Live Activity 裁掉, 而当初掉出屏幕的,正好就是第二个 agent 的 Allow 和 Deny。
按钮跑在哪 跑在 Moshpit 自己的进程里,不在 widget 里。你点一下,iOS 会把 App 拉到后台执行。 屏幕不用解锁。
就是往 Claude Code 那个 pane 里发原始按键。没有别的,也没有什么聪明操作。
| 按钮 | 发进 pane 的字节 | 什么状态下出现 |
|---|---|---|
| Allow | 0x0d——一个回车,选中当前高亮的那一项 |
需要你 |
| Deny | 0x1b——Esc,取消 |
需要你 |
| yes / continue | 这段文字,然后回车 | 需要你 |
| Stop | 0x03——Ctrl-C |
工作中 |
| Reply | 你输入的文字,然后回车 | 通知上的操作 |
这套映射是对着 Claude Code 的权限提示调的——肯定项默认高亮、Esc 取消,
这个形状也吻合绝大多数 TUI 的 yes/no 菜单。但它们是盲发的按键:Moshpit 不解析提示内容,
不会去确认此刻高亮的到底是哪一项。yes 和 continue 是快捷回复,
它们是往 pane 里打字,不是往什么聊天框里发消息。
agent focus,等切换真的完成了再写入。这条是被一个真 bug 逼出来的:
两个 agent 并发时,锁屏上的 Allow 可能变成别人的回车。Settings → NOTIFICATIONS,四个默认都是开的。
Bash: npm install 那一行。Notifications 和 Live Activity 两个都关掉,就什么都不看了。 herdr 连接下,Install agent hooks 那一行是隐藏的——没东西要装。
一处得说在前面的现状:Live Activity 上的按钮和通知里的操作名,目前只有英文 ——Allow、Deny、Reply、Stop,以及 “Not delivered”、 “Prompt already gone” 这两条提示都还没有中文。App 内的界面是中文的,锁屏这一层还不是。
解锁时 · 需要你 一个 agent 卡住就是琥珀色感叹号,多个就是数量。胶囊里只放得下一个—— 展开后的 Switch 按钮用来轮到别的。
解锁时 · 工作中 Claude Code 在跑的时候是青色加一个走着的计时器。在想的 agent 和卡住的 agent 长得不一样。
诚实的那一段
在你打算依赖上面那一切之前,这一段才是该读的。它是「中间不放服务器」这个决定的 必然代价,也不是任何一个设置能关掉的。
Moshpit 里没有任何推送服务器。你手机上的每一条提醒,都是正在跑的 App 从活着的那条会话里就地生成的本地通知。iOS 一挂起 App,那个 2 秒的轮询和 SSH 的拉取 也跟着停了。
真机实测:App 切到后台之后,把一个 pane 从 blocked 翻到 working,灵动岛 纹丝不动;只有回到前台、再过一个轮询周期,它才翻过来。tmux 那条路同理—— 这是「不做远程推送」这个产品决定的结果,不是 herdr 的问题。
Moshpit 2 working · 1 needs you
● claude needs you 2m
mac-studio · ~ · Tab 1
Bash: npm install
[ Deny ] [ Allow ]
…… App 被挂起两分钟 ……
Moshpit paused — open Moshpit to refresh
Live Activity 带着一个 120 秒的过期线——两个轮询周期没跟上—— 到点就渲染成诚实的「暂停」,而不是一个冻住的「working」。桌面小组件用的是 180 秒, 过期后把所有状态点都压成灰的。
now、2m、
1h 12m,从不印秒。背后的数据本身就有最多 8 秒的粗糙度,
印出秒来等于宣称一个它没有的精度。herdr 的直连是按 pane 独占的。Moshpit 必须带
--takeover 去 attach,因为每次重连都会和自己那条还没死透的旧通道撞上。
于是两台手机连同一个 pane,就会每两秒左右互相抢一次。这是独占式直连的固有行为,
在客户端消不掉。
Moshpit 能做的是:30 秒内被非预期地踢掉 3 次,就暂停 30 秒并给一条看得见的提示 ——“Another client is using this pane — retrying shortly”—— 等画面重新出帧就自动消失。你电脑上跑 herdr 自己的 TUI 不占 attach 名额, 所以「电脑 TUI + 手机」理论上是安全的,但这个组合没有被验证过。
零碎问题
不用。走 tmux 的话,去 Settings → NOTIFICATIONS → Install agent hooks
装一次 hook:一条命令,把 Claude Code 的 UserPromptSubmit、
PreToolUse、Notification、Stop 注册上,
让它们把状态盖到 tmux 的 pane 上。它会先备份
~/.claude/settings.json,永远 exit 0 所以挡不住 agent,
重复跑会自己去重。不装 hook 的话,Moshpit 退回去读 pane 输出和终端响铃——
那是猜,文档里也是当猜来写的。首页的 Agents 区块则是 herdr 独有的。
不能。没有推送服务器,所以提醒只在会话还活在你设备上的时候存在。iOS 会挂起连接, 状态会停更,直到你回来。见上面那一段。
想让一个 shell 扛过 Wi-Fi 切 5G,Mosh 是对的选择,但它扛不动 herdr 的 frame 协议,
也扛不动 tmux -CC。走 Mosh 时 herdr 在终端里跑自己的 TUI,侧栏要占掉手机
大约三分之一的宽度;控制面的 sheet 仍然通过另一条 SSH 旁路工作。这份指南请用 SSH。
细节见 Mosh 与漫游。
那基本可以肯定它不在 herdr 的 pane 里。herdr 靠观察自己的 pane 认 agent,
所以在 Terminal.app 或另一条 SSH 里起的 claude 对它是不可见的。
用 New Agent Task 起,或者手动在 herdr 的 pane 里跑。herdr 0.7.3 上还有第二层原因:
它不上报 agent 名字,所以空闲状态的 agent 根本长不出那一行。
没有 Moshpit 账号、没有中转、也根本没有 Moshpit 的服务器。App 只连你自己添加的机器。 唯一会离开 pane 的,是 hook 抓到的那一行短标题——agent 正在跑什么或问什么,截到 80 个字符 ——它渲染在你自己的锁屏上,并且可以用 Show detail on lock screen 关掉。
连接与密钥讲完整的表单和主机密钥行为, 用 herdr 讲术语和键位, 在锁屏上回应 agent 把通知和 Live Activity 那条链讲透。连不上或者行为奇怪,看 排查。