> For the complete documentation index, see [llms.txt](https://rokurokulab.gitbook.io/roku-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://rokurokulab.gitbook.io/roku-docs/subsystems/approval-and-execution-policy.md).

# Approval & Execution Policy

> create time: 2026-04-21 19:14 modify time: 2026-04-21 19:45

***

### description: Roku 在每次工具调用前插入的一道审批关——风险分层的心智模型、三种 gate 的角色分工、规范化执行的意义，以及目前这块哪里紧、哪里松。

## Approval and Execution Policy

每一次工具调用，在真正执行之前都会过一道审批关。这是主循环的固定路径，不是可选的拦截点。被判定为需要审批的工具，如果审批被拒，拒绝原因会作为一段工具结果返回给 LLM，循环继续下一轮——而不是让整个请求 crash 掉。

这个设计取向是一贯的：审批不是一个"中止执行"的信号，而是一个"这次不让你做，你换种方式试试"的信号。

### 三个相互独立的关注点

Roku 把这件事拆成三个独立的层次：

* **怎么判断一次工具调用有多危险**（风险分级）
* **谁来做实际的放行/拒绝决策**（审批门）
* **执行本身如何被规范化记录**（canonical execution）

这三层各自都可以单独替换，不会牵动另外两层。

### 风险分层的心智模型

Roku 把工具粗略分成三档：

**Safe**。只读、无副作用、或明显无害的操作。比如读取文件、枚举目录、调用终止循环的伪工具（`final_answer` / `fail` / `ask_user`）。这一档直接放行。

**Requires approval**。会写、会变更、会对外发起动作的工具。默认需要审批。Roku 对"未知"也放在这一档——没有明确的安全标签、工具目录里又找不到元数据时，保守处理为需要审批，而不是默认放行。

**Denied**。根本不应该执行。目前只有 Bash 这一个工具有这一档：极少数命令形态（破坏性文件操作、磁盘格式化、fork bomb 等）被直接硬拒。其他工具没有 Denied 档——要不就是 Safe，要不就是走审批。

Bash 之所以是特殊存在，是因为它的风险完全在命令字符串里而不在 tool catalog 的元数据里。审批前要看命令本身——先检查是否命中硬拒列表、再看是否包含 shell 组合符（`&&`、`|`、`` ` ``、`$()` 等，凡是能把"安全前缀"和"后续危险操作"接起来的都视为不能简单放行）、最后才检查命令前缀是否属于一个小而稳定的只读白名单。

这里有一处需要明确：只读白名单不是给"常用"命令开的，而是为"确认没有副作用"的命令开的。不在白名单上不代表一定危险，只代表需要审批。

### 三种 gate 的角色分工

一个 gate 就是一个 trait 对象，负责把上面那套风险分级翻译成一个放行/询问/拒绝的决定。目前有三种形态，按使用场景不同：

**无条件放行**。常驻自动化脚本、CI、已知可控的环境用这种——它不调用风险分级逻辑，所有工具一律直接 Approve。这就意味着即便是 Bash 的 Denied 列表，在这个 gate 下也形同虚设。这不是 bug，而是一个自觉的设计选择：无条件放行模式是给"你完全清楚自己在跑什么"的场景用的；如果你不想承担 Denied 列表被绕过的后果，就不要启用它。

**交互审批**。在 TUI/REPL 场景下，需要审批的工具会在 stderr 上弹出一行提示，等用户输入 `y` 放行、`n` 拒绝，或者 `a` 从此刻起改为无条件放行。这种 gate 是大多数日常使用下默认的形态。

**pipe 模式拒绝**。非交互调用（stdin 被数据流占用、脚本化 pipe）下，没法弹提示等用户，需要审批的工具会直接拒绝，并在错误信息里提示用户切回交互模式。这种 gate 把"无人值守时遇到不确定就不做"贯彻到底。

三种 gate 背后都接的是同一个风险分级逻辑，区别仅在于"需要审批时怎么做决定"这一步。

### 规范化执行：审批看的是它

工具调用的原始参数是一段 JSON 字符串——对审计、对人类审批者、对恢复路径，这段 JSON 都不够稳定也不够直观。Roku 因此引入了一个规范化的执行视图（canonical execution），把一次即将发生的工具调用翻译成一组更明确的字段：

* 要调用的工具名、最终要执行的程序、参数列表
* 执行模式是直接 exec 还是 shell 包装
* 工作目录、环境变量策略
* 涉及的资源范围：读路径、写路径、工作根
* 这次执行的语义类型：读、写、执行、网络、混合
* 一个用于唯一标识此次执行的 digest

审批流程里，审批者看到的是这份规范化视图——不是原始 JSON。审批记录通过 digest 绑定到这次具体执行上，为未来的"挂起—人工决策—继续"链路打基础。

目前这个规范化视图只覆盖 Bash 和一组文件系统工具；其他工具返回 None，走原始参数路径。这是一个分阶段实现：先把最危险的操作纳入规范化，后续再扩到更多工具。

### 这块哪里紧、哪里松

**紧的地方**。审批是硬性串在主循环里的，不能跳过。风险分级在未知工具上 fail-closed。只读白名单保守且显式。Bash 的 shell 组合符被特殊对待，防止把安全前缀和危险后缀拼起来。

**松的地方**。

* 无条件放行 gate 会跳过一切风险分级，包括 Denied 命令。这是设计选择，但也意味着风险完全转移给部署者。
* 审批请求和工具执行的规范化信息在类型层面已经完整，但"挂起等人工审批—再继续"这条 resume 链路在进程重启后还接不上——快照目前只在内存里。
* Roku 里同时存在两套相关类型：runtime 侧一套（执行路径上实际用的），数据合约侧一套（更完整的审批/策略记录用的）。两者目前在执行路径上没有完全统一，\[未查明] 是否有计划收敛到同一套。

这些是已知的"还没完善"，不是被遗忘的角落。如果你在真实部署里依赖完整的审批持久化或审计对齐，需要自己留意。

***

参见 [agent-loop](/roku-docs/subsystems/agent-loop.md) 了解审批门在主循环里的调用位置；[roku-common-types](/roku-docs/crates/roku-common-types.md) 了解规范化执行和审批记录在数据合约层的完整字段。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://rokurokulab.gitbook.io/roku-docs/subsystems/approval-and-execution-policy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
