# Kuruwa 第一版设计 本文记录设计访谈确认的方案。术语见 [CONTEXT.md](../CONTEXT.md),监听 FD 原型见 [验证说明](../prototypes/rmux-listener-fd/README.md)。目前只有启动机制原型经过验证,本文所述租户系统和产品 CLI 尚未实现。 ## 1. 目标与边界 Kuruwa 提供面向 agent 的多权限执行环境与终端复用,对外接口是 CLI。调用方自行启动 harness 或 agent,并决定向其暴露哪个入口;Kuruwa 不负责特定 agent 框架的集成。 权限由对象与操作授权表达,不预设一条从低到高的沙盒等级链。控制面严格检查公开入口的授权,沙盒自身的隔离强度则由定义决定。允许弱隔离环境,也允许人工交付高权限 shell。 “主机权限”指主 daemon 启动时的实际权限基线,不意味着 root。获得 shell 后,命令及后台进程能做什么由执行环境决定。若环境允许读取管理入口、修改可信定义或连接原始 RMUX socket,公开接口的检查不能阻止这些旁路。 ## 2. 对象模型 | 对象 | 含义 | | --- | --- | | 主 daemon | 按项目启动,管理租户、授权、沙盒实例与终端寻址。 | | 租户 | 一份授权上下文,可以供多个 agent 共用,不等同于 Linux UID。 | | 沙盒定义 | 可信的环境初始化规格,指定外部可执行程序及参数。 | | 沙盒实例 | 初始化后持续存在的环境,由其中的实例 daemon 派生终端进程。 | | 终端实例 | 命令任务与长期 shell 的统一对象,不另设任务实体。 | 每个沙盒实例对应一个 RMUX,作为实例 daemon。环境内的共享方式由沙盒定义决定,不通过每次启动独立沙盒来替代持续实例。 终端名称在同一个主 daemon 的全部租户与实例中唯一。不同主 daemon 不协调名称。名称仅用于寻址,不授予可见性或操作权限。 主机租户拥有最高控制面权限。主机实例使用 noop 初始化,是执行环境,不是授权上下文;两者分别存在。 ## 3. 入口与权限 第一版每个租户有一个受限 Unix socket 入口。共享入口的访问者共享授权,不依赖 agent 自报身份。管理入口供主机租户创建租户、实例和授权。受限租户不能自行创建下级租户或向下委派。 | 授权范围 | 允许的能力 | | --- | --- | | 指定定义的实例创建权 | 创建获准定义的实例,并管理自己创建的实例。 | | 实例控制权 | 在该实例中创建和管理终端;不另设独立的创建终端权限。 | | 指定终端访问权 | 读取输出、发送输入和必要的终端尺寸调整,不包含实例管理权。 | 人工可以创建高权限实例,只把其中一个终端交给受限租户。该租户不会因此取得创建同实例其他终端、清理整个实例或访问其他终端的权限。 撤回访问立即断开本项目受限入口中的相关连接,并禁止后续访问,但不终止终端或回滚 shell 已产生的影响。人工与 agent 的并发输入不做接管协调。 定义的写保护由运行环境实现,例如只读挂载。第一版不建设额外的定义审批系统。沙盒自行决定是否向内部暴露租户入口,默认可以暴露;原始 RMUX 控制入口不作为租户入口交付。 ## 4. 初始化与终端承载 ```text 主 daemon ├─ 管理入口 ├─ 租户受限入口 → 授权检查 → RMUX SDK 操作 └─ 实例启动流程 ├─ 在外侧预绑定内部 Unix listener ├─ 携带 listener FD 执行可信初始化程序 └─ 在最终环境中启动 RMUX ├─ 导入 listener FD,恢复 CLOEXEC,开始服务 └─ 创建自然继承该环境的终端进程 宿主管理 CLI attach → 外侧内部 socket → 原生 RMUX attach ``` 初始化允许执行任意可信代码,也允许跨越 `exec`,不要求用户链接某种语言的库。bwrap 可以用于初始化,但不是核心模型中的固定策略类型。用户只描述一个最终执行环境。 原始 socket 路径应由环境策略对终端进程隐藏;监听 FD 和已接受连接不能泄漏到终端子进程。外侧管理程序通过外侧路径连接。主机 noop 实例不承诺对宿主 shell 隐藏这些资源。 RMUX 导入 listener 后才提供服务。初始化失败或未就绪的实例不得作为可用实例交付。继承 listener 的实例不应自行按不可见路径重绑定或清理 socket;外侧创建者负责相应资源的收尾。 管理入口或目标实例 owner 使用原生 attach,保留完整人工交互体验,不需要透明代理 RMUX 协议。该访问需要实例控制权,不受终端 grant 撤回影响。受限入口使用语义操作,不透传任意 RMUX 命令。 ## 5. CLI 范围 以 muxrun 已验证好用的操作为基础: - `start`、`run`、`resume` 提供启动与等待操作。 - `status`、`ls` 提供状态与列举。 - `send`、`send --key` 提供文本与按键输入。 - `screen`、`tail`、`transcript` 提供视口、渲染历史与原始输出读取。 - `cancel`、`clean`、`gc` 提供生命周期操作,必须检查相应管理权限。 - `attach` 供管理入口或目标实例 owner 使用;`skill` 可提供使用说明。 不向受限租户开放任意 `rmux` 透传。单终端访问权不会因命令存在而获得清理或销毁权限。 CLI 通过环境变量或显式参数选择入口。创建终端必须显式指定实例,之后按终端名称操作。连接失败直接报错,不回退到主机,也不自动启动替代 daemon。 上述是第一版操作范围,不承诺逐字兼容 muxrun 的参数、返回格式、TTL 或自动清理语义;这些细节要在统一终端模型下明确。 ## 6. 生命周期与持久性 - 客户端断线不终止终端。实例 daemon 退出即实例失效,不沿用旧实例身份自动重建。 - 非空实例默认拒绝销毁,显式强制销毁才终止其终端和实例 daemon。 - 自定义初始化可配套清理程序。主机实例只清理本项目管理的进程与资源,不影响其他宿主进程。 - 第一版不保证主 daemon 重启后任务存活或恢复。 - 持久管理配置包含沙盒定义、租户声明及获准使用的定义。具体实例、终端和临时交付授权属于本次 daemon 运行。 - 重启不自动恢复高权限临时授权,旧对象身份不得指向新对象。 - 正常关闭清理受管实例;崩溃后的孤儿自动回收不作为第一版保证。 ## 7. 已验证的技术基础 基于 RMUX 0.8.0 的一次性原型位于 `prototypes/rmux-listener-fd/`,包含监听 FD 适配补丁与复现脚本。主 agent 独立执行以下命令,结果为 `VERIFY_PASS`: ```sh RMUX_SRC=/tmp/rmux-src/rmux prototypes/rmux-listener-fd/verify.sh ``` 运行证据包括: - 外侧预绑定后,初始化完成前请求超时;RMUX 导入 FD 后正常服务。 - 终端中的 socket 路径不可见,真实已接受连接存活时新建的终端也没有内部 socket FD 泄漏。 - 多个外侧 CLI 连接和 typed SDK 输入、按键、屏幕读取正常,缺失 endpoint 不自动启动服务。 - 原生 attach 输入、尺寸调整与 detach 正常。 - 独立终端的实际退出状态为 `42`,进程被回收。 - SIGUSR1 不替换继承 listener,也不创建内部 socket 路径;退出后受管进程和外侧 socket 清理成功。 原型验证的是当前 Linux/bwrap 样例,不证明任意 UID、PID namespace 或初始化程序组合均可用,也不证明同 UID 的 `/proc` 或 ptrace 隔离。租户授权系统尚未实现。 ## 8. 后续实现需细化的接口 后续工作限定为 CLI 参数与错误输出、初始化和清理的参数约定、单一终端对象的等待与清理语义,以及名称重用与旧对象身份的区分。 RMUX 原型以 `OwnedFd` 表达监听 FD 所有权,改变了 Linux 下部分配置类型的 `Clone`/`Eq` 派生。正式适配需要整理 API 兼容性;不能直接把一次性补丁视为可发布上游实现。