跳转到内容

Remote Execution(远端执行 / Mobile Remote-Control)

拆自 handbook/layers/future-capabilities.md。本章讲 MVP 不做但架构必须预留 的远端执行能力——把 agent runtime 放在远程主机 / 容器 / 云端,本地客户端(含 mobile)只做”遥控 + 审批 + 观察”。


1. 为什么要预留 remote execution

local-first 是 M0-M9 的主线,但下面四类场景在 M9 之后基本无法回避:

场景为什么 local-first 不够
笔记本休眠时 agent 还在跑测试local agent 进程被 OS suspend;任务挂死
跨设备工作(公司笔记本起一个 session,家里继续)local-only 状态没法同步到第二台机
Mobile 想审批 / 取消正在跑的 turnmobile 没有跑 agent runtime 的能力
团队共享一台云端 GPU 跑昂贵 provider 调用多人 share local process 是反模式

如果 MVP 架构不预留 remote,到 M10 才补会发现:

  • Session state 散在内存(无法跨主机迁移)→ 需重写 SessionEngine
  • Event stream 假设 in-process 单消费者 → 需重写 EventStore port
  • Permission UI 假设同 OS 弹窗 → 需重写 Approval lifecycle

所以 MVP 的设计原则是 “远端化”不是新能力,而是把同一套抽象搬到不同位置

2. 远端化必须复用的抽象

locally: remotely (M10+):
┌──────────────────┐ ┌──────────────────────────┐
│ Web client │ │ Web client (any device) │
└────┬─────────────┘ └────────────┬─────────────┘
│ ACP Streamable HTTP │ ACP Streamable HTTP over TLS
│ (loopback) │ (public address + auth)
▼ ▼
┌──────────────────┐ ┌──────────────────────────┐
│ apps/acp-daemon │ │ apps/acp-daemon │
│ on localhost │ │ on remote host │
└────┬─────────────┘ └────────────┬─────────────┘
│ spawn child per session │ spawn child per session
▼ ▼
┌──────────────────┐ ┌──────────────────────────┐
│ apps/acp-server │ │ apps/acp-server │
│ ↓ uses │ │ ↓ uses │
│ packages/core │ │ packages/core │
│ SessionEngine │ │ SessionEngine │
└──────────────────┘ └──────────────────────────┘

唯一变化是 daemon 的网络位置 + auth。其他都不变:

  • ACP 协议 / Streamable HTTP transport :相同([[adr-0004]])
  • Event log JSONL 格式:相同(M1-01)
  • PermissionEngine 决策:相同(M3)
  • SessionEngine 状态机:相同(M1-03)
  • Tools / Skills / MCP:相同

所以 “remote agent” 不是新功能,是 daemon 部署位置的迁移。

3. Remote-Specific 关注点

3.1 Authentication / Authorization

local 默认remote 必须
daemon HTTP listenerlocalhost:portTLS + bearer token / mTLS
client 自我标识OS process owner显式 credential 协商
auth scopefull session 控制可分级(read-only viewer / approver / driver)
Scope能做不能做
viewerreplay 已有 session、监听 live update不能 prompt、不能 approve
approverviewer + 回复 permission.requested不能 prompt、不能 cancel
driverapprover + session/promptsession/cancelsession/new不能管理 daemon 配置
admindriver + daemon 配置、provider key 管理(本机管理员)

scope 必须落到 ACP capability negotiation(initialize 响应里告诉 client “你能做什么”)。

3.2 Network 失败语义

local daemon 不会”断网”。remote daemon 会。

情况处理
client 网络断client 持 sequenceCursor 续传;daemon 保留 SSE buffer N 秒;超时 client 主动 reconnect
daemon 主动 push 时连接掉daemon 持 outbound queue per session;client 重连时按 cursor 续
daemon 重启(云端运维事件)session 进程状态依赖 event log;client 重连时由新 daemon 实例从 JSONL replay 恢复 session view

ACP Streamable HTTP transport spec([[adr-0004]] §2)必须包含这套语义。本地 daemon 共享同套实现——避免两套代码。

3.3 Artifact 同步

agent 产生的 artifact(修改的文件、生成的 diff、长 stdout)在 remote 模式下需要回流到 client:

类型处理
小 artifact(< 1MB)直接进 event payload preview
大 artifact落 daemon 端的 artifact storage;event 含 URI + content hash;client 按需 fetch
用户工作树(workspace files)自动同步;session.cwd 是 daemon 端的路径;本地客户端不假设有同样的文件系统

关键:mobile 客户端永远不要假设有 workspace 副本。它能做的是:viewer / approver / driver 级动作;不可能本地 diff 一个 daemon 端的 worktree。这定义了 mobile 的产品边界。

3.4 Permission UI 的异步性

local:approval 弹窗当下出现,user 立刻点击。 remote:approval 可能在用户在地铁里时触发;需要 push 通知 + 30-300s timeout。

设计点处理
触发媒介push notification(mobile / 桌面);email fallback
timeoutsession policy 配置;默认 deny on timeout
多人参与同一 session 多 approver 在线时谁先点谁先算;其他 approver 收到”已被 X 批准/拒绝”通知
长 turn 内多次 ask每次都重新触发通知;不能用前次 approval 一直放行(destructive 永不复用 [[tools-and-permissions]])

4. Mobile Remote-Control 的定位

Mobile 是 remote client 的特殊形态——不是新概念。

Mobile 是什么: Mobile 不是什么:
✓ ACP Streamable HTTP client ✗ agent runtime
✓ replay viewer ✗ tool executor
✓ approval surface ✗ memory writer
✓ session monitor ✗ session orchestrator
✓ notification consumer ✗ workspace editor

mobile App 的 minimum viable surface:

Tab功能
Sessionslist / search / filter;点进去看 replay
Approvals待批准的 permission.requested;带 risk 颜色和 rationale
Notifications高风险动作 / 长 turn 完成 / 失败
Settingsdaemon endpoint / token / push 偏好

不做的事(明确写到 mobile 产品 spec):

  • ❌ mobile 直接调用 tool / 修改文件
  • ❌ mobile 写 memory candidate(candidate workflow 走 main client)
  • ❌ mobile 安装 MCP server / skill
  • ❌ mobile 跑 SessionEngine

5. 实施路径

阶段工作内容
M1-M9(当前)保留所有抽象的 location-independent 性质:ACP wire、event log JSONL、PermissionEngine、SessionEngine 都不假设 in-process 单 user
M10-01 ADR写 Remote Runner ADR;定义 scope / auth / artifact / push 通知模型;不写代码
M10-RUNNER落实 remote daemon TLS + auth;扩 initialize capabilities 协商 scope
M10-MOBILE写 mobile client(约 React Native);只读 + approval surface
后续多人协作(multi-driver);session migration(local → remote 迁移);offline mode

6. 反模式(要避免的设计)

反模式为什么不行
daemon 上跑 N 个 session 共享一个 event log 文件失去 [[adr-0004]] 的 “1 session = 1 子进程” 隔离;一台 session crash 拖垮其他
mobile 直接调用 PermissionEngine.checkPermissionEngine 是 server-side 决策点;mobile 是 approver UI,不是决策方
session 状态分布在 daemon memory + client memorysession 真值只在 event log;client / mobile 都按 replay 投影
引入 WebSocket 替代 SSESSE 单向流够用;引入 WebSocket 等于增加协议复杂度(连接管理 / 帧分片);用 SSE 续传 cursor 解决重连
remote agent 自动同步整个 workspace 到本地mobile 上行没意义;笔记本同步要单独设计;MVP 不做
auth 用 OS keychain 直接放 daemon-sidesecret 落到远端机器风险大;用短期 token + refresh 模式

7. 进一步阅读

  • [[adr-0002]] §“Remote control / remote execution” — 总框架性预留
  • [[adr-0004]] §2 §5 — ACP Streamable HTTP 设计直接服务 remote
  • plugin-system.md — plugin 系统在 remote 下的部署约束
  • automation.md — scheduled job 也以 session 为基础