Repository navigation
Description
agent-management(#23)首版给 subagent 的工作树隔离是软隔离:默认在自己的 worktree 里干活,但拦不住它用主 checkout 的绝对路径出去。Claude Code 的同名能力是强隔离,命令层有主动检查。本 issue 记录这个差距,并说明为什么它应当在 V2 的 Location 作用域就位后再收口。
Claude Code 的强度
isolation: worktree 之下:
- subagent 得到一份从默认分支切出的 worktree(不是父会话的 HEAD)
- Bash / PowerShell 命令在 worktree 内执行;「A command whose working directory resolves to your main checkout instead, for example because the worktree directory was removed while the subagent was running, fails with an error」
- Bash 命令另有两项检查:工作目录必须解析到 worktree、命令不得把 git 重定向回主 checkout(且这些不是运行时计算的)
- 无改动则自动清理
首版能做到的强度
不改动任何文件系统解析逻辑,靠三件既有设施拼出来:
- 六个文件工具都接受绝对路径 ——
tool/read.ts:235、write.ts:41、edit.ts:80、lsp.ts:48、glob.ts:39、grep.ts:51;glob/grep还接受path参数换搜索根 shell有cwd——tool/shell.ts的cmd(shell, command, cwd, env)external_directory权限是现成的强制点 ——tool/external-directory.ts:目标不在 instance 目录内就要过一次ctx.ask;shell.ts会扫命令涉及的目录逐个 ask
于是:建 worktree → 子 Session 权限里预置 external_directory: { "<worktree>/**": "allow" } → 初始 prompt 说明工作目录 → 无改动则清理。
这已经比纯提示词约定强:越界到 worktree 与主目录之外的任何地方都会被 external_directory 拦下,是代码强制而非模型自觉。
差距在哪
子 Agent 仍可用主 checkout 的绝对路径直接操作。 主 checkout 在 instance 目录之内,containsPath(full, ins) 为真,external_directory 按设计放行 —— 它防的是"出界",不是"串门"。
具体缺三项:
| Claude Code | 首版 |
|---|---|
| 命令 cwd 必须解析到 worktree,否则报错 | 无检查,cwd 传什么是什么 |
| 命令不得把 git 重定向回主 checkout | 无检查 |
| worktree 被删则命令失败 | 无检查,会静默落到别处 |
为什么现在不做强制
强制需要"这个 Session 的文件系统根是 X"这一事实在工具层可判定。opencode V1 没有这根轴:
- 文件工具解析路径用的是 instance 级的目录(
InstanceState.directory),不是 Session 的 InstanceState本身以目录为 cache key(effect/instance-state.ts的get用ScopedCache.get(cache, yield* directory)),所以"换目录"等于换到另一份 instance 分片——SessionRunState、SessionStatus、BackgroundJob全都会换一份,agent_list/agent_stop随之失效
也就是说,在 V1 上做强制隔离要先把「文件系统根」与「instance 状态分片键」解耦,那是地基改造,且与 V2 正在建的东西重复。
为什么 V2 能收口
项目约束里已经写明方向:
Keep
SessionRunner, model resolution, tool registry, permissions, and filesystem Location-scoped. OmittedLocation.workspaceIDmeans implicit-local placement; explicit workspace identity remains reserved for future placement semantics.
Location 正是那根缺失的轴:文件系统按 Location 走,执行调度不必跟着走。届时"这个 Agent 的根是哪个 worktree"在工具层可判定,上面三项检查才有落点。
收口时要做的
- 工具层从 Session/Location 解析文件系统根,而非 instance 目录
shell执行前断言 cwd 解析到该根之内,否则失败- 命令扫描增加 git 重定向检查(
--git-dir/--work-tree/GIT_DIR等) - 根目录消失时命令失败而非回落
- 与
external_directory的关系厘清:前者防出界,新增的防串门,两者并存
关联
- feat(task): add task management API — list running background tasks and abort/stop a task #23 agent-management(首版在此实现软隔离)
- 强制隔离依赖 V2 Location 作用域落地,不单独在 V1 上建
Activity
feat(opencode): agent management surface (#35)