opencode 是什么:终端里的开源 AI 编程 Agent 全景地图

2026-08-04

本文基于 opencode 仓库 commit 7fe9938(2026-08-04)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/anomalyco/opencode 最新代码与文档为准。

opencode 最值得先记住的一件事:它不是一个「终端里的聊天框」,而是一个自带 HTTP 服务端的本地进程,你在终端里看到的界面只是它的第一个客户端。 想明白这一点,它后面那些设计——桌面端、编辑器插件、SDK、可编程调用——就都是同一个东西的不同外壳,而不是零散功能的堆砌。

先做个命名上的澄清:opencode 是这个开源项目的名字,首字母小写,仓库在 anomalyco/opencode,采用 MIT 许可证(LICENSE 文件里写的是 Copyright 2025 opencode)。本文里凡是写「opencode」的地方都指这个项目,不是泛指「开源的代码」,也不是别的名字相近的模型或工具。

站内已经有几篇相邻的文章,分工不同:AI 编程工具横评是站在选型角度对比多家产品,开源 AI 工具盘点是把开源生态铺开看一遍,Agent 框架对比讲的是搭 Agent 时的框架取舍;这一篇不做横向排名,只把 opencode 这一个仓库拆开,告诉你它内部分了哪几块、每块解决什么问题、哪些事它明确不管。它也是本系列的入口。

一、它的形态:一个进程,两个角色

装完之后你敲的命令就一个词:opencode。README 里给的安装方式很多,最简单的是安装脚本:

curl -fsSL https://opencode.ai/install | bash

npm 包名是 opencode-ai,另外还有 Homebrew、Scoop、Chocolatey、pacman、AUR、mise、Nix 等渠道,也提供了独立的桌面应用(处于 BETA)。安装脚本落盘位置按 $OPENCODE_INSTALL_DIR$XDG_BIN_DIR$HOME/bin$HOME/.opencode/bin 的优先级依次判断,如果你有多套二进制来源,这个顺序值得先看一眼。

真正有意思的是运行形态。文档里写得很直接:你运行 opencode 时,它会同时启动一个 TUI 和一个服务端,TUI 是那个跟服务端说话的客户端。服务端暴露的是 OpenAPI 3.1 规范端点,SDK 就是从这份规范生成的。你也可以只要服务端,不要界面:

opencode serve [--port <number>] [--hostname <string>] [--cors <origin>]

默认监听 127.0.0.1:4096。想加一层保护,设置 OPENCODE_SERVER_PASSWORD 就会启用 HTTP 基本认证,用户名默认是 opencode,可以用 OPENCODE_SERVER_USERNAME 覆盖。

这个「客户端/服务端分离」的取向决定了它的接入方式不止一种:终端 TUI 是一种,桌面应用是一种,编辑器侧通过 Agent Client Protocol 接入是一种(配置编辑器去跑 opencode acp,它会作为子进程用 stdio 上的 JSON-RPC 跟编辑器通信),直接调 HTTP 接口把它当服务用也是一种。对你的意义是:如果你打算把编码 Agent 编排进自己的流水线,而不只是坐在终端前面聊天,它留了正经的接口面,不用去逆向界面。

二、它把「写代码」拆成了哪几块

仓库是个 monorepo,packages/ 下有 32 个包。不用全看,按职责挑几块看就够了。

组成部分它负责什么对应仓库位置你什么时候会碰到它
终端界面你实际敲字、看输出、按 Tab 切 Agent 的地方,包名 @opencode-ai/tuipackages/tui/每天用;改主题、改键位时
主程序与会话运行时会话的推进、模型调用、工具调度都在这里packages/opencode/src/session/排查「它为什么没继续干」时
工具层Agent 能对你机器做的所有动作的实现packages/opencode/src/tool/(25 个 .ts 与 15 个 .txt想知道某个工具到底怎么执行时
提示词按模型/模式分开维护的系统提示词文本packages/opencode/src/session/prompt/(14 份 .txt想看清它给模型下了什么指令时
权限层判定某次工具调用是直接跑、先问你、还是拒绝packages/opencode/src/permission/packages/core/src/permission.ts第一次被弹窗打断时
服务端与协议HTTP 接口、路由、事件流的契约packages/server/packages/protocol/要编程调用它时
客户端与 SDK从公共接口生成的调用库packages/client/packages/sdk/packages/sdk-next/要把它嵌进自己程序时
桌面端非终端形态的外壳packages/desktop/不想活在终端里时
文档站官方文档源文件packages/web/src/content/docs/(36 份英文 .mdx查配置项时(比翻博客快)

顺带一个能说明这个项目气质的细节:根目录有 21 份 README 翻译(简体、繁体、韩、德、西、法、意、丹、日、波兰、俄、波斯尼亚、阿拉伯、挪威、巴葡、泰、土、乌克兰、孟加拉、希腊、越南),全仓受版本控制的文件有 6358 个。它不是一个几百行的玩具脚本,是一套有工程约束的代码库。

工具层那 25 个 .ts 里,你日常真正会感知到的是文档《Tools》一节列出的这批内置工具:basheditwritereadgrepglobapply_patchskilltodowritewebfetchwebsearchquestion,外加一个实验性的 lsp。有两个实现细节值得知道:grepglob 底层用的是 ripgrep,默认尊重 .gitignore,所以被忽略的目录它默认搜不到——需要放行时在项目根建一个 .ignore 文件显式允许;websearch 只有在使用 opencode 自家 provider 或设置了 OPENCODE_ENABLE_EXA 环境变量时才可用,它连的是 Exa AI 的托管 MCP 服务。lsp 工具需要 OPENCODE_EXPERIMENTAL_LSP_TOOL=true(或 OPENCODE_EXPERIMENTAL=true)才出现。

Agent 这一层分两类。主 Agent 是你直接对话的对象,用 Tab 键循环切换,内置两个:build 是默认的全权限开发 Agent,plan 是受限的分析规划 Agent,默认把文件改动和 bash 命令都设成先问你。子 Agent 由主 Agent 调起,也可以用 @ 提及手动召唤,内置三个:general(多步任务与复杂检索)、explore(只读,快速摸代码库)、scout(只读,看外部依赖与上游实现)。另外还有三个隐藏的系统 Agent:compaction 负责把长上下文压成摘要,title 生成会话标题,summary 生成会话摘要,都自动运行、界面里选不到。

自定义 Agent 有两种写法:写进 opencode.jsonagent 字段,或者在 ~/.config/opencode/agents/.opencode/agents/ 下放 Markdown 文件(文件名即 Agent 名,frontmatter 里写 descriptionmodemodelpermission 等)。不想手写就跑 opencode agent create,它会交互式问你存哪、干什么、给哪些权限,然后生成文件——注意它的默认取向是「你没勾选的一律拒绝」。

三、上下文这块,它专门立了一套词汇

opencode 仓库根目录有一份 CONTEXT.md,专门给会话运行时定义术语,而且明确写了哪些说法要避免——比如它把喂给模型的那组结构化事实叫 System Context,并注明「避免叫 system prompt」;把某一次实际选进请求的对话叫 Session History,注明「避免叫 session context」。

这不是命名洁癖。它背后是一个具体的机制:每一条独立可观测的上下文事实是一个 Context Source,有稳定的 key、编解码器、加载器和渲染器;一个 Context Epoch 开始时渲染出的那份完整上下文叫 Baseline System Context,它在这个 Epoch 内原样保留、跨进程重启也照旧复用,因为这段前缀要拿去命中服务商的缓存;当某个 Context Source 的值变了(比如日期变了、可用技能变了、项目指令文件变了),它不会去改那段基线,而是在下一个安全的模型调用边界上追加一条时间线上的系统消息,告诉模型「这项现在的有效值是什么」。按 CONTEXT.md 的定义,一个 Epoch 在压缩(compaction)完成、会话发生迁移、或者出现无法沿用旧基线的上下文切换时才结束,届时重渲一份新的基线。

对你的意义有三点。第一,会话跑很久之后它的上下文不是被反复重写的一锅粥,而是一条可审计的时间线,出问题时能往回追。第二,它明确写了「上下文变化绝不会唤醒空闲会话」,都是在下一次自然的模型调用前懒加载比较——所以你改了 AGENTS.md 不会立刻生效,得等下一轮。第三,项目指令的加载路径是全局与逐级向上的 AGENTS.md 聚合成一个有序整体;如果你设了 OPENCODE_DISABLE_PROJECT_CONFIG,项目侧指令会被跳过,全局的仍然生效。

工具输出也走同一套克制:Core 执行完工具后,进入会话历史和回放给模型的是一份有界的投影,超限部分被截断(保留头尾),完整文本落到一个临时的托管输出文件里,模型看到的预览里会带上那个文件路径。也就是说,模型看到的从来不是你磁盘上的原始输出全文——排查「它为什么漏了日志里那一行」的时候,这是第一个要想到的原因。

项目指令用 AGENTS.md,在 TUI 里跑 /init 可以生成或就地改进这个文件;它会扫仓库里的重要文件,必要时反问你几个问题,产出构建/测试命令、目录结构、项目约定这类后续会话最需要的信息。技能则是 SKILL.md,按目录约定发现:.opencode/skills/<name>/SKILL.md~/.config/opencode/skills/<name>/SKILL.md,以及兼容 .claude/skills/.agents/skills/ 的同名布局。这里有个容易忽略的点:注入上下文的只有技能的名称和描述,正文只有在通过受权限检查的 skill 工具加载时才会进来。

四、权限:它默认很松,这是你上手第一天要动的地方

这一节请当成安全提示读,别跳。

opencode 的权限用一套配置解决,每条规则解析成三种结果之一:allow(直接跑)、ask(问你)、deny(拦掉)。可配的键按工具名走,包括 readedit(覆盖 editwriteapply_patch 三个改文件的工具)、globgrepbashtaskskilllspquestionwebfetchwebsearch,另外两个是安全护栏:external_directory(工具碰到项目工作目录之外的路径时触发)和 doom_loop(同一个工具调用带着完全相同的输入重复三次时触发)。

默认值是:大部分权限默认 allowdoom_loopexternal_directory 默认 askread 默认允许,但 .env 类文件默认被拒——文档里给出的默认形态是这样:

{
  "permission": {
    "read": {
      "*": "allow",
      "*.env": "deny",
      "*.env.*": "deny",
      "*.env.example": "allow"
    }
  }
}

把这句翻译成人话:开箱即用的状态下,它可以在你的机器上直接跑 shell 命令、直接改你的文件,不用问你。 这是效率取向的选择,代价你必须自己认领。要收紧就用对象语法按模式匹配,规则最后一条命中的生效,所以通配的 "*" 要放最前面:

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "bash": {
      "*": "ask",
      "git *": "allow",
      "npm *": "allow",
      "rm *": "deny",
      "grep *": "allow"
    },
    "edit": {
      "*": "deny",
      "packages/web/src/content/docs/*.mdx": "allow"
    }
  }
}

反方向也有:--auto 启动会自动批准所有「本该问你」的请求,显式的 deny 仍然强制生效。opencode run --auto "..." 同理。这个开关在无人值守脚本里很好用,在你自己那台装着生产密钥的机器上就不太好用。关于权限放太松之后具体会以什么形式出事,展开可以看权限给太大之后会发生什么

五、边界与代价:它放弃了什么,什么时候别用它

任何设计都有账要还,opencode 这几笔账写在明面上。

它默认信任你的工作目录。 权限模型是围绕「当前工作目录」建起来的,目录外的访问要靠 external_directory 显式放行。反过来说,目录之内的东西,默认就在它的作用面内。如果你的仓库里躺着未加密的凭证、客户数据、还没脱敏的样本,那它们随时可能被读进上下文再发给模型服务商。这不是 bug,是这个设计的必然结果。

它会真的改你的文件。 editwriteapply_patch 三个工具都归 edit 权限管,默认允许。TUI 里有 /undo/redo,可以多次回退,但这是它自己的撤销栈,不等于版本控制的安全网。在一个没提交、没 stash 的工作区里放手让它干,出事的时候你能追回什么,取决于你事前做了什么。

代码会离开你的机器。 只要它调模型,读到的文件内容就会进请求体。凭据存在 ~/.local/share/opencode/auth.json(用 /connect 添加)。模型侧的数据留存、训练使用、并发与配额规则各家不同且会调整,以官方最新说明为准——你要做的判断是:这个仓库允不允许出网。

分享功能是公开的。 /share 会给当前会话生成一个公开链接,把对话历史同步到项目方的服务器,任何拿到链接的人都能看。默认是手动模式(不会自动分享),但配置里可以改成 auto,也可以设成 disabled 把这个功能整个关掉——后者写进项目的 opencode.json 再提交进 Git,就是一个团队级的开关。在企业仓库里用之前,先确认这个开关的状态。

它明确不管的事。 它不是 CI,不替你保证测试通过;它不是代码审查系统,plan Agent 给的是分析和计划,不是审批结论;它不做部署编排;opencode serve 默认只监听回环地址,服务端文档给出的保护手段就是「设一个环境变量启用 HTTP 基本认证」这一层,组织级的集中配置、身份对接这些都不在这个命令的默认能力里——想把它开给别人用,认证、网络边界、访问记录都得你自己补。

插件、自定义工具和 MCP 是另一条要自己把关的进入路径。 文档明确写了自定义工具是在配置里定义、可以执行任意代码的函数,MCP 服务端则是把外部服务接进来的通道。这意味着装一个来源不明的插件或 MCP,等于给一个已经能读你仓库、能跑 shell 的进程再加一段你没审过的代码。要接之前先看它读什么、往哪发,别把「工具多」当成收益本身;websearch 连的 Exa AI 托管 MCP 服务也属于这一类外部依赖,只是它是内置的。

什么场景不适合。 你的日常主要是在 IDE 里做小范围补全和局部重构,那终端形态的收益不明显,装了大概率还是回去用编辑器内联补全;你所在的环境禁止代码出网且没有可用的自托管模型,那它的核心能力用不上;你要的是「一句话生成整个项目然后不看」,那任何这类工具都会让你在两周后付出更大的代价,这个判断跟具体工具无关。终端类 Agent 之间到底该怎么选,可以看终端 Agent 选型

六、上手与避坑清单

每条都写清楚为什么会踩,以及怎么避。

一、先改权限,再干活。 为什么会踩:默认配置里 bashedit 都是允许,第一次跑起来它可能已经改了一批文件、跑了几条命令,你才反应过来。怎么避:进项目第一件事是在 opencode.json 里把 bash 设成对象语法,"*": "ask" 打头,再逐条放行 git *npm * 这类你确认无害的前缀,并把 rm * 显式 deny。记住最后命中的规则生效,通配符放最前面。

二、在干净的工作区里让它动手。 为什么会踩:它的 /undo 是会话级撤销,跟你的分支状态是两套东西;一旦中间夹了手动改动,回退边界就模糊了。怎么避:让它开工前先把工作区提交或暂存,改完先看 diff 再决定要不要留。

三、先 /init 再提问。 为什么会踩:没有 AGENTS.md 的仓库,它只能靠现场搜索猜你的构建命令和目录约定,问一次错一次。怎么避:跑 /init 生成一份,人工补上「跑测试的准确命令」「哪些目录不许动」,然后提交进 Git 让团队共享。改完之后别指望立刻生效——上下文是在下一次模型调用前才重新采样的。

四、复杂改动先切 plan 为什么会踩:直接让它上手实现一个跨模块的需求,它会一边猜一边改,改到一半方向错了,回退成本很高。怎么避:按 Tab 切到 plan,让它先出方案,你改完方案再切回 build 执行。

五、别用一个 Agent 干所有事。 为什么会踩:探索型任务(找文件、读依赖)会塞进大量无关内容,把主会话的上下文撑爆,后面真正干活时反而记不住关键约束。怎么避:把只读的摸底工作交给 explore、把查上游依赖交给 scout,主会话只留结论。子会话之间可以用配置的键位在父子会话间来回切。

六、搜不到文件时先想 ripgrep 的忽略规则。 为什么会踩:grepglob 默认尊重 .gitignore,你让它「看看 dist 里生成了什么」,它会一口咬定没有。怎么避:在项目根加 .ignore 显式放行需要检索的目录。

七、想编程调用就用服务端,别去套壳终端。 为什么会踩:拿脚本去解析 TUI 输出,界面一改你就全线崩。怎么避:起 opencode serve,走它的 HTTP 接口或生成的客户端;要嵌进编辑器就走 opencode acp

八、准备给这个项目提 PR 的话,先读 AGENTS.md 为什么会踩:它的仓库有几条不写在显眼处的硬约束——默认分支是 dev(本地可能压根没有 main 引用);测试不能从仓库根目录跑,有一道叫 do-not-run-tests-from-root 的守卫,得进到 packages/opencode 这类包目录里跑;类型检查要在包目录里用 bun typecheck,别直接敲 tsc。怎么避:动手前把根目录那份 AGENTS.md 从头读一遍,它连分支命名(最多三个词、连字符分隔、不带 feat/ 前缀)和提交信息格式都规定了。

收个尾

把 opencode 放回一句话:它是一个把编码 Agent 拆成「服务端 + 可替换客户端」的开源项目,工具层、权限层、上下文层各自有明确边界,默认配置偏向效率而不是保守,安全边界留给你自己划。

你可以拿这几条自检一下要不要投入时间:你的工作是不是经常需要跨文件、多步骤的改动(是的话终端形态才划算);你的仓库允不允许把代码内容发给模型服务商;你愿不愿意花半小时把权限配置写对,而不是一路点「同意」。三条都过了,再往下走。

接下来建议按这个顺序读仓库:先 packages/web/src/content/docs/permissions.mdx 把权限模型吃透,再 packages/web/src/content/docs/agents.mdx 搞清楚 Agent 与子 Agent 的分工,然后 packages/opencode/src/tool/ 挑几个你天天用的工具看实现,最后如果你在意它长会话为什么还稳,去读根目录的 CONTEXT.md——它把术语、边界条件和「什么时候不做什么」逐条写成了短句,比看代码更快对上它的心智模型。

这个系列的其余文章

这篇是总览。想往下挖,按下面两条线走:先把它用顺手,或者直接读代码

上手与使用

结构与机制

全部文章也汇总在 opencode 开源专题。另一个方向的开源项目——不做编码内核、专做能力分发与共享的那种——见 OpenWork 是什么:把技能与 MCP 打包成能力的开源桌面应用,它甚至把这个项目当引擎接了进去。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。