DSH / Atlas
2026-10-09implementedarchitecture

Shared native CUA process with Agent-scoped state

共享原生 CUA 进程并隔离 Agent 状态

On macOS 26.6.2, replayd derives capture-client identity from the executable path. Two live helpers at the same path repeatedly replace each other's connections even when their screenshot requests are sequential. Byte-identical executables at distinct real paths complete sequential and concurrent captures; two symlinks to one executable reproduce the failure. A per-request lock cannot isolate retained system connecti

Source compatibility: Chinese title uses a compatible non-canonical header

English

Problem

On macOS 26.6.2, replayd derives capture-client identity from the executable path. Two live helpers at the same path repeatedly replace each other's connections even when their screenshot requests are sequential. Byte-identical executables at distinct real paths complete sequential and concurrent captures; two symlinks to one executable reproduce the failure. A per-request lock cannot isolate retained system connections.

Decision

One user shares a native service per executable content digest across Agents and Hosts. A version lock elects the service; an additional canonical-executable-path lock prevents different builds published at one path from running together. Locks remain held until process exit. The managed startup command hands service lifetime to its client connections, and the last connection's completed cleanup ends the service. The diagnostic stdin/stdout entry proxies to this same service.

Each Agent connection owns its application handles, AX snapshots, limits and cancellation state. An app handle grants no exclusive use of the application. A FIFO orders complete desktop operations, including clipboard transactions, while response writes are independent. Agent disposal retires only its connection. The object API decision retains evaluator independence and coordinate semantics; the consent decision retains application authorization.

Cancellation and timeout first stop one request and wait for acknowledgement. A timed-out screenshot retains the single system-RPC slot until the real callback completes; new screenshots fail with CAPTURE_BUSY instead of accumulating requests. Late pixels are discarded, while other AX and input operations remain available. Ending an await or creating a wrapper does not prove that the system connection has recovered. An operation or cleanup that cannot stop can invalidate the process, making every old handle unusable. Uncertain input is never replayed automatically.

Alternatives considered

Separate executable copies per Agent avoid the observed identity collision but multiply system capture clients. One shared service preserves a single capture client while retaining Agent state isolation. An in-process Swift binding changes crash containment without removing the system RPC. The continuous-hover decision keeps individual operations serialized without cross-call application ownership.

Consequences

Two Hosts can race to start the service and receive the same instance. A may retain its app object while B screenshots and changes the same application; A reads fresh AX afterward. An Agent closing cannot retire another Agent's handles. Recovery must distinguish request, snapshot, handle, capture-backend and process failure. A lost system callback occupies a bounded capture slot; reliable in-process backend reset requires separate platform evidence. The historical DeepSeek failures have matching RPC errors, but their competing-client identity was not recovered from retained logs.

中文

问题

在 macOS 26.6.2 上,replayd 按可执行文件路径生成捕获客户端标识。同一路径的两个活动 helper 即使依次截图,也会反复替换对方的连接。相同字节的可执行文件位于不同实际路径时,交替和并发截图均成功;两个符号链接指向同一文件仍会失败。逐请求加锁不能隔离仍存活的系统连接。

决策

同一用户的多个 Agent 和 Host 按可执行文件内容摘要共享原生服务。版本锁选出服务实例,规范化可执行路径上的另一把锁阻止发布在同一路径的不同构建同时运行。进程退出才释放锁。受管启动命令将服务生命期交给客户端连接,最后一条连接清理完成后服务退出。诊断用 stdin/stdout 入口也代理到同一个服务。

每条 Agent 连接独立持有应用句柄、AX 快照、资源限制和取消状态。持有 app 句柄不代表独占应用。FIFO 队列串行执行包含剪贴板事务的完整桌面操作,响应写入独立进行。Agent 销毁只释放自己的连接。对象接口决策继续负责执行器独立性及坐标语义,授权决策继续负责应用许可。

取消或超时先停止单次请求并等待确认。截图超时后,唯一的系统 RPC 槽位保留到真实回调结束;新截图返回 CAPTURE_BUSY,不继续堆积请求。迟到图片被丢弃,其他 AX 与输入操作仍可执行。结束 await 或创建包装对象不能证明系统连接已恢复。操作或清理无法停止时,才可能使进程失效,届时所有旧句柄均不可用。结果不确定的输入不会自动重放。

考虑过的替代方案

每个 Agent 使用独立的可执行文件副本可以避开已观察到的标识冲突,但会增加系统捕获客户端数量。共享服务保留一个捕获客户端,同时隔离 Agent 状态。进程内 Swift 绑定会改变崩溃隔离方式,不能消除系统 RPC。连续悬停决策保留单次操作串行执行,不分配跨调用的应用所有权。

后果

两个 Host 同时启动服务时可连接同一个实例。A 可以保留 app 对象,B 对同一应用截图并修改,之后 A 重新读取 AX。一个 Agent 关闭不会释放另一个 Agent 的句柄。恢复需要区分请求、快照、句柄、截图后端和进程失效。系统回调丢失会占用有界的捕获槽位,可靠的进程内后端重置需要另外取得平台验证。历史 DeepSeek 失败具有相同 RPC 错误,但保留日志未能确定当时另一个冲突客户端的身份。