Rowboat Code Mode 引擎托管架构解析基于 ACP 适配器的 Claude Code / Codex 引擎按需供给方案【免费下载链接】rowboatOpen-source AI coworker, with memory项目地址: https://gitcode.com/GitHub_Trending/rowb/rowboat本文以仓库中 CODE_MODE_ENGINES_PLAN.md 设计文档为主体结合packages/core中已落地的工程实现engine-provisioner.ts、engine-manifest.ts、agents.ts、status.ts展开成文。Rowboat 的 Code Mode 通过 ACPAgent Client Protocol适配器驱动Claude Code与Codex两个原生编码代理本文完整还原其引擎托管Managed Engine Provisioning架构引擎二进制归应用管理、按需从 npm 下载、SHA 校验、版本锁定认证则复用用户既有凭证。读完你将掌握一套安装包不膨胀、打包版开箱即用、离线不挂起的编码代理引擎供给方案的设计与实现细节。一、问题背景打包版 Code Mode 为什么一直在坏Rowboat 的 Code Mode 同时运行两个编码代理Claude Code与Codex。实现方式是先拉起各自的ACP 适配器agentclientprotocol/claude-agent-acp、agentclientprotocol/codex-acp再由适配器孵化一个体积庞大的原生引擎二进制Claude 约 205 MB、Codex 约 194 MB。设计文档给出的核心目标是让 Code Mode 在打包发布版中对两个代理都能达到约 99% 的可靠运行同时又不把约 400 MB 的引擎塞进安装包。现状打包版每次发布都是坏的计划文档明确指出其描述基线为 #614 的回滚之后的状态打包构建不暂存stageACP 适配器且forge.config.cjs中的ignore: /^\/node_modules\//规则会把这些依赖剥掉运行时agents.ts通过require.resolve(...)解析适配器再 spawn于是直接抛出Cannot find module agentclientprotocol/...结论是打包版 Code Mode 在每次发布中都是坏的只有在 dev 下能跑因为 pnpm symlink 存在。当下既没有 400 MB 的膨胀也没有任何功能。两个候选方案的不足方案思路致命缺陷A. 打包引擎Bundle engines每个安装包内置一套 claude codex 原生二进制每个 OS/arch 的安装包增加约 400 MB体积不可接受B. 复用用户本机安装#614 曾采用后被回滚依赖用户已装好两个 CLI、已登录、版本正确且在 PATH 上强依赖用户机器环境——版本错位、GUI 启动 PATH 被剥离、未安装等结构性无法达到 99% 可靠性正是 B 方案的版本错位 PATH 陷阱问题使 #614 被回滚。这两条路径的失败直接催生了引擎托管这一第三条路线。二、核心架构Engine 归应用所有Auth 复用用户设计文档给出的解决方案把问题拆成engine与auth两件事区别对待Engine 由应用拥有将版本锁定的引擎二进制供给provision到应用支持目录~/.rowboat/engines/agent/version/首次使用时按需下载sha256 校验symlink/路径固定。不使用用户的全局 npm也不依赖用户的 PATH → 无版本错位、无 PATH 怪癖这是 99% 可靠性的来源。Auth 复用用户引擎读取用户已有的凭证~/.claude的 API key / Pro / Max 订阅、~/.codex的 auth.json无需二次登录。status.ts已具备对这些凭证的检查能力。实证Conductor 的落地形态计划文档记录了在开发机上对 Conductorconductor.build的观察作为实证其 DMG 仅123 MB远小于约 400 MB 的引擎体积 → 引擎不在安装包里而是安装后下载在~/Library/Application Support/com.conductor.app/观察到的目录布局agent-binaries/claude/2.1.170/claude (222 MB, single Mach-O arm64) agent-binaries/codex/0.138.0/codex (205 MB, single Mach-O arm64) bin/claude - agent-binaries/claude/2.1.170/claude (symlink to active version) bin/codex - agent-binaries/codex/0.138.0/codex agent-binaries/.meta/claude-2.1.170.json {sha256, size, downloaded_at_unix_ms, ...}即版本化目录 稳定 symlink sha256.meta台账 按需下载四件套。Rowboat 的方案镜像了这套形态详见第五节。三、关键事实基础适配器通过环境变量接受外部引擎方案成立的前提是两个 ACP 适配器都原生支持通过环境变量指定外部引擎无需改动适配器一行代码。计划文档给出了源码级证据当时锁定的适配器版本Claudeagentclientprotocol/claude-agent-acp0.39.0其dist/acp-agent.js:39有if (process.env.CLAUDE_CODE_EXECUTABLE) return it;第 1552 行pathToClaudeCodeExecutable: process.env.CLAUDE_CODE_EXECUTABLE ?? ...。若未设置且无内置原生依赖会直接抛出 set CLAUDE_CODE_EXECUTABLE。Codexagentclientprotocol/codex-acp0.0.44其dist/index.js:20900const codexPath process.env[CODEX_PATH] ?? codex;→spawn(codexPath, [app-server])。推论供给引擎 设置这两个环境变量就是引擎侧的全部工作。同时Rowboat 依赖的引擎包本身就是单一自包含二进制anthropic-ai/claude-agent-sdk-darwin-arm640.3.156→ 只含一个claude可执行文件外加 LICENSE/READMEopenai/codex0.128.0-darwin-arm64→ 内含vendor/target/codex/codex原生二进制还捆绑了一个rgripgrep位于vendor/target/path/rg—— 这是风险 R1 的来源见第七节。版本锁定与平台包命名计划文档从已安装的适配器依赖树中读出的固定版本映射Claude适配器claude-agent-acp0.39.0→ 引擎anthropic-ai/claude-agent-sdk0.3.156平台可选依赖anthropic-ai/claude-agent-sdk-platform0.3.156覆盖darwin-arm64、darwin-x64、linux-x64、linux-arm64、linux-x64-musl、linux-arm64-musl、win32-x64、win32-arm64八个平台。Codex适配器codex-acp0.0.44→openai/codex^0.128.0pnpmpatched见 R2平台依赖以别名形式openai/codex-platform→npm:openai/codex0.128.0-platform发布覆盖darwin-arm64、darwin-x64、linux-x64、linux-arm64、win32-x64、win32-arm64六个平台。需要说明的是计划文档中的 0.3.156 / 0.128.0 是动笔时的固定值当前仓库由构建脚本自动生成的 engine-manifest.ts 中实际锁定的是claude0.3.257与codex0.153.4codex 按0.153.4-platform发布。这正体现了清单由构建生成、与适配器永不脱节的设计意图对应风险 R8。四、分发源决策npm 平台包 适配器锁定版本已定案方案决定从 npm registry 拉取 ACP 适配器所依赖的、精确版本对应的分平台引擎包解出原生二进制供给到~/.rowboat/engines/...。不自建托管、不用 curl 安装器、不做 fallback。Tarball 地址模式https://registry.npmjs.org/pkg/-/file-version.tgzclaudeanthropic-ai/claude-agent-sdk-platform0.3.156→ 解出其中的claude二进制codexopenai/codex0.128.0-platform→ 解出vendor/target/codex/codex并且保留vendor/target/path/rg见 R1。为什么是适配器锁定的 npm 包而不是 curl 安装器 / 发布桶 / 自建托管计划文档给出了四个核心理由握手保证二进制是适配器构建/测试所针对的精确版本→ ACP 握手必然成功 → 这是约 99% 可靠性的关键零基础设施的完整性校验npm registry 高可用、按版本不可变packument 提供dist.integritysha512dist.shasumsha1无需任何自建基础设施即可校验规避官方安装器的行为官方curl | bash安装器面向终端用户会全局安装到~/.local/bin且后台自动更新——这恰恰是要避免的。Rowboat 需要一份隔离、固定、由应用管理、绝不会在适配器脚下漂移的副本Conductor 同样只取原始二进制而不运行安装器版本永不漂移版本在构建时从 lockfile 读取并内嵌到engine-manifest.json因此清单与随包发布的适配器永不失步。与 Conductor / 官方安装器的关系Conductor 在storage.conductor.build自托管同类原生二进制raw/.gz/.zst{url,gzipUrl,zstdUrl,sha256}清单将适配器与较新的独立 CLI版本claude 2.1.x、codex 0.138配对。这证明了较新版本可用但 Rowboat 出于确定性刻意锁定适配器自己的引擎版本。官方 Claude 发布也会在downloads.claude.ai/claude-code-releases/ver/提供 GPG 签名的manifest.jsonSHA256/platform。当前不用npm 更简单且与适配器匹配但这是未来接入最新 CLI 线的升级路径。若日后需要控制权/可用性/压缩可以把这些 npm tarball 镜像到自己桶里——运行时完全不变只改清单中的 URL。已锁定的决策user 确认源npm 平台包适配器锁定版本不自建托管总是供给无 fallback不回退到用户预装的claude/codex被回滚的路径 B 彻底退役Codex pnpm patch 无关紧要用户确认patch 针对的是 JS launcher而方案把CODEX_PATH直接指向原生二进制patch 不生效风险 R2 移除。五、构建期生成引擎清单 暂存适配器 JS5.1 引擎清单engine-manifest.json内嵌进应用构建脚本读取已安装的适配器依赖树按代理生成清单计划文档给出的结构示例JSONC{ claude: { version: 0.3.156, platforms: { darwin-arm64: { pkg: anthropic-ai/claude-agent-sdk-darwin-arm64, tarball: https://registry.npmjs.org/.../-/...-0.3.156.tgz, integrity: sha512-..., binRelPath: claude }, ...: {} } }, codex: { version: 0.128.0, platforms: { darwin-arm64: { pkg: openai/codex-darwin-arm64, tarball: https://registry.npmjs.org/..., integrity: sha512-..., binRelPath: vendor/aarch64-apple-darwin/codex/codex, extraPaths: [vendor/aarch64-apple-darwin/path/rg] } } } }版本、tarball URL、integrity 全部取自 lockfile / npm packument保证清单与随包适配器始终同步避免硬编码易碎的包名binRelPath/extraPaths记录可执行文件以及 codex 的rg在 tarball 内的位置。实现佐证仓库中的构建脚本 gen-engine-manifest.mjs 完整实现了这一逻辑通过pinnedDep()读取agentclientprotocol/claude-agent-acp对anthropic-ai/claude-agent-sdk、codex-acp对openai/codex的依赖规格对^/~范围会用已安装版本的package.json解析出实际安装版本使供给引擎与 lockfile 严格一致通过distFor()请求https://registry.npmjs.org/pkg/version拿dist.tarball与dist.integrity404 则跳过该平台并告警输出写入src/code-mode/acp/engine-manifest.ts提交入库。选择提交的 .ts 而非构建时拉取的 .json是为了应用构建无需网络、dev 离线可用、PR 可评审、且 esbuild 会将其内联进打包后的主 bundle。当前 engine-manifest.ts 中可看到完整的 8 平台 claude 条目与 6 平台 codex 条目每条都含pkg、pkgVersion、tarball、integritysha512 前缀文件头明确标注AUTO-GENERATED ... Regenerate after bumping the agentclientprotocol/*-acp adapter (engine) versions。5.2 暂存 ACP 适配器 JS#614 中保留的部分适配器本身很小含非原生 JS 依赖总共约 15 MB但打包版必须让它们在磁盘上存在agents.ts才能解析并 spawn。方案在forge.config.cjs的generateAssets中把两个适配器及其非原生生产依赖闭包暂存到.package/acp/node_modulesnpm 风格嵌套布局将.package从node_modules的 ignore 规则中豁免#614 的原生引擎暂存整体放弃——引擎来自供给不来自 bundle。实现佐证当前 forge.config.cjs 中有stageAcpAdapters逻辑将agentclientprotocol/claude-agent-acp、agentclientprotocol/codex-acp及其依赖闭包复制进.package/acp/node_modules并验证解析成功且 ignore 规则对/.package及/.package/*显式放行if (p /.package || p.startsWith(/.package/)) return false;。六、运行期引擎供给器engine-provisioner核心实现计划文档规划的新模块落在packages/core/src/code-mode/acp/engine-provisioner.ts其算法伪码为ensureEngine(agent): Promise{ executablePath: string } 1. 读取 (agent, currentPlatform) 对应的清单条目不支持则明确报错。 2. dir ~/.rowboat/engines/agent/version/ 3. 若目录存在 且 .meta/agent-version.json 的 sha256 匹配 → 直接返回 binPath。 4. 否则获取跨进程锁避免双重下载然后 a. 流式下载 tarball 到临时文件带进度事件。 b. 校验完整性清单中的 sha512/sha256。 c. 解压到临时目录原子 rename 进 version/tar gzip。 d. unix 下 chmod x 二进制以及 codex 的 rg。 e. 写 .meta/agent-version.json {sha256, size, downloaded_at_unix_ms}。 5. 返回引擎可执行文件的绝对路径。进度 取消通过 IPC 上抛支撑首次运行的 Downloading engine… UI离线/失败→ 抛出带清晰可操作信息的类型化错误绝不静默挂起原子性先下载到临时文件 → 校验 → rename绝不留下半解压但通过了存在性检查的版本目录。源码级细节当前实现对照 engine-provisioner.ts实现比计划更细平台判定platformKey()darwin/win32直接映射darwin-arch/win32-archlinux上先检测 muslAlpine优先linux-arch-musl否则回退 glibc 的linux-arch。musl 检测复用 Node 原生插件加载器的启发式process.report的 header 中出现glibcVersionRuntime即非 musl。定位可执行文件locateExecutable()claude 直接找claude/claude.execodex 在vendor/triple/下同时探测bin/与codex/子目录源码注释说明 codex 布局从codex/≤0.128迁到了bin/≥0.142兼容新旧版本。完整性校验verifyIntegrity()按 SRI 字符串sha512-base64拆分算法与期望值用crypto.createHash重算比对不匹配即抛错对应风险 R4。Windows 解压细节extractTarball()优先用System32\tar.exebsdtar找不到时改为从归档所在目录运行并只传文件名规避 GNU tar 把C:\...绝对路径误读为远程host:path的问题。版本清理pruneOldVersions()新版本供给成功后删除该代理下除活跃版本外的全部旧版本目录与.meta条目对应风险 R5并跳过.tmp-前缀的在途临时目录best-effort绝不因清理失败破坏一次成功的安装。幂等并发ensureEngine()每次用独立的mkdtempSync(.tmp-version-)临时目录下载/校验/解压最后renameSync原子换入并发调用者各用各的临时目录最终 rename 幂等。finally中必清理临时根目录。关键设计下载只发生在 Settings 里实现中getProvisionedEnginePath(agent)在 engine-provisioner.ts故意不下载聊天/运行路径调用它时若引擎缺失会抛出明确的Open Settings → Code Mode and click Enable to download it错误保证用户不会在对话中途遭遇约 200 MB 的意外下载。带下载能力的ensureEngine()只由 Settings 的 Enable 动作驱动——这实际上把计划文档中Provision timing: lazy vs eager的开放问题落定为了设置页驱动的 lazy 缓存。七、接入启动链路agents.ts 与 client.ts计划要求改造agents.ts的getAgentLaunchSpec()原先只设置CLAUDE_CODE_EXECUTABLE先await ensureEngine(agent)然后设置claude →env.CLAUDE_CODE_EXECUTABLE provisioned claudecodex →env.CODEX_PATH provisioned codex并保证其rg兄弟文件可解析保持 vendor 目录布局让 codex 能找到../path/rg适配器 spawn 保持ELECTRON_RUN_AS_NODE1不变。当前实现agents.ts比计划更进一步提供多个实战细节适配器解析resolveAdapterPkgJson()先在暂存的.package/acp位置解析打包版失败再回退普通 node_modules 解析devresolveAdapterEntry()读取包的bin字段拿到入口脚本绝对路径。登录 shell PATH 嫁接loginShellPath()探测用户登录 shell 的 PATH 并合并进引擎环境变量——因为 GUIFinder启动的应用继承的是 launchd 剥离过的 PATH引擎 spawn 的 git/gh/rg/bash 会报 command not found即使终端里可用Windows 或探测失败时为空操作。调试可观测性对 claude 额外设置DEBUG_CLAUDE_AGENT_SDK1让 SDK 把精确的 spawn 命令与 claude 的 stderr 记录到~/.claude/debug/sdk-*.txt使启动失败/挂起有迹可查。spawn 方式命令固定为process.execPathElectron 主进程内即 Electron 二进制ELECTRON_RUN_AS_NODE1使其以纯 Node 运行时行为执行适配器入口否则子进程不会以 node 运行ACP stdio 流会立即关闭ACP connection closed。同时规避了 Windows 上.cmd的 EINVAL 问题。调用链上client.ts 在 spawn 适配器前取getAgentLaunchSpec(this.agent)保证每次启动都拿到指向已供给引擎的完整环境。八、状态检测与 UXstatus.ts IPC8.1checkCodeModeAgentStatus()引擎已供给认证凭证存在计划要求把状态检查从PATH 上是否安装改为引擎是否已供给。当前 status.ts 的实现installed字段 isEngineProvisioned(agent)即~/.rowboat/engines/agent/version下可执行文件存在且.meta台账存在——不再查找 PATH 上的全局 claude/codex CLIsignedIn/account走引擎探针优先、文件启发式兜底claude对供给的引擎执行claude auth status解析输出 JSON 中的loggedIn真实引擎如何解析凭证——Keychain、CLAUDE_CONFIG_DIR、企业托管——就用同一套是 ground truth15 秒超时ENGINE_PROBE_TIMEOUT_MS覆盖引擎冷启动与 macOS 首次 Keychain 授权弹窗探针失败再回退到~/.claude/.credentials.json/ Keychain 检查codex执行codex login status退出码 0已登录身份信息从~/.codex/auth.json的id_tokenJWT claims 解码email、chatgpt_plan_type仅用于展示不作认证决策身份补充claude 从~/.claude.json的oauthAccount.emailAddress读取。8.2 首次运行流与 IPC 进度首次运行用户选择代理 → 若引擎缺失显示 Downloading engine (~200 MB), one time… 进度条 → 完成后继续后续使用瞬时完成。清晰的错误态下载失败 / 离线 / 不支持平台 / 缺认证。实现佐证主进程 ipc.ts 注册了codeMode:provisionEnginehandler调用ensureEngine(args.agent, { onProgress })把download/verify/extract/done各阶段以及receivedBytes/totalBytes通过codeMode:engineProgress事件流式回传给设置窗口用于实时进度条错误则以{ success: false, error }返回。另有codeMode:checkAgentStatushandler 暴露checkCodeModeAgentStatus()。九、边缘情况与风险清单R1–R8计划文档列出的风险在实现中逐一回应R1 — Codex 依赖rgcodex 平台包在vendor/target/path/rg捆绑 ripgrep。必须解压并保留整个 vendor 布局不能只取裸二进制。当前实现locateExecutable()探测bin/与codex/makeExecutable()对codex-path/与path/下的rg都chmod 755兼容新旧布局≤0.128 用path/≥0.142 用codex-path/。R2 — Codex pnpm patch已解决/无关patch 针对 JS launcherCODEX_PATH指向原生二进制patch 不生效。R3 — 平台/架构矩阵清单须覆盖 darwin x64/arm64、linux x64/arm64claude 另有 musl 变体、win32 x64/arm64Windows 引擎是claude.exe/codex.exe。当前engine-manifest.ts中 claude 8 平台、codex 6 平台齐全。R4 — 完整性与供应链chmod/执行前必须校验清单中的完整性哈希哈希不匹配是硬失败。实现中verifyIntegrity()即此职责。R5 — 磁盘与升级版本化目录会累积需清理策略只保留每个代理的活跃固定版本。实现中pruneOldVersions()已落地。R6 — 首次运行网络每个代理只需一次之后永久缓存必须是清晰、可取消的 UX绝不静默挂起复用 #614 启动期限的教训。R7 — macOS 代码签名 / Gatekeeper下载的原生二进制不在应用签名覆盖内。需验证其在 Gatekeeper 下可运行二进制本身已由 Anthropic/OpenAI 签名公证quarantine 属性可能需要清除。Conductor 能从 app-support 正常运行Rowboat 需同样确认计划中列为 P2 期间验证项。R8 —engine-manifest陈旧适配器/引擎版本变更时必须重新生成清单把生成绑进构建流程使其不可能漂移。当前gen-engine-manifest.mjs与提交入库的engine-manifest.ts即此机制。十、实施阶段划分P1–P5阶段内容验收标准P1 打包修复适配器 JS 暂存进.package解析器优先查暂存路径打包版 Code Mode 至少能 spawn 适配器与供给无关是 #614 值得保留的部分P2 供给器ensureEngine() 清单 接线环境变量macOS arm64 上两个引擎都能供给并从~/.rowboat/engines启动P3 UX 状态首次运行下载 UI、状态面板、错误态用户可见的完整下载与状态体验P4 跨平台 CI 冒烟矩阵清单mac/linux/win 冒烟多平台可用P5 打磨版本清理、取消、离线提示、可选本机安装 fallback全场景健壮十一、决策与遗留问题已解决锁定源 npm 平台包、适配器锁定版本非自建托管、非 curl 安装器、非发布桶总是供给无本机安装 fallbackCodex pnpm patch 无关。实现期间可再定其中部分已被当前实现落定供给时机首次 Code Mode使用时lazyvs 首次应用启动eager 后台下载。当前实现取lazy 缓存且下载只由 Settings 的 Enable 动作触发见第六节版本目录清理每个代理只保留活跃固定版本——pruneOldVersions()已实现P2 期间验证 R1codexrg与R7Gatekeeper。十二、总结Rowboat 的 Code Mode 引擎托管方案本质是一次清晰的职责切分引擎由应用以版本锁定的方式按需供给认证复用用户既有凭证。它同时绕开了安装包膨胀 400 MB与依赖用户本机环境两个死结靠适配器支持环境变量指定引擎 npm 平台包天然带完整性校验 构建期自动生成永不漂移的清单三个事实落地。从当前仓库的实现看计划中的供给器、清单生成、启动接线、状态检测、IPC 进度 UI 均已落地且实现细节musl 探测、Windows bsdtar、vendor 布局双版本兼容、旧版本清理比计划文档更进一步可视为该设计在真实工程中的完整验证。如需深入可继续阅读 CODE_MODE_ENGINES_PLAN.md设计原文、engine-provisioner.ts供给器实现、agents.ts启动接线、status.ts状态检测、gen-engine-manifest.mjs清单生成脚本与 forge.config.cjs打包暂存。【免费下载链接】rowboatOpen-source AI coworker, with memory项目地址: https://gitcode.com/GitHub_Trending/rowb/rowboat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考