关于 FerryCat
FerryCat 是供不同桌面 IDE 主机中的 AI Agent 使用的本地任务交接与审查总线。它通过 MCP 服务和 SQLite WAL 传递经契约校验的任务,并检查文件指纹以发现过时的审查上下文。
主要功能
- 01跨主机任务交接
- 02基于契约的输出校验
- 03SHA-256 文件完整性检查
- 04事务化 SQLite 任务状态
- 05用于检查和验证的命令行工具
适用场景
- 01在不同 IDE Agent 间交接代码审查任务
- 02在提交审查结果前确认文件未变化
- 03校验工作 Agent 的结构化结果
- 04检查或验证本地交接契约
MCP 相关
FerryCat 以本地 MCP 服务运行,提供分发、领取、验证、完成和检查任务契约的工具。不同 MCP 主机共用同一 SQLite WAL 数据库和工作区文件。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
8收录的工具列表 · 更新于 2 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| title | string | 是 | 简洁的合同标题(1–120 个字符),概述请求目标。 |
| pointers | array | 是 | 包含 1 到 50 个目标文件指针的数组,使用完整文件 SHA-256 和快照边界进行哈希,以检测篡改。 |
| task_type | enum | 是 | 合同任务类型。分级默认执行 TTL:code_review/architecture_audit 为 1800s,implementation/test_generation 为 300s。code_review | architecture_audit | implementation | test_generation |
| exec_ttl_sec | integer | 否 | CLAIMED 后的执行 TTL(秒)(默认值:审查/审计为 1800s,实现/测试为 300s)。Worker 必须在此时间窗口内完成、延长、释放或标记失败。 |
| target_agent | string | 是 | 预期会认领并执行此合同的目标 Worker Agent 标识符(例如,"workbuddy"、"antigravity")。 |
| queue_ttl_sec | integer | 否 | 状态为 SUBMITTED 时的队列过期 TTL(秒)(默认值:1800s / 30m)。如果过期前未被认领,则转换为 TIMED_OUT。 |
| workspace_root | string | 是 | 两台主机均可访问的共享本地工作区目录的规范绝对路径(例如,"F:/git/FerryCat")。路径越界访问和敏感文件会被阻止。 |
| context_summary | string | 是 | 提供给 Worker Agent 的详细任务说明、审计重点、架构约束和背景信息(1–20000 个字符)。 |
| contract_schema | object | 否 | 可选的 Draft-07 JSON Schema,structured_output 必须通过该 Schema 验证。大小上限为 1MB,最大深度为 32(FC-302)。 |
| requester_agent | string | 否 | 请求方 Agent 标识符。默认为 AGENT_NAME 环境变量(例如,"antigravity"、"workbuddy")。 |
详细介绍
FerryCat:基于契约的跨宿主 AI Agent 交接总线
English • 中文
FerryCat(
ferrycat)是一款轻量、确定性的跨宿主 AI Agent 交接与代码审查总线,基于 Model Context Protocol(MCP)和 Node.js 内置的node:sqlite(WAL 模式)构建。
它专为安全连接彼此隔离的桌面 IDE Agent 宿主而打造(例如 Google Antigravity、WorkBuddy、Claude Code 和 Cursor),让它们跨独立 OS 进程协作,同时避免上下文偏移或对过时文件进行盲审。
核心痛点与工程解决方案
虽然官方 MCP Tasks 规范(2025-11 / 2026-07)解决了单一 Client ↔ Server 连接中的长时间运行操作,但它无法解决开发者工作站上的跨宿主协作问题:
stdio进程隔离:桌面 IDE 会将本地 MCP 服务作为独立子进程启动,这些进程的内存空间相互隔离,且使用不同的 Node.js 运行时。- 对过时代码进行无声盲审(
Stale Context):将任务从宿主 A 移交给宿主 B 时,未保存的 IDE 缓冲区、分支切换或审查过程中的编辑,都会导致接收任务的 Agent 审查过时的代码,并得出看似合理但实际无效的结论。 - 上下文窗口膨胀:在聊天窗口之间粘贴数百行源代码,会让双方重复消耗 Token。
- 交接输出缺乏结构:自由格式的文本回复缺少确定性的 Schema 约束,导致下游处理不可靠,还容易陷入无限重试循环。
FerryCat 通过由人工调度、基于契约的 SQLite WAL 总线解决这些故障模式:
[Developer] [Host A: Antigravity] [~/.ferrycat/mesh.db] [Host B: WorkBuddy]
| | | |
|-- 1. "Dispatch review" --->| | |
| |-- dispatch_contract() -------->| Write status = SUBMITTED |
| | (Full SHA-256 + Line Bounds) | Store size / sha256 snapshot |
| | | |
|-- 2. Switch IDE: "Poll" ---|--------------------------------|------------------------------>|
| | |<-- poll_next_task() ----------|
| | | (Atomic claim changes===1 |
| | | + Verify disk SHA-256) |
| | | |-- Read local files
| | |<-- fulfill_contract() --------|-- Re-verify SHA-256
| | | (Validate Ajv JSON Schema | & submit JSON
| | | -> status = COMPLETED) |
| | | |
|-- 3. Switch IDE: "Inspect" | | |
| |-- inspect_mesh_state() ------->| Read-only query of COMPLETED |
|<-- Present structured res -| | |
核心架构支柱
1. 确定性的 7 状态机
每次状态转换都绑定到显式 SQL 事务,并采用乐观并发控制(changes === 1),从而消除虚假或悬空状态:
dispatch_contract()
│
▼
┌───────────┐
│ SUBMITTED │ (Queue TTL: default 1800s)
└─────┬─────┘
│
poll_next_task()
┌────────────────┼────────────────┐
│ (Queue TTL) │ (Hash Match) │ (Missing / Size Diff / SHA-256 Mismatch)
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────────┐
│ TIMED_OUT │ │ CLAIMED │ │ POINTER_STALE │ (Terminal: Rejects blind review)
└───────────┘ └─────┬─────┘ └───────────────┘
▲ │ (Exec TTL: default 300s)
│ fulfill_contract()
│ ┌────────────────┼────────────────┬────────────────┐
└──┤ (Exec TTL) │ (Schema Valid) │ (Retries > 2) │ (Mid-Review File Edit)
│ ▼ ▼ ▼
│ ┌───────────┐ ┌───────────────────┐ ┌───────────────┐
└──────────│ COMPLETED │ │ VALIDATION_FAILED │ │ POINTER_STALE │
└───────────┘ └───────────────────┘ └───────────────┘
对 CLAIMED 合约的持有方生命周期控制(均要求 agent_id === target_agent):
| 调用 | 转换 | 防护措施 |
|---|---|---|
release_contract | CLAIMED → SUBMITTED(移至队列末尾,开启全新的队列时限) | 重置 extend_count(续期额度按持有方计算),但保留 retry_count:模式校验失败熔断器是合约级配额,因此释放合约不能变相重置重试额度。超过绝对生命周期截止时间后将拒绝释放。每个合约最多释放 3 次。 |
extend_ttl | CLAIMED → CLAIMED(claimed_at = now) | 必须在有效时限内调用;每个持有方最多续期 5 次;一旦 now ≥ created_at + 4 × queue_ttl_sec,将拒绝续期。 |
fail_contract | CLAIMED → FAILED(终态) | 必须提供 reason,并以 WORKER_FAILED: <reason> 的形式保存。时限关闭后到达的报告将转为 TIMED_OUT,并附带原因。 |
2. 全文件 SHA-256 指纹、提交前验证与 TOCTOU 软失败缓冲(ADR-0004)
- 分发快照:
dispatch_contract会读取磁盘上的目标文件,并记录字节size、全文件sha256(64 位十六进制字符)、first_line和last_line。如果文件在过去 3 秒内被修改,则会发出warning,提醒请求方可能存在尚未保存的 IDE 缓冲区。 - 领取验证:
poll_next_task会验证存在性 -> 字节大小 -> 全文件 SHA-256(绝不会仅因mtime_ms不匹配而拒绝,以兼容 IDE 中无实际修改的保存操作)。如果不匹配,会等待150ms后重试一次,以排除 IDE 临时写入的影响,然后再将合约标记为POINTER_STALE。 - 提交前验证(
verify_contract):严格只读的检查,允许工作者或脚本在提交前审计指针状态(valid: true或valid: false并附带有变更的文件列表)。 - TOCTOU 软失败缓冲:
fulfill_contract会检查磁盘上的指针指纹。如果检测到指针对应的文件有变更:- 第 1 次异常会返回
RETRY_NEEDED,使合约保持CLAIMED,续期执行时限,并列出有变更的文件及恢复说明(git stash/git checkout -- <file>)。 - 第 2 次异常会将合约转为终态
POINTER_STALE,并将完整的已提交审查内容保存到salvaged_result_json,确保审查工作不会丢失。
- 第 1 次异常会返回
- 缩小 TOCTOU 竞态窗口:基于文件的系统无法消除读取磁盘字节与提交数据库行之间以微秒计的竞态,但 FerryCat 在
poll和fulfill阶段进行双重验证,将 TOCTOU 窗口从数分钟的盲审大幅缩短到亚毫秒级的原子 SQL 状态转换边界。
3. 有界模式校验(RETRY_NEEDED $\le 2$)
- 输出会通过缓存的 Ajv 校验器,按照合约的 JSON Schema 进行验证;错误会被压缩为简洁的单行路径(例如,
["/passed: must be boolean"])。 - 最多 2 次校验失败会返回
RETRY_NEEDED,同时使合约保持CLAIMED,以便立即自行修正(每次拒绝也会续期执行时限);第 3 次失败会将合约转为终态VALIDATION_FAILED。
4. 双阶段 TTL 与读前写清理
- 将
queue_ttl_sec(SUBMITTED状态的默认值为 1800s)与exec_ttl_sec(从claimed_at开始计时)分开,避免在队列时限后段领取的任务在执行期间过早超时。 exec_ttl_sec默认值按task_type分级:code_review/architecture_audit→ 1800s(深度推理或人工参与),implementation/test_generation→ 300s。显式指定的exec_ttl_sec始终优先。poll_next_task会在尝试对过期行执行任何UPDATE之前,执行无锁的SELECT COUNT(*)探测;inspect_mesh_state则严格保持只读。
5. 深度防御路径安全
- 在
dispatch和worker验证路径中,强制确保路径位于workspace_root内,并拦截敏感文件模式(.env*、*.pem、*.key、id_rsa*、*credentials*、*secret*、.npmrc、.git/config)。 - 路径解析:强烈建议将
workspace_root作为绝对路径传入。如果提供相对路径,则会通过path.resolve,确定性地相对于process.cwd()进行解析。
6. 威胁模型与安全假设(本地工作站 IPC)
- 信任环境假设:FerryCat 有意设计为受信任的本地工作站总线,用于桥接运行在同一 OS 用户账户下的隔离 IDE 主机。调用方和工作节点共享本地文件系统(
workspace_root)和 SQLite 数据库(~/.ferrycat/mesh.db)。 - 防御范围:路径包含性检查(
assertSafePointerPath)和敏感文件模式过滤器,可防止交接过程中意外越出工作区、遍历符号链接或泄露凭据/机密文件。 - 不在范围内(非目标):FerryCat 不提供对抗性沙箱、多租户隔离,也不针对恶意本地进程或伪造
AGENT_NAME的恶意 Agent 提供网络授权。
适用范围限制(何时不应使用 FerryCat)
- 文件系统不互通:FerryCat 通过文件引用传递上下文;两个主机都必须能访问同一个本地
workspace_root。 - 简单的单轮查询:每次跨主机交接都需要人工切换窗口 3 次(约增加 15–25s 开销)。
- 无人值守的后台流水线:桌面 IDE 主机采用请求-响应模式,空闲的 MCP 服务无法异步唤醒它们。对于无人值守的多步骤流水线,请使用独立的 DAG 工作流引擎,例如 PatchCat。
快速入门
1. 推荐:零安装 MCP 挂载(通过 npx)
无需本地克隆或手动编译。使用 npx -y ferrycat 直接挂载到 IDE 的 MCP 配置中:
Antigravity 配置
编辑 %USERPROFILE%\.gemini\antigravity\mcp_config.json(macOS/Linux 上为 ~/.gemini/antigravity/mcp_config.json):
{
"mcpServers": {
"ferrycat": {
"command": "npx",
"args": ["-y", "ferrycat"],
"env": {
"AGENT_NAME": "antigravity"
}
}
}
}
WorkBuddy / Claude Code / Cursor / Codex 配置
在目标主机的 MCP 设置中,使用相应的 AGENT_NAME 进行配置:
{
"mcpServers": {
"ferrycat": {
"command": "npx",
"args": ["-y", "ferrycat"],
"env": {
"AGENT_NAME": "workbuddy"
}
}
}
}
2. 全局安装与源码构建
- 全局 CLI 安装:
然后只需在 MCP 配置中设置npm install -g ferrycat"command": "ferrycat"。 - 本地源码构建(供贡献者使用):
使用本地路径挂载:git clone https://github.com/GuoBug/FerryCat.git cd FerryCat npm install npm run build npm test"command": "node"、"args": ["--experimental-sqlite", "/path/to/FerryCat/dist/index.js"]。
一流的 CLI 使用体验(ferrycat-cli)
除了作为 IDE 内的 MCP 服务,FerryCat 还提供一流的 CLI 工具(ferrycat-cli 或 npx ferrycat-cli)。CLI 与 MCP 服务共用 ~/.ferrycat/mesh.db SQLite WAL 数据库和 Zod 验证契约,让开发者无需离开终端,即可检查网格运行状况、验证工作树安全性,并接入自动化 CI/Git 脚本:
1. 终端可视化检查(ASCII 状态表)
以 ASCII 表格形式查看所有跨主机交接及错误原因:
# View all contracts in an ASCII table
npx ferrycat-cli inspect
# Filter by target agent (e.g., only tasks for antigravity)
npx ferrycat-cli inspect --target antigravity
2. 预检验证(变更前审计)
在提交审核工作前,根据契约的基准 SHA-256 审计磁盘上的指针文件完整性(ADR-0004),以避免误报交付:
npx ferrycat-cli verify <CONTRACT_ID>
3. 本地 CI 与无头工作节点执行
轮询队列、认领任务,并执行本地审核/测试脚本;发生失败时自动关闭任务:
# Safely run a script upon task arrival (no shell quotation hazards)
npx ferrycat-cli worker --agent codex --mode=exec --exec-file ./scripts/review.sh
暴露的 MCP 工具
| 工具名称 | 角色 | 事务行为 |
|---|---|---|
dispatch_contract | 请求方 | 执行路径黑名单检查 $\to$ 计算完整文件的 SHA-256 和行边界 $\to$ 插入 SUBMITTED。 |
poll_next_task | 工作方 | 清理过期 TTL(先读后写)$\to$ 通过 changes === 1 认领(CLAIMED)$\to$ 验证磁盘 SHA-256(或标记为 POINTER_STALE)。 |
fulfill_contract | 工作方 | 重新验证 SHA-256(TOCTOU 防护)$\to$ 验证 Ajv JSON Schema(通过 RETRY_NEEDED 最多重试 2 次,第 3 次标记为 VALIDATION_FAILED)$\to$ 标记为 COMPLETED。 |
release_contract | 工作方(持有者) | 将 CLAIMED 合约退回队列末尾,状态设为 SUBMITTED。保留 retry_count(合约级断路器);重置 extend_count。最多释放 3 次;超过绝对生命周期截止时间后拒绝释放。 |
extend_ttl | 工作方(持有者) | 心跳:重启执行窗口(claimed_at = now),最多续期 5 次,且总生命周期受限。 |
fail_contract | 工作方(持有者) | 将 CLAIMED 合约标记为终态 FAILED,并且必须提供 reason。 |
verify_contract | 工作方 / 任意方(只读) | 预检:根据基准 SHA-256 验证磁盘上的指针文件,不修改合约状态(ADR-0004)。 |
inspect_mesh_state | 任意方(只读) | 纯只读查询合约状态、输出和动态 is_logically_expired 标志。 |
💡 架构决策记录与工程验证:
- ADR-0001:跨主机 SQLite WAL 总线与人工调度的轮询模型(为何选择
node:sqliteWAL +poll_next_task,而非 60 秒阻塞等待或单连接 MCP Tasks)- ADR-0002:完整文件 SHA-256 指纹、TOCTOU 防护与跨模型审计(防止上下文过期,以及真实跨主机验证记录)
- ADR-0003:GUI 沙箱与 CLI 进程混合分层架构及唤醒边界(桌面 HITL 审批与内部 CLI 双通道自主运行)
- ADR-0004:审查与修改分离(SRM)、TOCTOU 软失败缓冲与不可变基准协议(如何防止并发或出于好意的审查者编辑导致审查中止)
- FerryCat 需求待办与路线图
作者简介
Guo Qiang (GuoBug),专注于平台工程与增长的产品工程师。目前致力于 AI 工作流编排、DAG 状态机和确定性系统架构。
开源项目与主页:https://github.com/GuoBug · https://guobug.github.io
欢迎就工作流引擎架构、拓扑调度和开发者体验进行咨询与讨论。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。