firstmate

框架

kunchenguid/firstmate

单一入口管理多智能体协作的智能体发行版。

项目简介

firstmate 是一个智能体发行版,让一个主编码智能体统一调度一组自治协作者。它提供独立的 git worktree、tmux 会话可视化以及重启后仍持久的状态管理,支持 Claude Code、Grok、Pi 等多种终端智能体。

README 预览

firstmate\n\n  \n  \n  \n\n\nTalk to one agent. Ship with a crew.\n\n\n  \n\n\n## What it is\n\nYou can run one coding agent easily.\nBut the moment you want three project tasks done in parallel - fixes, investigations, plans, audits - you become a tab-juggler: babysitting sessions, copy-pasting context between repos, forgetting which terminal had the failing test.\n\nfirstmate flips the model.\nYou talk to a single agent - the first mate - and it runs the crew for you: spawning autonomous agents in a visible session backend, giving each a clean git worktree, supervising them to completion, and handing you finished PRs, approved local merges, or standalone investigation reports.\nFor larger fleets, you can opt in to persistent secondmates: second mates that are still ordinary direct reports, but run from their own isolated firstmate homes on this machine or another SSH-reachable host.\n\nfirstmate is not a model, not a harness, not a skill, not an MCP server, and not a CLI.\nfirstmate is an agent distro for running a crew of agents.\nAn agent distro is a portable directory of instructions, skills, tooling, policies, and state conventions that turns a general-purpose agent into a specialized one.\nThere is no app to install: the cloned repo is the distro - `AGENTS.md`, bundled firstmate skills, and helper scripts that any terminal coding agent can follow.\nLaunching a supported harness inside it instantiates your first mate - and makes you the captain.\n\n## Features\n\n- **One liaison** - you talk only to the first mate; it dispatches, supervises, escalates only real decisions, and reports plain outcomes.\n- **A visible crew** - every crewmate works in its own tmux window, experimental herdr/zellij tab, cmux workspace, or Orca terminal you can watch or type into; the first mate reconciles.\n- **Disposable worktrees** - each task runs in a clean [treehouse](https://github.com/kunchenguid/treehouse) git worktree, or an Orca-managed worktree when `backend=orca`, so par

常见问题 (5)

故障排除
当第二个 Linux 或 macOS 用户运行 fm-teardown 时,如何修复"herdr session presentation lock could not be resolved"错误?

失败的原因是 Firstmate 使用机器全局目录 /tmp/firstmate-herdr-presentation,要求该目录归当前 UID 所有且权限模式为 700,并且即使在 presentation 被禁用的情况下,fm-teardown.sh 也会解析此锁。--force 无法绕过该限制。临时解决方法:在没有活动的 Herdr presentation 会话时,让目录所有者使用 rm -rf /tmp/firstmate-herdr-presentation 删除该目录,然后立即以被阻塞用户的身份重新运行 bin/fm-teardown.sh <task>;之后可能需要再次删除该目录。或者,使用 sudo chown <blocked-user>:<blocked-group> /tmp/firstmate-herdr-presentation 一次性移交该目录的所有权。为避免在共享主机上反复发生冲突,请在主账户上将 config/backend 设置为 tmux,以便远程 home 继承该设置,或者应用/修补按账户划分的命名空间,例如 /tmp/firstmate-herdr-presentation-$UID 或 $XDG_RUNTIME_DIR/firstmate-herdr-presentation。该问题在 Firstmate 8b10b61e 和 Herdr 0.7.4 上观察到;相关修复正在 PR #2730、#2530 和 #5804 中跟踪。

来源 Issue #4716
故障排除
如何修复间歇性的 fm-watcher-lock stale-steal 失败:'expected exactly one stale-lock stealer, got 0' 和 'reap race hook never fired'?

这些是测试夹具中的竞态问题,而不是锁实现的 bug。请修改 tests/fm-watcher-lock.test.sh:

1. 在 test_lock_stale_steal_single_winner_under_concurrency 中,不要依赖 40 个一次性的 fm_lock_try_acquire 调用来产生一个胜者。在负载情况下,每个非阻塞的竞争者都可能看到 .steal 互斥锁处于忙碌状态并退出。应使用 39 个非阻塞竞争者,外加一个 fm_lock_acquire_wait 竞争者。让等待的竞争者通过 FIFO 报告其获胜,然后断言恰好只有一个 FIFO 胜者。

2. 在 test_lock_steal_reap_cannot_remove_successor 中,不要杀死一个夹具进程并将其 PID 留在锁中,因为操作系统可能会复用该 PID。应创建一个专用进程,确认它已经终止,并将这个已确认死亡的 PID 写入锁夹具中,以保证 reap 路径一定会被执行。

锁实现本身不需要更改。该稳定性修复由 PR "test: stabilize watcher lock race fixtures" 覆盖;下游验证可在 ironerumi/firstmate#69 中查看。

来源 Issue #6455
故障排除
为什么 fm-send.sh --help 会报错 "target '--help' is not resolvable",而不是打印用法说明?

bin/fm-send.sh 没有 -h|--help 处理分支:FM_HOME 检查会首先运行(约第 231 行),而选项解析(约第 486 行)仅覆盖 --resolve-key / --fire-and-forget,因此 --help 会被传递给目标解析,并以一条误导性的提示失败,建议使用 fm---help。修复方法:升级到包含 PR #6402 的版本,该 PR 增加了一个前置的 -h|--help 分支,在 FM_HOME 检查和目标解析之前打印脚本头部的 Usage: 块并以退出码 0 退出。受影响版本的临时解决方案:直接从头部注释中读取用法约定,例如 sed -n '1,40p' bin/fm-send.sh,因为头部是 steering、--resolve-key 和 pending-reply 约定的文档化来源。

来源 Issue #6398
故障排除
当目标会话无效或不活动时,如何修复 Herdr composer probe 导致 Bash 管道挂起的问题?

升级到包含 issue #6915 修复的构建版本(fix(bin): keep herdr composer probes observable-only without autostarting server)。挂起问题的发生原因是 fm_backend_composer_state 调用了 fm_backend_herdr_target_ready,而后者会启动 herdr server;后台辅助进程继承了管道描述符 10,因此诸如 ... | head -20 之类的命令永远收不到 EOF。

在 bin/backends/herdr.sh 中应用以下代码修复:
1. 在 fm_backend_composer_state 中,将就绪/自动启动检查替换为被动的可观察性/状态检查。
2. 如果会话未激活、不存在,或者目标是裸窗格 ID(例如 wPW:p2),则立即返回 unknown,而不调用 fm_backend_herdr_server_ensure。
3. 作为纵深防御,将后台服务器进程与继承的描述符分离,例如:
( exec herdr server --session "$session" ) </dev/null >/dev/null 2>&1 10>&- &

即时规避措施:仅探测会话已在运行的目标,避免对不受信任的目标通过管道传输探测命令,使用 timeout 包裹探测命令,并通过以下命令移除失控的服务器:
pkill -f 'herdr server --session nonexistent-session'

来源 Issue #6915
故障排除
如何修复在 Claude Code 后台会话中运行 /clear 后出现的 "another live firstmate session holds the lock" 错误?

Claude Code 后台会话(claude --bg-pty-host)在 /clear 之后可能会错误地将自己的 fleet 锁检测为外部持有,从而进入只读状态并阻塞所有 fleet 变更操作(drain、spawn、steer、merge)。原因:/clear 会生成新的 CLAUDE_CODE_SESSION_ID,而进程 pid(CLAUDE_PID)保持不变,因此当 state/.lock 的第 1 行记录的是过时的非祖先 pid(例如终端前端 pid)而非模型循环 pid 时,所有权检查会失败。

临时解决方法:删除过时的锁并重新获取:
rm state/.lock && bin/fm-lock.sh
重新获取后,第 1 行变为模型循环 pid,会话恢复正常运行。

永久修复:修改 bin/fm-lock.sh 中的 confirm_own_lock,使得当通过可信的同会话 ID 路径确认所有权、且 CLAUDE_PID 与记录的存活 pid 不同时,将第 1 行重写为 CLAUDE_PID(会话的锚点)。这样可以使锁在 /clear 之后仍然有效,因为无论会话 ID 如何变化,祖先成员检查都能通过。可选地,还可以将来自同一 CLAUDE_PID 且带有 source: "clear" 的 SessionStart 钩子事件视为同一会话。

预防措施:确保 state/.lock 的第 1 行始终刷新为会话自身的 CLAUDE_PID,而不是启动它的前端 pid,因为只要前端进程存活,过时的非祖先 pid 就会无限期地存留。

来源 Issue #6820