开源终端编码 Agent opencode:什么时候别用它干活
本文基于 opencode 仓库 commit 7fe9938(2026-08-04)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/anomalyco/opencode 最新代码与文档为准。
判断一个任务该不该交给 opencode,看的不是它能不能做,而是做错了你多久能发现、多快能退回去。 这两个数字如果答不上来,任务再简单也别放它自动跑;答得上来,改动再大也可以分批交出去。
opencode 是一个 MIT 许可证的开源项目(仓库根目录 LICENSE,Copyright 2025 opencode),默认形态是终端里的 TUI,也能用 opencode run 跑非交互式的单次任务。它把 shell 命令执行、文件读写、子代理调度都放在同一个权限框架下。正因为这些能力是真的会落到你磁盘上的,判断顺序比操作技巧更值钱。
这篇只回答「什么时候不该开这个会话」。至于同一件事该交给模型还是该写成硬编码流程,看Agent 硬编码流程与模型自主决策的边界;会话开起来之后账单怎么控,看Agent 成本失控的识别与止血;它吐出来的代码能不能直接进生产,看AI 写的代码能上生产吗。三篇各管一段,本篇管最前面那个「开不开」。
一、第一道闸:一条命令能解决的,别开会话
opencode 自己的提示词里就写着这条。packages/opencode/src/tool/task.txt 是 Task 工具的说明文本,它有一整段叫 When NOT to use the Task tool:
- If you want to read a specific file path, use the Read or Glob tool instead of the Task tool, to find the match more quickly
- If you are searching for a specific class definition like "class Foo", use the Grep tool instead, to find the match more quickly
- If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Task tool, to find the match more quickly
- If no available agent is a good fit for the task, use other tools directly
这段是写给模型看的,但换成人的视角同样成立:目标明确、路径已知、结果可直接验证的操作,多套一层代理只会多一次上下文往返和一次误判机会。你要看某个文件第几行写了什么,grep 一下就完了;你要知道某个函数在哪儿,编辑器跳转比让模型搜一遍快得多。
具体到 opencode,这道闸可以这样落:
- 目标能用一句 shell 命令表达,而且你敢直接把这条命令粘进终端——那就自己敲。
- 目标需要读三五个文件才能想清楚,但改动点你心里已经有了——用
opencode run跑一次非交互式的,别开 TUI 长会话。packages/web/src/content/docs/cli.mdx里给run的定位就是脚本化与自动化场景,它还支持--attach挂到已经起好的opencode serve上,省掉每次 MCP 服务器冷启动的时间。 - 目标需要来回澄清、需要看着它改再决定下一步——这时候才值得开 TUI 会话。
判断成本几乎为零,收益却是实的:会话开得越少,你需要审的 diff 就越少,需要盯的权限弹窗也越少。
二、第二道闸:改动面太大的,先拆再交
改动面大不大,不看行数,看两件事:涉及几个互不相关的模块、失败之后有几处需要人工回滚。任何一个数字超过三,就不该一次性交出去。
opencode 在这件事上准备了一套现成的分级手段,都写在 packages/web/src/content/docs/agents.mdx 里。
内置两个主代理。build 是默认主代理,全部工具可用,适合需要完整文件操作与系统命令权限的开发工作。plan 是受限主代理,按文档说明,所有写入、补丁、编辑以及全部 bash 命令默认都是 ask,用来分析代码、给改动建议、出计划,而不实际修改代码库。TUI 里按 Tab 键(或你配置的 switch_agent 键位)在主代理之间切换。
内置三个子代理。general 有除 todo 之外的完整工具权限,可以改文件,适合并行跑多个工作单元;explore 是只读的快速代理,不能修改文件,用来按模式找文件、搜关键词、回答关于代码库的问题;scout 同样只读,用于外部文档与依赖调研,能把依赖仓库克隆进 opencode 管理的缓存里读源码,而不动你的工作区。
另外还有一个专门的建议开关。packages/opencode/src/tool/plan-enter.txt 是一个工具的说明文本,作用是在用户的请求「适合先规划再实现」时建议切到 plan 代理,并明确写了不要在简单直接的任务上调用、也不要在用户明确想立刻实现时调用。而 packages/opencode/src/session/prompt/plan-mode.txt 是规划模式激活后注入的系统提醒,开头就写死了不得做任何编辑、不得运行任何非只读工具(包括改配置和提交),唯一允许写的是那个计划文件本身。
对你意味着什么:拆解不必靠自觉,可以靠角色。先用 plan 或 explore 把范围摸清、把计划写出来,人过一遍,再切 build 分批执行。中间那次人工过目是这套流程里最便宜也最有效的一环——花你三分钟,省掉的是一次跨五个模块的错误重构。任务该拆到多细,任务分解粒度怎么定那篇讲得更细。
三、第三道闸:没有测试兜底的,别开自动批准
opencode 的权限系统是它最值得先读的部分,规则全在 packages/web/src/content/docs/permissions.mdx。每条规则解析成三种动作之一:allow 直接运行、ask 弹窗确认、deny 直接拦掉。
关键是默认值,文档写得很直白:多数权限默认 allow;doom_loop 和 external_directory 默认 ask;read 默认 allow,但 .env 类文件默认被拒。前三条在代码里能一一对上,packages/opencode/src/agent/agent.ts 里构造默认权限时是这样写的:
const defaults = Permission.fromConfig({
"*": "allow",
doom_loop: "ask",
external_directory: {
"*": "ask",
...
},
question: "deny",
plan_enter: "deny",
plan_exit: "deny",
.env 这一条值得单独说一句:同一份代码里 read 的默认块给 *.env 与 *.env.* 写的是 ask(弹窗问你),*.env.example 保持 allow;而权限文档 Defaults 那节的示例把前两项写成了 deny。两边描述的严格程度不一样,谁更新更快都可能变。所以别把「密钥文件读不到」当成既定事实来用,装完之后自己让它读一次 .env,看它是弹窗、是拒绝还是直接读走,以你机器上的实际行为为准。
也就是说,开箱状态偏宽松。它会在你没配置任何东西时就允许改文件、允许跑 bash。这不是缺陷,是这类工具的产品取向,但它把配置责任明确交给了你。
再叠一层的是 --auto。文档写明:用 --auto 启动会自动批准所有没有被显式拒绝的权限请求,opencode run --auto 同样适用;显式的 deny 规则仍然强制生效,auto 模式只改变那些本来会弹窗询问的请求。TUI 里可以从命令面板开关,开启时提示区会在当前代理旁边显示一个淡色的 auto 标记。
把这几件事连起来看,结论就出来了:--auto 的安全性完全由你写的 deny 规则决定,而不是由模型的谨慎程度决定。所以在没有测试兜底的仓库里开 --auto,等于把「改错了」这件事的发现时机,推迟到你自己肉眼看 diff 的那一刻。
packages/opencode/src/session/prompt/default.txt 里对模型的要求是「Verify the solution if possible with tests. NEVER assume specific test framework or test script. Check the README or search codebase to determine the testing approach.」——注意 if possible 这三个词。测试不存在的时候,这条约束自动失效,模型手里没有任何东西可以自证改对了。
回滚这一侧同样有前提。packages/web/src/content/docs/config.mdx 说 opencode 默认开启 snapshot 来跟踪代理操作期间的文件变更,从而支持会话内撤销与回退,实现方式是一个内部 git 仓库;大仓库或子模块多的项目会因此索引变慢、磁盘占用明显,可以用 snapshot 配置关掉,但关掉之后代理做的改动就无法从界面回滚。packages/web/src/content/docs/tui.mdx 里 /undo 的说明更硬:它会移除最近一条用户消息、后续所有响应以及产生的文件改动,而且内部使用 Git 管理这些文件改动,所以你的项目必须是一个 Git 仓库。
所以「没有测试兜底别自动跑」的完整版是:没有测试、不在 Git 仓库里、或者你为了性能关掉了 snapshot,这三种情况下都别开自动批准。测试与回滚这两件事怎么配合,回归测试怎么给 Agent 兜底那篇有更系统的写法。
四、这几个部件你迟早会碰到
| 组成部分 | 它负责什么 | 对应仓库位置 | 你什么时候会碰到它 |
|---|---|---|---|
| 权限规则与默认值 | 决定每个工具调用是直接跑、弹窗还是拦掉 | packages/web/src/content/docs/permissions.mdx、packages/core/src/v1/config/permission.ts | 第一次发现它没问就改了文件的时候 |
| 代理与子代理配置 | 主代理/子代理的模型、提示词、权限、迭代上限 | packages/web/src/content/docs/agents.mdx | 想让评审角色只读、让规划角色不许动手的时候 |
| 规划模式提示 | 建议切到规划代理,并在规划期间禁止一切写操作 | packages/opencode/src/tool/plan-enter.txt、packages/opencode/src/session/prompt/plan-mode.txt | 任务比你以为的大,需要先出计划的时候 |
| Task 工具说明 | 定义什么时候该派子代理、什么时候直接用工具 | packages/opencode/src/tool/task.txt | 觉得它「为了读一个文件绕了一大圈」的时候 |
| 快照与撤销 | 用内部 git 跟踪改动,支持 /undo 回退 | packages/web/src/content/docs/config.mdx、packages/web/src/content/docs/tui.mdx | 改砸了想退回去,或者大仓库嫌它慢的时候 |
| 项目规则文件 | 把构建、lint、测试命令与项目约定固化进上下文 | packages/web/src/content/docs/rules.mdx、仓库根 AGENTS.md | 它反复用错命令、反复违反项目约定的时候 |
| 命令与环境变量 | 非交互执行、挂载已有服务、统计用量、各类开关 | packages/web/src/content/docs/cli.mdx | 想把它塞进脚本或 CI 的时候 |
| 会话分享 | 把会话同步到服务端并生成公开链接 | packages/web/src/content/docs/share.mdx | 想把一段排查过程发给同事的时候 |
顺带说一下这个仓库的体量,方便你判断读它要花多久:packages/ 下 32 个包,英文文档 packages/web/src/content/docs/ 共 36 份 mdx,packages/opencode/src/session/prompt/ 有 14 份提示词,packages/opencode/src/tool/ 有 25 个 .ts 与 15 个 .txt,根目录另有 21 份 README 翻译,全仓受版本控制的文件 6358 个。想搞清楚它到底会对你的机器做什么,读权限文档加 tool 目录那批 .txt 就够了,不用通读源码。
五、边界与代价:它明确不管的那些事
它不替你判断改动对不对。 权限系统管的是「这个动作允不允许发生」,不管「这个动作是不是你要的」。把一条 bash 规则设成 allow 之后,跑对了和跑错了走的是同一条路径。判断对错这件事,只能靠测试、类型检查和你自己的眼睛。
放宽权限的代价是真实的。 这类工具会在你的机器上执行 shell 命令、直接改你的代码文件、把读到的代码内容发给模型服务商。把 bash 整体设成 allow 之后,一条 rm 就能删掉不该删的目录;把 external_directory 从默认的 ask 放开,工具就能读写工作目录之外的路径。默认拒绝 .env 只挡住了最常见的一类密钥文件,硬编码在源码里的凭证、CI 配置里的 token、日志里残留的密钥,权限系统一概不认。权限该收到多紧,最小权限怎么设计那篇给了可以直接抄的思路。
分享等于公开。 packages/web/src/content/docs/share.mdx 写得毫不含糊:分享出去的会话对任何拿到链接的人都可访问,会话历史会同步到项目方服务器,链接形如 opncd.ai/s/<share-id>。默认是手动模式,需要你执行 /share 才会生成链接,但配置里可以把 share 设成 auto,让所有新会话自动分享。在私有代码库里工作时,这个开关值得先确认一遍。
它不保证收敛。 doom_loop 这条权限的触发条件很朴素:同一个工具调用用完全相同的输入重复 3 次。这是个兜底提醒,不是纠错机制——它只能告诉你「它卡住了」,不能告诉你「它想错了」。真正的目标漂移和缓慢跑偏,这条规则一点忙都帮不上。
成本不封顶。 agents.mdx 里的 steps 选项可以限制一个代理在被迫只输出文字之前能做多少次代理式迭代;文档明说,如果不设这个值,代理会一直迭代到模型自己选择停止,或者你手动中断会话。至于每次迭代花多少,取决于你接的模型服务商,各家规则不同且会调整,以官方最新说明为准。
它不是本地闭环。 除非你接的是本地模型,代码内容要发到模型服务商那边才有结果。这条对合规敏感的团队是硬约束,不是调配置能绕开的。
六、上手与避坑清单
先读权限文档再装。 为什么会踩:默认值偏宽松,多数权限默认 allow,装完直接聊天就可能被改文件。怎么避:装之前把 packages/web/src/content/docs/permissions.mdx 的 Defaults 那节读完,然后在项目里写一份最小的 permission 配置,把 bash 收成 ask 或改用对象语法逐条放行。
记住最后匹配的规则赢。 为什么会踩:权限文档里明写,规则按模式匹配,最后一条匹配的规则生效。很多人按「越具体越优先」的直觉排序,把 "*" 写在末尾,一条通配把前面所有精细规则全覆盖了。怎么避:照文档推荐的写法,把 "*" 放最前面,具体规则往后排,改完拿一条真实命令试一次。
bash 规则要带参数通配。 为什么会踩:文档提示里说得很清楚——"grep *" 能放行 grep pattern file.txt,而单写 "grep" 会把它拦住;像 git status 这样的命令在无参数时按默认行为走,带参数时需要显式的 "git status *"。怎么避:写 bash 规则时默认都补上末尾的通配,除非你就是只想放行光秃秃的那一条。
~ 展开不等于纳入工作区。 为什么会踩:权限文档专门澄清了这点——home 展开只影响模式怎么写,不会让外部路径变成当前工作区的一部分,工作目录之外的路径仍然必须通过 external_directory 放行。有人在 edit 里写了家目录下的路径就以为通了,实际还卡在外部目录这一关。怎么避:跨目录访问一律先加 external_directory 规则,再按需要叠加针对具体工具的 allow 或 deny;文档里也提醒,被放行的外部目录会继承当前工作区的同一套默认值,所以该单独拦的要单独拦。
别在非 Git 仓库里放它自动跑。 为什么会踩:/undo 内部靠 Git 管理文件改动,项目不是 Git 仓库就没有这条退路;如果你为了性能关掉了 snapshot,界面上的回滚也一起没了。怎么避:确认 git status 干净再开会话,改动分批提交,让每一段自动执行都有一个明确的回退点。
把验证命令写进 AGENTS.md。 为什么会踩:default.txt 要求模型完成任务后运行 lint 与 typecheck,前提是这些命令「已经提供给它」;找不到命令时它会回头问你。项目里如果有非常规的运行方式,它多半会猜错。怎么避:照 packages/web/src/content/docs/rules.mdx 的建议,在项目根放 AGENTS.md,把构建、lint、测试命令与执行顺序写清楚并提交进 Git。opencode 自己根目录的 AGENTS.md 就是范例,里面直接写了要在包目录下运行 bun typecheck、以及测试不能从仓库根跑、要进 packages/opencode 这类包目录跑。
长命令先想好超时。 为什么会踩:shell 工具有默认超时,packages/opencode/src/tool/shell.ts 里超时后返回的提示是让模型带更大的 timeout 值重试。构建或集成测试这种长任务被中途砍掉,模型可能拿着半截输出继续往下推理。怎么避:在提示词里明确告诉它这条命令预期耗时长,或者干脆把长构建放在会话之外自己跑完再回来。
定期看用量。 为什么会踩:steps 不设就没有迭代上限,一个跑偏的会话可以自己转很久。怎么避:opencode stats 会显示会话的 token 用量与成本统计,支持按天数、按项目过滤,把它加进你的周检查清单;对固定用途的自定义代理,直接在配置里给 steps 设个上限。
收束:开会话之前问自己四句
这四句按顺序问,任何一句答不上来就停在那一步:
- 这件事能不能用一条我敢直接粘进终端的命令解决?能就自己敲,别开会话。
- 改动涉及几个互不相关的模块?超过三个,先用 plan 或 explore 出计划,人过一遍再分批交。
- 改砸了我多久能发现?没有测试、没有类型检查,答案就是「等我自己看 diff 那一刻」——这种状态别开
--auto。 - 发现之后多久能退回去?项目在 Git 里、
snapshot没关掉、工作区是干净的,才算真有退路。
接下来该读哪个文件,取决于你卡在哪一句:卡在第 3、4 句就读 packages/web/src/content/docs/permissions.mdx,先把默认值和「最后匹配的规则赢」这两件事吃透;卡在第 2 句就读 packages/web/src/content/docs/agents.mdx,把 plan、explore、scout 各自的边界搞清楚;想把它塞进脚本和 CI,就读 packages/web/src/content/docs/cli.mdx 里 run 和 serve 那两节。这几份文档加起来一个下午读得完,比在会话里试错省事得多。
本篇属于一个把开源AI 编程 Agent 项目 opencode逐层拆开讲的系列,整体地图见 opencode 是什么:终端里的开源 AI 编程 Agent 全景地图;沿着这条线往下,还可以看 开源终端编码 Agent 项目 opencode 的安全边界:它明说不做沙箱,你该在外面补什么 和 opencode 开源终端编码 Agent 拆解:服务端分离、双主智能体与权限规则。