> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openkova.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 沙箱（能写到哪）

> 内核级下界：write/edit 的宿主硬校验与 bash 的 macOS Seatbelt 隔离，以及「失败坚决不放行」的口径。

> [!NOTE]
>
> **状态：引擎与切换入口已落地，撞墙卡尚未接入。** 边界判定（宿主写入校验 + macOS Seatbelt
> 包装）、失败关闭语义、会话偏好落库、以及底栏的锁标识都已可用（附单测与真机验证）；
> 「撞墙时弹卡让你选择放行 / 记住目录」还没做——目前撞墙表现为工具错误
> （模型会看到"怎么办"的提示）。默认仍是不隔离，行为与从前一致。

权限档位回答「改之前问不问」，**沙箱档**回答「**内核允不允许**」。两者正交：
审批（或 AI 审查）放行，也越不过沙箱；沙箱拒绝，连审批卡都到不了。

| | |
| - | - |
| 值 | 只读 `read-only` / 工作区隔离 `workspace-write` / 不隔离 `full-access` |
| 管什么 | 文件写入的**硬边界**（内核级，不是提示、不是审批） |
| 模型可见 | 否（工具报错时它才看到，且报错文案带着"怎么办"） |
| 生效 | 下一条工具调用 |
| 默认 | **不隔离**（引入沙箱前的行为）；底栏锁标识可切，新会话跟随「最近一次使用」 |

> 默认不开是刻意的：沙箱最大的风险不是被绕过，而是**让正常活儿莫名失败**。
> 先在愿意试的人身上收集误拦清单，再谈默认。

## 三档的语义

| 档 | write / edit | bash 与后台任务 |
| - | - | - |
| 只读 | 一律拒绝 | 子进程可写集为空（读放开） |
| 工作区隔离 | 工作区内 + 你记过的可写根放行，其余拒绝 | 同左，由 macOS Seatbelt 在**内核层**执行 |
| 不隔离 | 不校验 | 不包装 |

「工作区隔离」的放行集 = 工作区 + 你在 `.kova/permissions*.json` 里记过的可写根 +
平台临时目录 + **工具链缓存白名单**（`~/.bun/install/cache`、`~/.npm`、`~/.cache`、
`~/.cargo/registry`、`~/Library/Caches`、`~/Library/pnpm`、`~/.yarn/berry/cache`、
`~/go/pkg/mod`、`~/.gradle/caches`、`~/.m2/repository` 等）。少一条就有工具链命令
装不上——这是沙箱最常见的"莫名失败"来源。

两条固定规则：

* **读一律放开**。只读档是"不能写"，不是"不能看"——它不是机密性隔离（要防读是另
  一个课题）。
* **`.env` / `.env.*` / `*.pem` / `*.key` 永不落盘**（denyWrite 硬拒绝，连审批都不给）。

## 边界是怎么执行的

| 执行面 | 谁在写 | 怎么管 |
| - | - | - |
| `write` / `edit` 工具 | 宿主进程**自己**写 | 宿主在落盘前做路径校验（realpath 归一化：symlink 与 `..` 逃逸都判到真实落点） |
| `bash`（含后台任务） | 子进程 | macOS 生成 Seatbelt profile，`sandbox-exec` 在**内核层**拒绝越界写 |

判定顺序是 **deny → allow → 拒绝**；不在放行集里的写入会被拒绝，工具错误里带着
可行动的信息（"写进工作区"或"去设置里加可写根"），模型可以自己改道。

## 失败关闭

沙箱起不来（缺 `ripgrep`、平台不支持、profile 生成失败）时，命令**不执行**，并把
原因与出路回给你——绝不当成"没沙箱就裸跑"。宁可这一步失败，也不要"以为隔离了、
实际没有"。

## 与其它两套机制的关系

```
沙箱（下界，内核级）
  └─ 审批档 / AI 审查（上界，问不问）
       └─ 工具调用
```

* **审批**（变更前确认 / 工作区内自动 / 自动编辑）决定"要不要问你"；
* **AI 审查**决定"由模型代替你判"；
* **沙箱**决定"就算放行了，能写到哪"。

所以你可以在"完全访问"下开着工作区隔离：不打扰你，同时写不出工作区。

## 怎么切

底栏（输入框下方）那排控件里，权限选择器右边有一枚**锁**：锁上=工作区隔离，闭合的锁
（蓝）=只读，开锁=不隔离。点它即可切换——切的是**会话级**偏好，刷新/重启后保留；
新会话跟随你最近一次的选择。`full-access` 是默认态，所以要真正启用隔离，得先切一次。

## 已知边界

* **P0 只有 macOS** 做子进程隔离；其它平台选了工作区隔离会**如实报错**，而不是假装隔离。
* **MCP 服务器进程**目前不在包装范围内（P0）；`write`/`edit` 与 bash 都在。
* **网络不设限**（P0 只做文件）；域名白名单是后续版本的事。
* 沙箱是**判断不了意图**的：它只看路径。想让它少拦，就把该放的根加进可写根清单
  （与「工作区内自动」共用同一份清单）。

> [card] [下一步](https://docs.openkova.site/features/modes.md)
>
> 沙箱和它的三个邻居：会话模式、权限档位、自动化档。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.