🟢 入门

OpenCode 怎么用

一个跑在终端里的开源 AI 编程代理:一条命令装上、一次 /connect 接上模型,然后让它替你读代码、改文件、跑测试

📅 更新于 2026-09-13

本文校对于 anomalyco/opencode @ v1.18.30(2026-09-09 发布)· 官方源:github.com/anomalyco/opencode

206,915
GitHub Star(2026-09-12)
401
贡献者(GitHub 计数)
15,717
默认分支提交数
75+
可接的模型提供商

0030 秒速览:三条结论 + 按处境挑动作

读完这一篇,你能做出三个判断:你该用哪条安装路线、第一件事该敲什么、以及在哪一步必须先把闸门关上(因为 OpenCode 默认允许 AI 直接改你的文件,这一步不做,风险是你自己的)。

🔑 先记住三句话(后面全是细节)

① 它不是补全插件,是"会自己动手"的代理——你说一句话,它去读文件、改文件、跑命令,而补全插件只在你敲字时猜下一个词(01)。② 它自己没有智能,智能来自你接的那个模型:OpenCode 是"外壳 + 手脚",模型是"大脑",所以你随时能换脑(09)。③ 默认权限是全开,edit 和 bash 都不问你就执行;进生产项目前先把 bash 设成 "ask"(10)。

按你的处境,直接做这一件

你现在的状态直接做这个为什么是它
还没装,只想先跑起来看看curl -fsSL https://opencode.ai/install | bash官方推荐的一条命令装法,跨平台(03)
macOS 上要"更新最快"brew install anomalyco/tap/opencode官方 tap 比 Homebrew 官方的 formula 更新更勤(03)
公司电脑装不了新东西npm install -g opencode-aiNode 包管理器路线,不依赖系统权限(03)
装完了,卡在"没模型可用"进 TUI 敲 /connect用哪个模型必须先在这里接上(04)
第一次在这个项目里用敲 /init它扫一遍仓库生成 AGENTS.md,之后的对话质量会明显不同(14)
要让它改一个真实文件先用 Tab 切到 Plan,看方案再切回 BuildPlan 模式把"改"这一步关掉了,只出方案(12)
怕它执行破坏性命令配 "permission": {"bash": "ask"}每次跑 shell 命令前都问你一次(10)
它改错了,想回到改之前敲 /undo撤销这一轮对话和它做的文件改动,前提是项目在 Git 里(08)
对话变长、回答开始变笨敲 /compact把长历史压成摘要,省上下文(08)
要把它塞进脚本或 CIopencode run "…"不进交互界面,跑一次就退出(06)
想给队友看刚才这段对话敲 /share生成公开链接(注意:任何拿到链接的人都看得到)(08)

一条可执行的上手路径

1
装上,确认版本(约 1 分钟)

跑 opencode --version。它应该吐出 1.18.30 这样的版本号——吐不出来说明 opencode 不在 PATH 里,见 03 的排错一行。

2
接上一个模型(约 3 分钟)

在任意目录敲 opencode 进界面,输入 /connect,选提供商、粘 API Key。新手可以直接用 OpenCode Zen(官方筛过的模型集合),见 04。

3
在一个你熟悉的项目里走一遍"看 → 计划 → 改"(约 15 分钟)

cd 进项目 → opencode → /init → 问一个只读问题 → Tab 切 Plan 出方案 → Tab 切回 Build 让它改 → /undo 试一次撤销。完整命令见 05。

4
把权限收紧,再长期用(一次性)

在项目根目录建 opencode.json,把 bash 设成 "ask"、把 .env 类文件挡掉。这是唯一一条"不做就可能出事"的步骤,见 10。

📌 读完你应该能

说清"代理"和"补全"差在哪;独立选对安装方式并接上模型;用 Plan / Build 和 /undo 组成一条能反悔的改码流程;并且知道默认权限为什么必须先关小。本文讲的是OpenCode 这个工具本身——它怎么用、怎么配、坑在哪,不含"怎么写提示词让模型更聪明"那类模型侧话题。

01它到底会改我的文件吗

会。这是理解 OpenCode 的第一道分水岭,也是最多人误解的地方——所以先把这句话放在最前面:你说一句"把登录那块的 bug 修了",它真的会去改你的源码文件,不是给你一段建议让你自己粘。

opencode
OpenCode
开源工具 · MIT 许可
官方一句话定义是:一个开源的 AI 编程代理(an open source AI coding agent),提供终端界面、桌面应用和 IDE 扩展三种形态。它接入的是模型提供商——官方说它通过 AI SDK 和 Models.dev 支持 75+ 个 LLM 提供商,也支持跑本地模型。
它凭什么能"自己动手"
  • 工具——它手上有一组能真正操作你项目的动作:读文件、改文件、写新文件、按内容搜代码、按文件名找文件、跑 shell 命令、上网查资料。官方文档把这些叫内置工具(built-in tools),一共十几个。
  • 代理——模型自己决定"现在该用哪个工具、传什么参数",然后看结果、再决定下一步。这个"决定—执行—看结果"的循环就是它和聊天窗口的全部区别。
  • 权限——上面每个动作都能被配置成"直接做 / 问一下 / 不许做"。默认几乎是全放行的,这是 10 要专门讲的事。
💡 一句话对上号

你把它想成一个坐在你旁边、手放在键盘上的同事:你说的话是"任务",不是"提问"。所以"帮我看看这个函数"它能做,"帮我修好这个函数"它也能做——后者会真的落笔。日常工具里最接近的类比是"远程配对编程",不是"更聪明的搜索框"。

它不是哪几样东西

下面这几个"它不是",每一条都对应一个新手真的会踩的误解。看的时候顺便对一下你自己的预期。

你可能以为它是实际上误解为什么会产生
像 Copilot 那样在你敲字时补全它是独立进程,占满一个终端窗口,你按回车它才动;它不看你光标在哪两者都被叫"AI 编程工具",但补全猜的是"下一个词",它接的是"一整件事"
一个"更强的大模型"它自己不含模型。所有推理都发生在你 /connect 接上的那个提供商那边它启动后就要你选模型,很容易以为"选了模型 = 装了模型"
一个聊天窗口它默认能改文件、跑命令,而且默认不问你界面长得像聊天,所以心理上会当成"随便问问没关系"
一个 IDE 专属插件主形态是终端程序;VS Code 那类集成是"你在 IDE 的集成终端里敲 opencode 时顺便装的扩展"官方确实有 IDE 扩展,容易反过来以为它依附于 IDE
一个云服务,代码要上传它是本地程序,在你自己的机器上跑,直接读写你磁盘上的文件要填 API Key 这件事让它看起来像"连了个云服务"

它和最常见的三个近邻差在哪

这一张表不是评测,是"该选哪个"的判断依据。下面每一行的差异点都能在你自己的使用场景里对照出来。

维度OpenCode补全型(GitHub Copilot 那类)IDE 内嵌代理(Cursor 那类)
主界面终端编辑器内联提示编辑器侧栏 / 内嵌聊天
模型选择75+ 提供商,可以换、可以接本地模型基本跟着厂商走主要跟着编辑器厂商给的清单
源码可见性开源,MIT 许可闭源闭源
能不能 SSH 进服务器用能——它就是个终端程序,装在哪就在哪跑不能(要编辑器)不能(要图形界面)
你要自己准备什么一个模型提供商的 API Key(或用它的 Zen)一个订阅一个订阅
最容易后悔的地方默认可写文件可跑命令,得自己收紧权限能用但不深入项目换模型不自由

里面有什么:六个零件

你不需要背这张图,但看一眼能省掉后面一半的困惑——比如"为什么我要登录两次""为什么模型列表在另一个地方"。

你
敲一句话
→
TUI
终端界面
→
Server
本地服务
→
Agent
决定做什么
→
Tools
真去动手
→
LLM
提供商那边的模型
零件用大白话说是干什么的你什么时候会直接碰到它
TUI"终端用户界面"的缩写,就是你会看到的那个全屏窗口:上面是消息流,下面是输入框每次敲 opencode 进入的就是它
Server本地跑着的一个服务,管会话状态、排队请求你想从浏览器用(opencode web)或从别的终端接上去(opencode attach)时
Agent(代理)一套"用哪个模型、能用哪些工具、提示词是什么"的组合,不是模型本身按 Tab 切换主代理时,就是在换 Agent
Tools(工具)真正落手落脚的十几个动作:读、改、写、搜、跑命令……你在配置里写 "permission": {"bash": "ask"} 时,改的就是某个工具
Model(模型)真正做"思考"的那个大语言模型,跑在提供商那边用 /models 换模型时
Provider(提供商)模型的服务方,比如 Anthropic、OpenAI、OpenCode Zen,或者你本机的 Ollama用 /connect 添 API Key 时
📖 一个容易踩的推论

因为 Server 是个独立进程,所以你在终端里敲 opencode serve 起一个后端,再用 opencode attach http://… 从另一台机器接上 TUI,是官方支持的用法——这意味着你可以把"跑模型请求的那台机器"和"你敲键盘的那台机器"分开。

02为什么不全用现成的工具

官方的仓库描述只有一句:The open source coding agent.(开源的编程代理)。它刻意把自己定位在"开源"和"代理"这两个字上,所以它的价值主张也得从这两处读。

它解决的是四类具体问题,不是"更好用"

你碰到的麻烦换成 OpenCode 之后变成什么样这条的代价(公平地说)
想试新模型,但工具只认一家换 model 一行配置,或 /models 选一下,就能切到另一家的模型模型换来换去,同一个提示词的效果差异要你自己重新摸
想知道工具到底把什么发给了谁源码公开(MIT 许可),可以自己读、自己改、自己编译读源码是额外成本;自己改就得自己维护
主力开发在远程服务器上,本机只有终端它就是终端程序,SSH 进去装一个就能用没有图形界面时,图片类输入、可视化 diff 的体验会打折
成本想自己控制可以按任务分模型:简单的活给小模型,难的活给大模型(配置里的 small_model 就是干这个的)分模型要花心思,配错了只是变慢或变贵,不会报错
❌ 把"开源免费"理解成"用起来不花钱"

OpenCode 本身确实免费、MIT 许可。但模型调用是要花钱的——除非你用本机跑的本地模型,或者用某个订阅额度(比如 GitHub Copilot 账号、ChatGPT Plus/Pro 账号的额度)。

最常见的翻车:装完接上一个大模型,一晚上让它读了整个 monorepo,第二天收到账单。

✅ 正确的预期

把 OpenCode 当成"一套免费的手脚",把模型当成"按量计费的大脑"。省钱的做法:日常问答用便宜模型,难任务临时切贵模型;长对话及时 /compact 或干脆 /new 开新的。

想完全不花钱:接本机的 Ollama / LM Studio 这类本地模型服务。

决定要不要用它,问自己三句话

03装哪一条:六种安装方式怎么选

OpenCode 的安装方式多到有点烦,但它们的差别其实只有两点:谁帮你管更新、你的机器上已经有什么。先看表选一条,再往下抄命令。

先看这张表决定用哪个包管理器

方式什么时候选它自动更新别在什么时候用
官方安装脚本什么都不知道,只想先跑起来会(启动时自动升级)公司机器不允许 curl | bash 时
Homebrew(官方 tap)macOS / Linux 上要最新版用 brew upgrade 自己管不想装 Homebrew 时
npm / bun / pnpm / yarn机器上已经有 Node 生态,或者装不了系统级包用包管理器自己管Node 版本太老时(先升级 Node)
Arch Linux pacman你在 Arch 上,只要稳定版随系统更新想第一时间拿到新功能时(换 AUR 的 opencode-bin)
Windows Scoop / Chocolatey你在 Windows 上,不想开 WSL用包管理器自己管想体验完整功能时——官方明确推荐 WSL
Docker / Mise要放进容器,或已经用 Mise 统一管工具版本自己管想直接用本机项目文件时(容器要自己挂目录)
⚠️ Windows 用户先看这一条

官方文档的第一句建议就是:Windows 上推荐用 WSL(Windows Subsystem for Linux,可以理解成"在 Windows 里开一个真正的 Linux")。理由是性能和功能兼容性更好。opencode web 的文档里还额外提了一句:Windows 上请从 WSL 里跑,别从 PowerShell 里跑,否则文件系统访问和终端集成会出问题。

把命令抄走

官方推荐的是安装脚本这一条:

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

不想用脚本,就用包管理器。下面这些命令按平台分组,只抄你需要的那一行:

# Node 生态(npm / bun / pnpm / yarn,四选一)
npm install -g opencode-ai
bun install -g opencode-ai
pnpm install -g opencode-ai
yarn global add opencode-ai

# Homebrew(macOS / Linux,官方 tap,更新最快)
brew install anomalyco/tap/opencode

# Arch Linux:稳定版 / AUR 最新版
sudo pacman -S opencode
paru -S opencode-bin

# Windows:Scoop / Chocolatey / NPM
scoop install opencode
choco install opencode
npm install -g opencode-ai

# Mise(统一管版本的工具)
mise use -g github:anomalyco/opencode

# Docker(一次性跑,用完即走)
docker run -it --rm ghcr.io/anomalyco/opencode
💡 装完先验一件事

跑 opencode --version,应该吐出 1.18.30 这样的版本号。如果提示找不到命令,说明安装目录不在 PATH 里:用 Homebrew 装的话通常是 /opt/homebrew/bin(Apple 芯片)或 /usr/local/bin;用 npm 装的话是 npm bin -g 给出的目录。把它加进 PATH 后重开终端。

装完想升级、想卸掉

# 升到最新版
opencode upgrade

# 升到指定版本(注意官方文档里的示例写的是 v0.1.48 这种老版本号,格式一致)
opencode upgrade v0.1.48

# 指定安装方式来升级:curl / npm / pnpm / bun / brew
opencode upgrade --method brew

# 卸载:先看不删什么(--dry-run 只打印要删哪些东西)
opencode uninstall --dry-run

# 真的卸:保留配置、保留会话数据与快照、不再问确认
opencode uninstall --keep-config --keep-data --force

它把东西都放在哪

出问题时你基本只需要翻这三个位置,所以值得记一下:

路径里面是什么什么时候要动它
~/.local/share/opencode/auth.json你 /connect 或 opencode auth login 存进去的 API Key想确认自己到底接了哪几家(或想手动清理)时
~/.config/opencode/opencode.json你的全局配置:默认模型、权限、提供商想让"所有项目都默认把 bash 设成 ask"时
.opencode/(在你项目里)这个项目专属的东西:agents、commands、plugins、skills、tools、themes想给团队共享一个自定义命令时

桌面应用(Beta):不想用终端的人

官方除了终端界面,也提供了桌面版。可以从下载页取安装包,也可以走包管理器:

# macOS(Homebrew cask)
brew install --cask opencode-desktop

# Windows(Scoop,注意要先进 extras 这个 bucket)
scoop bucket add extras; scoop install extras/opencode-desktop

安装包的下载页是 opencode.ai/download,提供 macOS、Windows、Linux 三个平台。桌面版目前官方标着 Beta,所以本文讲的配置与命令都以终端版为基准,桌面版的界面差异请以它自己的文档为准。

让 /editor 和 /export 用你惯用的编辑器

这两个命令都会去读 EDITOR 这个环境变量。不设它的话,打开的可能是一个你不想用的默认编辑器。

# 设置编辑器
export EDITOR="code --wait"   # VS Code
export EDITOR="cursor --wait" # Cursor
export EDITOR=nvim            # Neovim

# 想永久生效,把上面那行加进 shell 配置:~/.bashrc、~/.zshrc 等

# Windows 上不一样:CMD 用 set,PowerShell 用 $env:
set EDITOR=notepad
set EDITOR=code --wait
$env:EDITOR = "notepad"
$env:EDITOR = "code --wait"
⚠️ 图形界面编辑器基本都要加 --wait

官方专门注明了这一条:像 VS Code 这类编辑器必须带 --wait。原因是它的启动方式默认是"把窗口打开就立刻返回"——不加 --wait,OpenCode 会以为你已经编辑完了。--wait 的作用就是让它一直阻塞到你关掉编辑器为止。可以在候选清单里挑:code、cursor、windsurf、nvim、vim、nano、notepad、subl。

04先接上一个模型

装完 OpenCode 之后,它还不能用——因为它自己没有模型。这一步做错或跳过,后面所有命令都会卡住。整个流程就三步。

三条命令之外没有别的坑

1
在任意目录启动

输入 opencode 回车,进入全屏界面。

2
敲 /connect

它会列出所有可选的提供商,让你选一个。

3
把 API Key 粘进去

去提供商的网站上创建一个 Key,复制,粘到弹出来的输入框里,回车。

不想进界面也能做同样的事——命令行里也有一条:

# 交互式登录某个提供商(会问你要哪种登录方式、然后要 Key)
opencode auth login

# 直接指定提供商和登录方式,跳过两次选择
opencode auth login --provider anthropic --method api-key

# 看看现在已经接了哪些(这个命令不需要进界面)
opencode auth list
opencode auth ls

# 退掉某一家
opencode auth logout
📖 用支付宝式的一句话解释"什么是提供商"

提供商(provider)就是卖"模型的调用能力"的那家服务商。模型是货,提供商是店家,API Key 是你在这家店的会员卡。同一件"货"(比如某个 Claude 模型)可能在好几家店都有卖,价格和速度还不一样。这就是为什么 OpenCode 让你先选"店家"再选"货"——两件事。

不想折腾选模型,就用官方筛过的那一套

官方给新手的建议很直接:如果不知道选哪个模型,用 OpenCode Zen。它是 OpenCode 团队自己测过的模型集合,官方原话是"a curated list of models that have been tested and verified by the OpenCode team"(一份经过团队测试与验证的精选模型清单)。做法是:

# 1. 在 TUI 里敲 /connect
/connect

# 2. 在提供商列表里选 opencode

# 3. 浏览器打开下面这个地址,注册、绑支付方式、复制 API Key
#    https://opencode.ai/auth

# 4. 把 Key 粘回 TUI

# 5. 接完敲 /models,官方推荐的模型就在列表里
/models
模型入口适合谁钱怎么算别当什么用
OpenCode Zen新手、不想研究模型差异的人按请求计费,自己充额度别当成"免费额度"——它是付费网关,只是帮你选好了模型
自己的提供商 Key已经有某家订阅或 Key 的人照那家的价目表别在一个项目里同时挂好几家 Key,换模型时容易选错
GitHub Copilot 账号已经有 Copilot 订阅的人用订阅里的额度别以为能拿到 Copilot 的全部功能——你只是借用它的模型额度
ChatGPT Plus / Pro 账号已经有 OpenAI 订阅的人用订阅额度同上,是额度不是功能
本地模型(Ollama / LM Studio)不想花钱、或代码不能出门的人只花自己的电费和显卡别指望本地小模型能扛住"重构整个模块"这种活
⚠️ 接不上时的三个常见原因

① Key 粘错了:复制时带了前后空格是高频问题,粘完看一遍开头结尾。② 环境变量和 auth.json 打架:如果你既设了 ANTHROPIC_API_KEY 这类环境变量、又在 /connect 里存了 Key,两边不一致时会让人怀疑人生。③ 企业代理:公司网络要走代理时,得在提供商配置里改 baseURL,见 13。

把"接了哪几家"和"有哪些模型"查清楚

# 命令行里列出所有提供商提供、且你已配置的模型(格式是 provider/model)
opencode models

# 只看看 anthropic 家的
opencode models anthropic

# 模型清单是缓存的,刚上新模型时手动刷一下
opencode models --refresh

# 想看带价格、上下文长度这类元数据的版本
opencode models --verbose

输出里的 provider/model-id 就是你在配置里该写的那串字。举个例子:如果你用的是 Zen,想看 GPT 5.1 Codex,写的就是 opencode/gpt-5.1-codex 这个格式——斜杠前面是店家,后面是具体那个模型。

05最小例子:十分钟走完一遍

下面这一段是一条从头到尾能照着敲的路径:从一个真实项目到让 AI 改一个真实文件,最后再安全地撤回来。全流程只需要一个终端窗口。

第一步:进入项目并启动

cd /path/to/your/project
opencode

第二步:让它先读懂这个项目

/init

/init 会扫描仓库里的重要文件,必要时问你一两个它自己答不上来的问题,然后生成(或就地改进)一份 AGENTS.md。它重点记的是:构建 / 检查 / 测试命令、命令的执行顺序、从文件名看不出来的架构、项目特有的约定。

💡 这一步为什么不能跳

没有 AGENTS.md 时,它每次都要靠猜你的项目怎么跑测试、代码放在哪。官方建议把它提交进 Git——这样团队里每个人、每次会话的起点都一样。如果你是从 Claude Code 迁过来的,它连 CLAUDE.md 也认(见 14)。

第三步:先问一个只读的问题

用 @ 引用文件是它最基本的动作。@ 会触发一次项目内的模糊搜索(你打几个字母它就把候选文件名列出来):

给我这个项目的代码结构做一个快速总结
How is authentication handled in @src/auth.ts

文件内容会被自动读进对话里。所以问"这个函数做什么"这类问题,它答得比你自己翻文件快。

第四步:让它跑一次命令给你看

消息以 ! 开头,就表示"这条不是给模型的话,是要执行的 shell 命令",输出会作为工具结果进入对话:

!git status
# 输出会被加入对话上下文,AI 能看到命令结果

更实用的写法是命令加问题一起来:

!git log --oneline -10
最近这 10 个提交里,哪个最可能跟"登录后偶发 500"有关?

第五步:要改代码,先切 Plan

按 Tab 或 Shift+Tab 在主代理之间切换(默认的两个是 Build 和 Plan,右下角会显示当前是哪个)。Plan 模式下"改文件"和"跑命令"默认都要问你,所以它只会给你方案:

# 1. 按 Tab 切到 Plan 模式
当用户删除笔记时,我们需要在数据库中标记为已删除。
然后创建一个页面显示最近删除的笔记,
用户可以从这个页面恢复或永久删除笔记。

# 2. AI 给出实现方案
# 3. 觉得可以,按 Tab 切回 Build 模式
看起来不错,开始实现吧。

第六步:撤回来看看

这一步强烈建议现在就试一次——知道"能撤"之后,你才敢放手让它改:

/undo
# 它会撤掉最近这条消息、以及它引起的所有文件和代码改动
# 然后把你刚才那句话重新显示出来,方便你改一改再发一次

/redo
# 反悔了:重做刚才撤销掉的那一批改动
⚠️ /undo 有一个硬前提

官方原文:Internally, this uses Git to manage the file changes. So your project needs to be a Git repository.(内部通过 Git 管理文件改动,所以你的项目必须是一个 Git 仓库。)目录里没有 .git,这两个命令就不工作。好消息是它用的是自己的内部快照机制,不需要你先把改动提交过。

第七步:长对话了把它压一压

/compact
# 把当前这一段长历史压成摘要,接着聊(别名 /summarize)

/new
# 或者干脆开一段新会话(别名 /clear)——任务换了一个主题时更推荐这个

完整的一套照抄版

如果你只想复制一整段,从装到撤回是这样的:

# 装(一次)
curl -fsSL https://opencode.ai/install | bash
opencode --version

# 接模型(一次):进界面敲 /connect 并粘 Key
opencode

# 在项目里干活
cd /path/to/your/project
opencode

# 在 TUI 里依次敲:
#   /init                    生成 AGENTS.md
#   这个项目的入口在哪?     先问只读问题
#   !git status              让它看看工作区状态
#   Tab                      切到 Plan 出方案
#   Tab                      切回 Build 执行
#   /undo                    不满意就撤回
#   /exit                    走人(别名 /quit、/q)
📖 拖一张图进去也行

把设计稿、报错截图直接拖到终端窗口里,它会当成图片输入读进去。官方文档里就是用这一招收"照着这张设计图做这个页面"这种需求(原文:Drag and drop images into the terminal to add them to the prompt.)。Plan 模式迭代方案时特别有用:参考这张图改一下布局 [图片]。

06终端界面长什么样

OpenCode 的主界面就是一个「终端里的应用」。它复用了你终端的一部分能力(滚动、选中),又接管了一部分(键盘输入)。知道哪块归谁管,能省掉一次「我打了个字怎么没反应」的困惑。

两种启动方式

# 在当前目录启动
opencode

# 指定项目目录启动(不 cd 也能直接开)
opencode /path/to/project

四块区域,各管一件事

位置上面有什么你什么时候会看它
顶部当前模型、当前代理名、这一段会话的信息怀疑「它是不是换了个小模型在答我」时
中部对话消息流:你说的话、它的回复、它调用的每一次工具及其结果想看它到底跑了什么命令、改了哪些文件时
底部输入框和快捷键提示每次打字都在这里
右下角当前代理模式的指示器按 Tab 之后确认「切成功了吗」时

输入框里几个键,先认清它们

键作用新手最容易混的地方
Enter发送想换行时别按它——按它就直接发出去了
Shift+Enter(或 Ctrl+Enter / Alt+Enter / Ctrl+J)在消息里换行不同终端支持不一样,四个里总有一个能用
Tab / Shift+Tab在主代理之间正向 / 反向切换它切的是代理不是模型;换模型用 /models
Ctrl+P打开命令面板,能搜到所有可用命令和设置项记不住斜杠命令名时靠它
Esc打断它正在做的事它不是「退出程序」,是「停下当前这一轮」
Ctrl+X默认的前缀键,单独按没反应,要再按一个字母Ctrl+X 然后 u 才是撤销
Ctrl+Z把界面挂起、暂时回到 shell想跑一条本机命令又不想退出会话时用
📖 什么是「前缀键 / leader key」

有些终端程序会把某个组合键设成「开场白」:先按它,松手,再按一个字母,两个键合起来才算一条快捷键。OpenCode 默认的前缀键是 Ctrl+X,官方文档里写成 <leader>。所以你看到 <leader>u,意思就是「按 Ctrl+X,松手,再按 u」。默认它等你 2000 毫秒(2 秒)看你还按不按第二个键,这个时间可以配。

把界面调成你顺手的样子

界面相关的东西放在另一个文件里:tui.json(或带注释的 tui.jsonc)。它和管运行行为的 opencode.json 是分开的两份,可以放全局的 ~/.config/opencode/tui.json,也可以放项目里。

{
  "$schema": "https://opencode.ai/tui.json",
  "theme": "opencode",
  "leader_timeout": 2000,
  "keybinds": {
    "leader": "ctrl+x",
    "command_list": "ctrl+p"
  },
  "scroll_speed": 3,
  "scroll_acceleration": {
    "enabled": false
  },
  "diff_style": "auto",
  "cursor": {
    "style": "block",
    "blinking": true
  },
  "mouse": true
}
配置项它改的是什么什么时候该动它 · 别踩哪里
theme配色主题的名字终端背景不是纯黑、默认主题刺眼时改;旧文档里写过 TUI 配置能放在 opencode.json 的 tui 键下,现在那份已标记为过时并会自动迁移,新写法是独立文件
keybinds键位映射,会和内置默认值合并习惯的前缀键不是 Ctrl+X 时改;只写你要改的那几条就够
leader_timeout按完前缀键后等多久算「你放弃了」,单位毫秒,默认 2000手慢、常按不出快捷键时调大
scroll_speed滚动多快,默认 3,可写小数(最小 0.001)觉得一次滚太多时调小
scroll_acceleration.enabled开启「滚得越快、滚得越远」的手感开着它的时候,scroll_speed 会被忽略——两个别同时配
diff_style"auto" 跟终端宽度自适应,"stacked" 强制单列代码改动对比在窄窗口被压扁时改 stacked
cursor输入框光标的样子与是否闪烁光标和背景同色、看不见时改
mouse是否接管鼠标,默认 true想用终端原生的「选中复制、滚轮翻页」时设 false
attention.enabled桌面通知与提示音,默认关任务跑完时你在看别的窗口,想被叫回来才开
💡 两个能立刻改善体验的小动作

① 按 Ctrl+P 打开命令面板,搜 "username" 可以把消息前面那个用户名显示关掉——这个开关会自己记住,下次进来还是关的。② 界面的配色直接在 tui.json 里改 theme;想先看看有哪些主题,用命令面板搜主题相关的项,比手写配置快。

三样东西跑在 TUI 之外,但你要知道它们在

# 浏览器界面:起一个本地服务并自动打开浏览器
opencode web
opencode web --port 4096

# 让局域网里别人也能连(注意:同时必须设访问密码,否则等于裸奔)
opencode web --hostname 0.0.0.0
OPENCODE_SERVER_PASSWORD=secret opencode web

# 只起后端、不给界面(给别的客户端用)
opencode serve

# 一台机器起后端,另一台机器把 TUI 接上去
opencode web --port 4096 --hostname 0.0.0.0
opencode attach http://10.20.30.40:4096
⚠️ 加 --hostname 0.0.0.0 之前先加密码

官方在 opencode web 的文档里明确写了:If OPENCODE_SERVER_PASSWORD is not set, the server will be unsecured.(没设密码,服务就是不设防的。)本机自己用没问题,但一旦绑到 0.0.0.0(意思是「这台机器的所有网卡都能连」),同一个 Wi-Fi 下的人就能操作你的项目。正确姿势是 OPENCODE_SERVER_PASSWORD=你的密码 opencode web --hostname 0.0.0.0,用户名默认是 opencode。想换用户名就设 OPENCODE_SERVER_USERNAME。

VS Code 里的扩展是怎么装上的

这里要纠正一个很常见的误解:你不需要先去装扩展。官方给的做法是——打开 VS Code,打开集成终端,在里面敲 opencode,扩展会自己装上。

# 在 VS Code / Cursor / Windsurf / VSCodium 的集成终端里敲:
opencode
# 之后扩展自动安装。装不上时按下面的三步查。
📖 扩展装不上时的三步检查

① 确认你是在集成终端里敲的 opencode,不是系统终端;② 确认 IDE 的命令行工具装了——VS Code 是 code、Cursor 是 cursor、Windsurf 是 windsurf、VSCodium 是 codium;没装的话在 IDE 里按 Cmd+Shift+P(Mac)或 Ctrl+Shift+P,搜 "Shell Command: Install 'code' command in PATH";③ 确认 IDE 有安装扩展的权限。

07第一次进项目先敲什么

上面那十分钟已经覆盖了主干。这一节补的是"能跑通之后,第一周真正会反复用的东西"——尤其是当你一次想干几件事的时候。

并行干活:同一份代码,几条会话同时开

每次 /new 都是一段独立会话。这带来一个很实用的用法:让一段会话去研究、另一段去实现,互不干扰。

# 会话 1:让它研究"认证是怎么做的"
# 会话 2:让它改一个完全无关的小 bug
# 用 /sessions 在它们之间来回切(别名 /resume、/continue)
/sessions

# 或者直接用命令行起一段新会话
opencode --continue              # 接着上一次
opencode --session <session-id> # 接指定的那一段
opencode --fork                  # 在续接时岔出一支,不污染原来那条线

不进交互界面也能问一句

这是它最被低估的一条能力——opencode run 把整个代理塞进一条命令里,跑完就退出:

opencode run "Explain how closures work in JavaScript"

# 挂到一个已经跑着的后端上,省掉每次冷启动 MCP 服务器的等待
opencode serve
opencode run --attach http://localhost:4096 "Explain async/await in JavaScript"

# 让它把结果按 JSON 吐出来,方便脚本解析
opencode run --format json "列出这个仓库里所有的 TODO 注释"

# 自动批准没有被显式禁止的权限(CI 里用,见 08)
opencode run --auto "Refactor this module"

对团队:分享、导出、交接

# 生成一个链接并复制到剪贴板
/share

# 取消分享
/unshare

# 导出成 Markdown,用你的默认编辑器打开
/export

# 命令行里:导出某段会话为 JSON(不给 id 会让你选)
opencode export
opencode export --sanitize   # 抹掉敏感内容再导出

# 把别人给你的会话 JSON 导进来(也支持分享链接)
opencode import session.json
opencode import https://opncd.ai/s/abc123
🚨 /share 之前先想两秒

官方原文写得很直白:Shared conversations are publicly accessible to anyone with the link.(分享出去的对话,任何拿到链接的人都能看。)分享时它会把你这段对话历史同步到官方服务器上,并给你一个 opncd.ai/s/<id> 形式的公开地址。所以分享前先确认这段对话里没有密钥、没有客户数据、没有内部地址。三种分享模式的开关在 13。

训练自己的肌肉记忆:五条就够

第一遍:只读

只用 @文件 提问和 !命令,不让它改任何东西。目标是建立"它读得懂我的项目"的信任感。

第二遍:让它只改一个文件

挑一个你有把握的小改动,走 Plan → Build。做完立刻 !git diff 看一眼它到底改了什么——这个习惯能省掉很多惊吓。

第三遍:引入 /undo

故意让它改一个你不想要的方向,然后用 /undo 拉回来。目的是把"改错不可怕"变成本能。

第四遍:配置权限

建 opencode.json,把 bash 设成 "ask"。之后正常干活一天,感受一下"问得太勤"还是"刚刚好"。

第五遍:写一个自己的命令

把你每天重复说的一段话(比如"跑测试、只看失败的、给修复建议")做成 .opencode/commands/test.md,以后敲 /test 就行。模板见 13。

08斜杠命令与快捷键

在界面里敲 /,候选列表就出来了。这些叫斜杠命令——它们是"你控制这个工具"的开关,不是发给模型的提示词。下面按"你什么时候需要"分两张表。

十七个斜杠命令,一次列全

第三列是这套清单里哪一条会咬人,赶时间的话只看它。

命令它做什么什么时候用 · 别踩哪里
/connect添加模型提供商、填 API Key装完第一件事;接错了模型会一直报「没有可用模型」
/init引导式创建或更新 AGENTS.md第一次进项目必做;已有 AGENTS.md 时是就地改进,不是覆盖
/models列出可用模型换模型;它切的是模型,和 Tab 切的代理是两件事
/new开一段新会话,别名 /clear换主题时用;快捷键 ctrl+x n
/sessions列出并切换会话,别名 /resume、/continue同时在跑几条线时回来找;快捷键 ctrl+x l
/undo撤销最近一条消息,以及它引起的全部文件改动改错了撤回来。项目必须在 Git 仓库里;快捷键 ctrl+x u
/redo重做上一次撤销掉的东西只有 /undo 之后才可用;快捷键 ctrl+x r
/compact把当前会话压成摘要,别名 /summarize对话太长、回答开始变笨时;快捷键 ctrl+x c
/share分享当前会话,生成链接并复制到剪贴板给队友看。任何拿到链接的人都能看,先确认没有密钥
/unshare取消分享发现分享错了时的补救
/export把会话导成 Markdown,用你的默认编辑器打开要归档、要贴进文档时;快捷键 ctrl+x x,用的是 EDITOR 环境变量
/editor打开外部编辑器来写这条消息要写一大段需求、终端里敲着难受时;快捷键 ctrl+x e
/themes列出可用主题换配色;快捷键 ctrl+x t
/thinking显示 / 隐藏模型思考过程那一段只是显示开关,不会让模型开始或停止推理;要真的切推理档位用 ctrl+t
/details切换工具执行详情(它跑了什么、输出什么)排查「它刚才到底干了什么」时
/help弹出帮助对话框记不住时
/exit退出,别名 /quit、/q走人;快捷键 ctrl+x q
⚠️ /undo 的前提,值得单独说一遍

官方原文:Internally, this uses Git to manage the file changes. So your project needs to be a Git repository.(内部用 Git 管文件改动,所以项目必须是 Git 仓库。)没有 .git 目录,/undo 和 /redo 都不工作。可以连续执行多次 /undo 往回退多步;每退一步,会把文件恢复到那条消息之前的状态。

没有斜杠版本的那些快捷键

下面这些只在键盘上。默认的前缀键是 Ctrl+X(表里写成 <leader>)。

快捷键作用记住它的理由
Tab / Shift+Tab正向 / 反向轮换主代理Plan 和 Build 的切换就靠它,这是最该形成肌肉记忆的一个
Ctrl+P打开命令面板所有命令和设置项都能搜到,等于一张活的速查表
<leader>u / <leader>r撤销 / 重做和 /undo、/redo 等价,手不用离开键盘
<leader>e打开外部编辑器写消息长需求的效率差很多
<leader>x导出会话归档时用
<leader>n / <leader>l新会话 / 会话列表管多条并行会话
<leader>t / <leader>m / <leader>a主题列表 / 模型列表 / 代理列表三张「选一个」的清单,比记斜杠命令更统一
<leader>b / <leader>s开关侧边栏 / 查看状态窄窗口下腾地方
<leader>y复制最后一条消息要把它的回答贴到别处时
<leader>g看会话时间线长会话里回跳到某个节点
Ctrl+T轮换模型变体(官方叫 variant,用来选推理强度这类档位)和 /thinking 不是一回事:它改的是「用哪个档位」,不是「显不显示」
F2 / Shift+F2在最近用过的模型之间正 / 反向切两个模型来回对比时最省事
<leader>↓进入第一个子会话子代理干的活单独开会话,这是进去看它干了什么的路
← / → / ↑(在子会话里)子会话之间前后切换 / 回到父会话看完子代理的活要回到主线
Esc打断当前这一轮发现它走错方向时立刻停,不是退出程序
Ctrl+C / Ctrl+V / Ctrl+Z清空输入框 / 粘贴 / 把界面挂起回 shell注意 Ctrl+C 在输入框里是「清空」不是「退出」
📖 键位可以整套改

上面这些名字(messages_undo、session_list、model_list……)就是 tui.json 里 keybinds 的键名。想改成什么就写什么,比如 {"keybinds": {"leader": "ctrl+space"}}。没写的那些还按默认值走,所以不用把几十条全抄一遍。

把你每天重复说的话做成一条命令

斜杠命令列表里还可以有你自己的东西。做法有两种,先看 Markdown 文件那种——它最直观:

# 建这个文件(项目级)或 ~/.config/opencode/commands/test.md(全局级)
# .opencode/commands/test.md
---
description: Run tests with coverage
agent: build
model: anthropic/claude-3-5-sonnet-20241022
---
Run the full test suite with coverage report and show any failures.
Focus on the failing tests and suggest fixes.

文件名 test.md 就成了命令名 test,敲 /test 就发出去。不想用文件,也可以全写在配置里:

{
  "$schema": "https://opencode.ai/config.json",
  "command": {
    "test": {
      "template": "Run the full test suite with coverage report and show any failures.\nFocus on the failing tests and suggest fixes.",
      "description": "Run tests with coverage",
      "agent": "build",
      "model": "anthropic/claude-haiku-4-5"
    },
    "component": {
      "template": "Create a new React component named $ARGUMENTS with TypeScript support.\nInclude proper typing and basic structure.",
      "description": "Create a new component"
    }
  }
}

自定义命令里能塞三种动态内容

这是把"重复劳动"真正消掉的地方。三种写法可以混着用。

# 1. 参数占位:$ARGUMENTS 收全部参数,$1 $2 $3 收第几个
# .opencode/commands/component.md
---
description: Create a new component
---
Create a new React component named $ARGUMENTS with TypeScript support.
Include proper typing and basic structure.

# 用起来:/component Button  →  $ARGUMENTS 被换成 Button

# .opencode/commands/create-file.md
---
description: Create a new file with content
---
Create a file named $1 in the directory $2
with the following content: $3

# 用起来:/create-file config.json src "{ \"key\": \"value\" }"
#   →  $1 = config.json,$2 = src,$3 = { "key": "value" }

# 2. 把命令输出塞进提示词:用 !`命令` 这个写法
# .opencode/commands/analyze-coverage.md
---
description: Analyze test coverage
---
Here are the current test results:
!`npm test`
Based on these results, suggest improvements to increase coverage.

# .opencode/commands/review-changes.md
---
description: Review recent changes
---
Recent git commits:
!`git log --oneline -10`
Review these changes and suggest any improvements.

# 3. 引用文件:还是用 @
# .opencode/commands/review-component.md
---
description: Review component
---
Review the component in @src/components/Button.tsx.
Check for performance issues and suggest improvements.
💡 这三条写法的一次分工

命令在你项目的根目录执行,输出会直接变成提示词的一部分。规律很简单:要变化的字用 $ARGUMENTS;要先跑一遍命令看当下状态用 !`…`;要固定看某几个文件用 @路径。这三样凑起来,「每天开工先看一遍 CI 状态并总结」这种活就能压成一条 /开工。

09模型、提供商和 Agent 是三件事

这是最容易混成一团的一组词,而且混了之后所有配置都写不对。一句话先分开:提供商是店家,模型是货,Agent 是"用哪件货、配哪些工具、说什么话"的一个组合。

用一张收货单理解这三层

概念大白话在配置里长什么样换它意味着什么
提供商(provider)卖模型调用服务的那家店,比如 Anthropic、OpenAI、OpenCode Zen,或者你本机的 Ollama"provider": {"anthropic": {…}}换的是「去谁家买」,通常要重新填 Key、计费也跟着换
模型(model)货本身,比如某个 Claude、某个 GPT"model": "anthropic/claude-sonnet-4-5"——斜杠前是店家,后面是货换的是「用哪个脑子」,能力和价格都变
Agent(代理)一套预设:用哪个模型、允许哪些工具、系统提示词是什么"agent": {"build": {"model": "…", "permission": {…}}}换的是「以什么身份、带着什么权限干活」

官方对 small_model 的解释正好说明这三层是可以拆开配的:它专门给"起标题"这类小事配一个便宜模型,默认行为是"能从你的提供商那里找到更便宜的模型就用它,找不到就退回主模型"。

# 把主模型和"干杂活的模型"分开
{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-5",
  "small_model": "anthropic/claude-haiku-4-5"
}

同一家店还能调什么

调完店、调完货,还有一层"这家店怎么联系"的参数。它们在 provider.<名字>.options 里:

参数它管什么默认值 / 什么时候动它
timeout整个请求最多等多久(毫秒)默认 300000(5 分钟);设成 false 表示不限时
headerTimeout等响应头最多等多久;一旦头到了它就不再计时,不限制后面的流式内容默认 300000;服务商「先不回话、慢慢吐字」时别指望它兜底
chunkTimeout两个流式片段之间最多隔多久,超了就中断请求默认 300000;网络抖就断的场合可以调大
setCacheKey给指定的提供商固定设一个缓存键默认不带;配合某些提供商的提示词缓存时用
baseURL换掉这家店的接口地址走公司代理、或用兼容接口的自建服务时用
apiKey这一家的密钥一般用 {env:…} 引环境变量,别写死在文件里
blacklist / whitelist从模型选择列表里藏掉 / 只保留某些模型店里有一堆你永远不用的模型、每次翻列表很烦时用
# 一家店的常见调法:超时、缓存键、换接口地址、藏掉不用的模型
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "anthropic": {
      "options": {
        "timeout": 600000,
        "chunkTimeout": 30000,
        "setCacheKey": true,
        "apiKey": "{env:ANTHROPIC_API_KEY}"
      },
      "blacklist": ["claude-opus-4-20250514"]
    }
  }
}

不想让某个提供商被自动加载

有时候你机器上有某个 Key,但你就是不想让这次的会话用它——比如公司要求只走指定的店。两个配置项管这件事:

# 明确禁掉几家(优先级更高)
{
  "disabled_providers": ["openai", "gemini"]
}

# 或者反过来:只允许这几家,其余全不加载
{
  "enabled_providers": ["anthropic", "openai"]
}
📖 哪一个说了算

官方写明:disabled_providers 的优先级高于 enabled_providers,而且这是为了向后兼容特意保留的行为。所以同一家店同时出现在两个列表里时,它是被禁用的。被禁用的店有三重后果:即使环境变量里有 Key 也不加载、即使 /connect 里存过 Key 也不加载、它的模型也不会出现在模型选择列表里。

不确定该用哪个模型时

官方给的答案就是 OpenCode Zen,理由写在它自己的文档里:There are a large number of models out there but only a few of these models work well as coding agents.(模型很多,但真正适合当编程代理的只有少数。)而且同一件货在不同店家那里的表现也不一样,所以官方做了三件事:测了一批模型并与模型团队沟通怎么跑最好、和几家提供商一起确保服务方式正确、最后对"模型 + 提供商"这个组合做实测打分,得出一份可推荐的清单。

💡 什么时候"换模型"真的有用

三种情况值得换:① 它反复理解错你的项目约定——换一个更强的;② 它在做机械劳动(改名、加日志)烧钱太快——换一个便宜的;③ 它不支持你要的推理档位——换 Ctrl+T 切变体,或换模型。反过来,"它答得不好"里只有一部分是模型问题,还有很大一部分是上下文没给够(见 17 的成对示例)。

10别让它乱改:权限与自动模式

这是全文最该认真读的一节。官方在配置文档里写得很明白:By default, opencode allows all operations without requiring explicit approval.(默认情况下,OpenCode 允许所有操作,不需要明确批准。)也就是说——它一装上就是"什么都不问"的状态。不改它,你的第一周就是拿真实项目试手。

🚨 默认状态的准确含义

不是"它只会读",而是"它读写都能做、命令也能跑,而且不问你"。默认只有两类事情会来问你:碰到项目目录以外的路径(external_directory),以及同一个工具用完全相同的输入连着调了 3 次(doom_loop,官方把它叫「代理看起来卡住了」的救援提示)。读文件默认也是放行的,唯一的例外是 .env 系列文件默认被挡。

三种动作:放行、问你、禁止

取值它的意思什么时候该用哪一档
"allow"不用批准,直接执行只读类、你完全信任的操作(比如 grep、glob);或者在你自己的玩具仓库里图省事
"ask"每次执行前弹出来问你生产项目里 bash 的推荐档位;改动别人的代码、跑可能影响环境的命令时
"deny"这个工具直接不可用明确知道某些事不该由 AI 做时,比如让它禁止 git push、禁止改某个目录

先抄一份"能睡好觉"的配置

如果你只想抄一段就走,抄这个。它的思路是:读放开、写和跑命令要问、几类危险命令直接禁、密钥文件不许读。

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "*": "ask",
    "read": "allow",
    "grep": "allow",
    "glob": "allow",
    "edit": "ask",
    "bash": {
      "*": "ask",
      "git status *": "allow",
      "npm test *": "allow",
      "git push *": "deny",
      "rm -rf *": "deny"
    }
  }
}
⚠️ 规则是「最后一条匹配的赢」

官方原文:Rules are evaluated by pattern match, with the last matching rule winning.(按模式匹配逐条判断,最后一条匹配的规则生效。)所以上面那段里,*: ask 写在最前面、具体规则写在后面——顺序颠倒过来,整段就失效。官方文档给的常见做法也是这一条:先放 catch-all 的 "*",再放更具体的。

哪里能写、写了能不能被覆盖

位置给谁用优先级
全局 ~/.config/opencode/opencode.json你个人的默认习惯低;会被项目配置盖掉
项目根目录 opencode.json这个团队的约定,可以提交进 Git高;盖掉全局
Agent 自己的 permission只约束某一个代理最高;和全局合并后,Agent 的规则优先
管理员托管配置公司强制下发、用户改不了最高一层,连项目配置也盖不了它

可配的权限清单:十四个键

第三列告诉你"这个键为什么值得单独配"——多数人只需要动其中三四个。

权限键它挡的是哪些动作为什么值得配 · 别当什么用
read读文件(按文件路径匹配)默认放行,但 .env 默认被挡;别拿它当"防泄漏"的万能闸——真正机密的东西不该放在它读得到的目录里
edit所有文件修改,覆盖 edit、write、apply_patch 三个工具最该配的一个;分成 "ask" 是「改前过目」,"deny" 是「只让它出方案」
bash跑 shell 命令(按解析出来的命令匹配,比如 git status --porcelain)风险最高的一项;至少设 "ask",并对 git push *、rm -rf * 这类上 "deny"
glob按模式找文件(匹配的是那个模式字符串)纯读操作,一般放行;仓库特别大时才考虑限制
grep搜文件内容(匹配的是正则串)同上,放行;想禁止它读某个目录的内容时用路径级规则
task启动子代理(匹配的是子代理的类型名)想控制"它能派出哪些小代理"时用;"deny" 会让这个子代理从工具描述里彻底消失,模型就不会去试
skill加载技能文件(匹配技能名)你装了很多技能、只想让某几个能被自动取用时的开关
lsp跑语言服务的查询目前不支持细粒度规则,只能整体开关;实验性功能
question它在执行途中向你提问关掉它 = 让它别打断你,但代价是它只能自己猜
webfetch抓取某个网址(匹配 URL)代码不能出门的场合,把它设 "deny" 比设 "ask" 更省心
websearch联网搜索(匹配查询词)同上;另外这个工具本身还有前置条件,见 12 的工具表
external_directory任何读写项目目录之外路径的动作默认就是 "ask";这是防"它跑到你主目录乱翻"的主要一道闸
doom_loop同一个工具调用、完全相同的输入,连着重复 3 次默认 "ask";它不是安全闸,是"代理卡住了"的救援提示
todowrite维护任务清单的工具(覆盖 todowrite、todoread)子代理默认不能碰这两个工具,需要的话手动开
📖 子代理的权限键名字不一样,别抄错

同一件事,在"全局/项目配置"里叫 todowrite,在 Agent 的 Markdown 配置文件里官方表格写作 todowrite / todoread 一组。另外 Agent 文档里还多列出一个 list 键(管"列目录"那个工具),它在权限总表里没有单列。这类命名不一致是真实存在的,写配置时以你那份文档页的表格为准,别凭印象拼。

细粒度规则:让"读能进去、改不能"

权限的值除了写一个动作,还可以写一个"模式 → 动作"的对象。中间支持的匹配规则很简单:* 匹配任意多个字符,? 匹配正好一个字符,其他字符按字面匹配。另外 ~ 和 $HOME 可以在开头代表你的主目录。

# 一个典型场景:只允许读某个目录,不允许改它
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "external_directory": {
      "~/projects/personal/**": "allow"
    },
    "edit": {
      "~/projects/personal/**": "deny"
    }
  }
}
⚠️ 允许一个目录 ≠ 那个目录变成了你的工作区

官方专门澄清过这一点:external_directory 里的 ~ 展开只影响你怎么写这个模式,不会把那个路径算成当前工作区。所以"项目目录以外的路径"仍然必须靠 external_directory 显式允许,别指望写个 ~ 就全通了。另外,被允许的目录会继承当前工作区的默认值——因为 read 默认放行,所以被允许的目录里的读也是放行的,除非你再单独加规则把它挡住。

"ask" 弹出来之后,三个选项分别是什么

你的选择它批准的范围什么时候点它
once只批这一次拿不准这条命令的后果时;多问几次总比误批好
always批准"和这次匹配的同一类模式"——比如 bash 通常会给一个安全前缀,像 git status*确认它是重复性的安全操作;注意这个批准只在当前这一段会话里有效
reject拒绝这一次它想跑的正是你不允许的事;拒绝之后它通常会换个做法或来问你

自动模式:批量放行,但禁掉的仍然禁掉

有些场合你不想被问(比如在 CI 里跑、或者你自己盯着屏幕),可以开自动模式:

# 启动时开
opencode --auto

# 非交互的一次性任务也支持
opencode run --auto "Refactor this module"

官方对它的边界说得很清楚:Explicit "deny" rules are still enforced. Auto mode only changes requests that would otherwise ask for approval.(显式写 "deny" 的规则照样执行;自动模式只改那些「本来会来问你」的请求。)在界面里也能切:按 Ctrl+P 打开命令面板,搜 "auto-approve" 就能开关;开着的时候,输入框旁边会有一个淡淡的 auto 提示。

💡 生产项目的最小动作

如果你只打算改一行配置,就改这一行:在项目根目录的 opencode.json 里写 {"permission": {"bash": "ask"}}。它把最高风险的那一项从"默默执行"变成"每次过目",而读写文件仍然顺畅——性价比最高的一道闸。

三段可以直接抄的细粒度配置

前面讲的是规则,这里是三段真实可用的写法。它们的差别在于"你想拦到多细"。

# ① 全局两档:改要问、跑命令要问(最小可用)
{
  "permission": {
    "edit": "ask",
    "bash": "ask"
  }
}
# ② 把 bash 拆开:默认问,几条读类命令放行,几条危险命令禁止
{
  "permission": {
    "bash": {
      "*": "ask",
      "git status": "allow",
      "git status *": "allow",
      "npm test": "allow",
      "npm test *": "allow",
      "git push": "deny",
      "git push *": "deny"
    }
  }
}
📖 为什么上面每条都写了两遍

因为匹配的是解析后带参数的完整命令。官方在权限页的提示里写得很清楚:"grep *" 能放行 grep pattern file.txt,而只写 "grep" 会把带参数的那种挡在外面;git status 这种"不带参数能用"的,一旦带了参数就需要显式放行。同时写"不带参数"和"带参数"两条,是这里唯一不会漏的写法。

# ③ 按代理分开配:全局不许改,但 build 这个主代理例外
{
  "permission": { "edit": "deny" },
  "agent": {
    "build": {
      "permission": { "edit": "allow" }
    }
  }
}
# ④ 同一个思路,写在一个 Markdown 代理文件里(只读审查代理)
# ~/.config/opencode/agents/review.md
---
description: Code review without edits
mode: subagent
permission:
  edit: deny
  bash:
    "*": ask
    "git diff": allow
    "git log*": allow
    "grep *": allow
  webfetch: deny
---
Only analyze code and suggest changes.

最后这段值得多看一眼:它只放行了三条读类命令(git diff、以 git log 开头的、以及 grep 带参数的),其余 bash 一律要问、抓网页直接禁止。一个"只做审查、绝不改代码"的代理,配出来就是这么几行。

11@ 和 ! 什么时候用

消息框里有两个符号不是普通文字:@ 表示"去把项目里的文件喂给我看",! 表示"这条先当命令跑掉"。这两个符号决定了它到底知不知道你在说什么,所以值得单独讲清。

@ 引用文件:它替你做了"复制粘贴文件内容"这件事

你在消息里打 @,它会在这个项目里做一次模糊搜索——你打几个字母,候选文件名就列出来了,选中即可。官方文档的说法是:The content of the file is added to the conversation automatically.(文件内容会被自动加进对话。)

这个函数的逻辑不太对,帮我看看 @src/utils/format.ts
# OpenCode 会自动读取文件内容并加入对话上下文

# 更具体的问法:把两个文件一起给它
我们需要给 /settings 路由加认证。
参考 @packages/functions/src/notes.ts 里的写法,
在 @packages/functions/src/settings.ts 里实现同样的逻辑。

! 前缀:让它的眼睛看到"现场"

以 ! 开头的整条消息会被当成 shell 命令执行,输出作为工具结果进入对话。官方的说法是 The output of the command is added to the conversation as a tool result——注意"工具结果"这个词,意味着它和它自己跑命令看到的东西是同一种东西。

!ls -la
!git log --oneline -10
!git diff HEAD~3
💡 为什么这条比"你帮我看一下 git 历史"强

因为它的"自己去看"要花好几轮:先想用什么命令、再等你批准、再看输出。而你直接 !git diff HEAD~3 把它要看的东西一次性放到它面前,省掉的是往返次数(也省了 token)。最实用的组合是「命令 + 问题」写在一条消息里。

引用别名:把"隔壁仓库"也变成 @ 得出来的东西

项目里常有这种情况:真正要参考的文档在另一个仓库。references 就是为这个场景准备的——配一次别名,之后 @别名 即可。

# 完整写法:本地目录用 path,Git 仓库用 repository + 可选 branch
{
  "$schema": "https://opencode.ai/config.json",
  "references": {
    "docs": {
      "path": "../product-docs",
      "description": "Use for product behavior and documentation conventions"
    },
    "sdk": {
      "repository": "anomalyco/opencode-sdk-js",
      "branch": "main",
      "description": "Use for JavaScript SDK implementation details"
    }
  }
}

# 简写:不需要分支和描述时,直接写路径或仓库
{
  "references": {
    "docs": "../docs",
    "effect": "Effect-TS/effect"
  }
}

# 用起来:@别名 挂上整个根,@别名/ 继续往里搜文件
对比我们的配置和 @docs/README.md
对比一下我们的实现和 @sdk/src/client.ts
字段本地目录Git 仓库它是干什么的
path可以不行指向一个本地目录;可以是相对配置文件的位置、绝对路径、或 ~/ 开头
repository不行可以接受 Git URL、host/path 形式,或 GitHub 的 owner/repo 简写;它会把这个仓库拉到本地缓存里再用
branch不行可以指定分支或 ref;不写就用仓库的默认分支
description可以可以告诉模型"什么时候该用这个引用";只有带描述的引用才会被主动告诉模型
hidden可以可以从 @ 自动补全里藏掉;它只影响补全,带描述的隐藏引用仍然会进模型上下文
📖 别名有命名限制

官方写明了:别名不能为空,也不能包含 /、空白、反引号、逗号。想成"文件夹名"就行——因为 @别名/ 后面还要接路径,别名里再出现斜杠就分不清边界了。

引用和权限是什么关系

这一条挺关键,因为它解释了"为什么我配了 @docs 就能读隔壁目录,而别的目录还是要问":

# 把引用藏起来,不污染 @ 补全列表(但仍然希望模型知道它存在 → 保留 description)
{
  "references": {
    "internal": {
      "path": "../internal",
      "description": "Use for internal implementation details",
      "hidden": true
    }
  }
}
⚠️ 别把 references 当成"免权限通道"

它的作用是"让模型知道该去哪找、并让 @ 能补全出来",不是"给它一片法外之地"。真要约束,还得回到 permission 那一套规则上写(见 10)。

12主代理与子代理

Agent(代理)这个词在 OpenCode 里指的不是模型,而是一套预设:用哪个模型、允许用哪些工具、系统提示词是什么、在界面上什么颜色。官方把内置的代理分两类:主代理(直接和你对话的)和子代理(被主代理派出去干专项活的)。

两类的差别只有一句话

类型谁在跟它说话你怎么启动它它的 description 写给谁看
主代理(primary)你。它是你正在对话的那个Tab / Shift+Tab 轮换,或用配置里的 default_agent 指定默认那个写给你看,帮你判断该切到它
子代理(subagent)主代理。你一般不直接和它聊主代理自己按任务派;你也可以在消息里 @名字 直接点它写给模型看——它靠这段描述判断"这个任务该不该交给它"
📖 这条边界解释了为什么"描述写得好不好"很重要

主代理决定要不要派子代理时,看的就是子代理的 description。所以你自定义一个子代理时,描述要写成"什么时候用它"而不是"它是什么"。一个可用的写法是:Reviews code for best practices and potential issues(官方示例原话),而不是"代码审查代理"。

五个内置代理,各管一段

除了这五个,还有三个"隐藏的系统代理"(compaction、title、summary),它们负责压缩上下文、起会话标题、写会话摘要,自动跑,你在界面上选不到。

代理类型它能做什么什么时候用它
Build主代理(默认)所有工具都开着:能读、能改、能跑命令日常开发、写代码、修 bug——它是你 80% 时间的默认状态
Plan主代理受限代理:官方原话是「以下全部默认设为 ask」——所有文件编辑(写入、打补丁、编辑)与所有 bash 命令分析代码、出方案、评审建议。这是"先别动手"的开关
General子代理通用子代理,工具几乎全开(只差待办清单那个),所以它也能改文件研究复杂问题、执行多步骤任务;官方建议用它来并行跑几块工作
Explore子代理只读,不能改文件。按模式找文件、按关键词搜代码、回答关于代码库的问题"这个项目里 X 在哪、怎么实现的"这类快速摸路
Scout子代理只读,看外部文档和依赖库:能把依赖仓库 clone 到它的缓存里、查库的源码、对照本地实现和上游怀疑"是不是库自己有问题"、或要照着上游写法改时
💡 Plan 和 Build 的配合,是省返工的关键

默认配置里 Plan 会把 edit 和 bash 都设成「要问你」。这不是"它不能改",而是"它每次想改都会先停下来问你"——所以你在 Plan 模式下说"实现它",它会先给你方案而不是直接动手。真正的用法是:Plan 里把方案讨论清楚 → 按 Tab 切到 Build → 一句"看起来不错,开始实现吧"。这一来一回省下的是"它按错的理解改了 200 行"。

怎么调用子代理

三条路,按你可能用到的顺序排:

# 1. 手动点名:在消息里 @ 它
@general help me search for this function

# 2. 自动:主代理按子代理的 description 自己决定派谁

# 3. 看它干的活:子代理会开自己的"子会话"
#    进入第一个子会话        <leader>+↓(默认 ctrl+x 然后方向键下)
#    在子会话之间轮换        →(右箭头)
#    反向轮换                ←(左箭头)
#    回到父会话              ↑(上箭头)
⚠️ 子代理不是"免费并行"

子代理的价值在于:它读的一大堆文件不占你主会话的上下文——它在自己的会话里读,只把结论带回来。但代价是:它看到的东西和你当前对话的上下文不共享,所以给它的指令必须自洽、不能靠"你懂的"。另外官方默认只允许一层子代理(子代理不能再派子代理),想放宽要动 subagent_depth(见 13)。

它手上到底有哪些工具

这是"权限表"的另一面。上一节讲的是"怎么拦",这一张讲的是"它本来能干什么"。

工具它干什么由哪个权限键管特别要注意的
bash在你项目环境里执行 shell 命令bash风险最高;匹配的是解析后的命令(比如 git status --porcelain),所以带参数的命令要写 "git status *" 这种带星号的规则
edit用"精确替换某段字符串"的方式改现有文件edit官方说它是"LLM 改代码的主要方式";它只替换完全匹配的文本,所以改造上下文不唯一的代码时会失败
write创建新文件、或覆盖已有文件edit注意它会覆盖同名文件;它没有独立的权限键,和 edit、apply_patch 共用
read读文件内容read支持只读某几行(大文件时有用);.env 系列默认被挡
grep用正则搜文件内容grep底层是 ripgrep,默认遵守 .gitignore——这既省时间也是个坑(见下)
glob按 **/*.ts 这类模式找文件glob返回的文件按修改时间排序
lsp问语言服务:跳定义、找引用、悬停信息、调用层级lsp实验性,只有打开实验开关才出现;能省掉大量"全文翻找"
apply_patch应用补丁文件edit它能一次做增删改移四种操作,路径信息写在补丁的标记行里(比如 *** Update File: src/a.ts)
skill加载一个技能文件(SKILL.md)并把内容带进对话skill装了技能包时它才会出现在工具列表里
todowrite维护一份任务清单,跟踪多步进度todowrite子代理默认没有这个工具,需要手动开
webfetch抓取某个网址的内容webfetch用途是"取回已知地址的内容",不是"找资料"
websearch联网搜索websearch有前置条件:只用 OpenCode / OpenCode Go 这两家提供商时自带,否则要设 OPENCODE_ENABLE_EXA 或 OPENCODE_ENABLE_PARALLEL;不需要额外的 API Key
question在执行途中反过来问你问题question一次可以问多个,每个带选项,你也可以自己敲答案
# 联网搜索的两条开启方式(默认不满足前置条件时不出现这个工具)
OPENCODE_ENABLE_EXA=1 opencode
OPENCODE_ENABLE_PARALLEL=1 opencode

# LSP 工具是实验性的,要显式打开
OPENCODE_EXPERIMENTAL_LSP_TOOL=true opencode
⚠️ grep / glob 默认"看不到"被忽略的文件

官方写明:grep 和 glob 底层用 ripgrep,而 ripgrep 默认遵守 .gitignore——.gitignore 里列掉的文件和目录,它搜不到也列不出。想让它看进去,在项目根目录建一个 .ignore 文件,把要放开的路径以 ! 开头写进去:

!node_modules/
!dist/
!build/

这条也解释了一个常见困惑:"为什么它说找不到那个文件?"——先去确认那个文件是不是被 .gitignore 排掉了。

自己造一个代理:两种写法

内置的五个不够用时,可以加自己的。JSON 那种适合"顺手改一下内置代理",Markdown 那种适合"长期维护一个专用代理"。

# 写法一:写在配置里(opencode.json)
{
  "$schema": "https://opencode.ai/config.json",
  "agent": {
    "build": {
      "mode": "primary",
      "model": "anthropic/claude-sonnet-4-20250514",
      "prompt": "{file:./prompts/build.txt}",
      "permission": {
        "edit": "allow",
        "bash": "allow"
      }
    },
    "plan": {
      "mode": "primary",
      "model": "anthropic/claude-haiku-4-20250514",
      "permission": {
        "edit": "deny",
        "bash": "deny"
      }
    },
    "code-reviewer": {
      "description": "Reviews code for best practices and potential issues",
      "mode": "subagent",
      "model": "anthropic/claude-sonnet-4-20250514",
      "prompt": "你是一个代码审查专家。关注安全性、性能和可维护性。",
      "permission": {
        "edit": "deny"
      }
    }
  }
}
# 写法二:一个 Markdown 文件。放项目级或全局级:
#   .opencode/agents/review.md
#   ~/.config/opencode/agents/review.md
---
description: Reviews code for quality and best practices
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
permission:
  edit: deny
  bash: deny
---
You are in code review mode. Focus on:
- Code quality and best practices
- Potential bugs and edge cases
- Performance implications
- Security considerations
Provide constructive feedback without making direct changes.

这是同一个机制做出来的第二个代理——一个安全审计用的子代理。它和上面那个只差在提示词和文件位置:

# .opencode/agents/security-auditor.md
---
description: 代码安全审计
mode: subagent
permission:
  edit: deny
---
你是一个安全专家。关注:
- 输入验证漏洞
- 认证和授权缺陷
- 数据暴露风险
- 依赖漏洞

文件的名字就是代理名:review.md 就创建了一个叫 review 的代理;security-auditor.md 就是 security-auditor。两者都被设成 mode: subagent、edit: deny,所以它们能看、能分析,但改不了你的代码——这正是"审查类代理"该有的形状。

一个代理能配哪些选项

选项它管什么取值与默认什么时候真的需要它
description这个代理是干什么、什么时候用必填子代理必填;它是主代理决定"派不派它"的唯一依据
mode这个代理是主代理还是子代理primary / subagent / all;不写默认 all想让一个代理既能 Tab 切到、又能被 @ 点名时用 all
model这个代理用哪个模型不写时:主代理用全局配置那个,子代理沿用调用它的主代理的模型想给"规划"配便宜模型、"实现"配强模型时
prompt系统提示词;写 {file:./prompts/x.txt} 可以指向一个文件路径相对配置文件所在目录提示词很长、想单独维护时
temperature回答的随机程度常用区间 0.0–1.0;不写时按模型自己的默认(多数模型是 0,Qwen 系列常见是 0.55)0.0–0.2 适合分析规划;0.6–1.0 适合头脑风暴
steps这个代理最多能"自己动手"多少轮,到顶就强制只输出文字不写则不限,一直做到模型自己停或你打断想把成本封顶时用;旧名字 maxSteps 已废弃,用 steps
permission这个代理的权限,和全局合并,同键时以它为准见 10 的十四个键做只读代理、或做"能改但禁止 push"的代理时
hidden从 @ 自动补全里藏掉只对 mode: subagent 生效内部专用代理,不想让它出现在补全里、但仍希望模型能通过工具派它
disable把这个代理关掉true / false不想用内置的某个代理、又不想删配置时
color它在界面上的颜色十六进制色值如 #FF5733,或主题色名 primary / accent / success 等代理多起来之后靠颜色分辨
permission.task这个代理允许派哪些子代理模式对象;"deny" 会让那个子代理从工具描述里彻底消失做一个"只能派自己那几个下属"的编排代理时
# 用命令行交互式造一个新代理(想量产时把四个参数都给全,就变成非交互)
opencode agent create
opencode agent list

# 四个参数都给全时,它不再问你任何问题
opencode agent create --path .opencode/agents --description "审查 SQL 注入风险" --mode subagent --permissions read,grep,glob
🚨 agent create 的权限是「白名单逻辑」

官方写得很清楚:你没允许的都会被否掉。可用清单是 bash, read, edit, glob, grep, webfetch, task, todowrite, websearch, lsp, skill,默认值是 all(全给)。也就是说——如果你为了"安全"而写了一个空的 --permissions,得到的确实是最小权限;但如果你随手照抄了"默认 all",那你造出来的是一个权限全开的代理。这一步值得停下来看一眼参数。

📖 一个老配置项,别在新配置里再用

你可能在旧教程里看到 "tools": {"write": false} 这种写法。官方已经把它标为废弃(deprecated),推荐改用 permission 字段,因为它能表达更细的规则。旧写法目前仍然兼容:在那套语义里,true 等价于 {"*": "allow"},false 等价于 {"*": "deny"},并且支持 mymcp_* 这种通配符来一次控制一个 MCP 服务器下的所有工具。

13配置文件与优先级

OpenCode 的配置是多份合并的,不是"一份覆盖另一份"。官方原话:Configuration files are merged together, not replaced.(配置文件是合到一起的,不是替换关系。)明白这一点,才能解释"我明明改了全局配置怎么不生效"——因为项目里那份把它盖掉了。

八层优先级,从低到高

后面盖前面。你日常只会碰到中间三层,但知道有托管层存在,能解释"为什么这条配置我改不动"。

顺序来源它在哪你什么时候会用它
1(最低)远程配置组织在 .well-known/opencode 提供的默认值你加入了某家提供商的账号时它自动生效,你一般不用管
2全局配置~/.config/opencode/opencode.json你的个人习惯:默认模型、默认权限
3自定义路径配置OPENCODE_CONFIG 指定的文件想在"全局"和"项目"之间插一层时(比如按客户切换)
4项目配置项目根目录的 opencode.json团队约定,可以提交进 Git
5.opencode 目录内容.opencode/ 下的 agents、commands、plugins 等放自定义代理、自定义命令时
6内联配置OPENCODE_CONFIG_CONTENT 里直接写的 JSON临时试一段配置,不想落文件时
7管理员托管文件macOS /Library/Application Support/opencode/、Linux /etc/opencode/、Windows %ProgramData%\opencode公司强制下发的配置,需要管理员权限才能写,你改不了
8(最高)macOS 托管偏好通过 MDM 下发的 .mobileconfig(偏好域 ai.opencode.managed)企业环境;官方说它不可被用户覆盖
📖 「合并」具体是什么意思

官方举的例子最能说明问题:全局配置里写了 autoupdate: true,项目配置里写了 model: "anthropic/claude-sonnet-4-5"——最后生效的配置里两条都在。只有同一个键冲突的时候,后面的才盖前面的。所以你的全局配置不会因为项目里放了个小配置就整体失效。

放配置的三条经验规则

常用配置项:一份能直接用的样例

下面这份把最常动的几项都放进去了,注释写在右侧。抄的时候记得删掉注释——或者干脆把文件命名成 opencode.jsonc,那种格式允许注释。

{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-5",
  "small_model": "anthropic/claude-haiku-4-5",
  "autoupdate": true,
  "formatter": true,
  "lsp": true,
  "permission": {
    "edit": "allow",
    "bash": "ask"
  },
  "instructions": ["CONTRIBUTING.md", "docs/guidelines.md"]
}

其余常用项,按你的需求点菜

配置项它管什么取值 / 默认什么时候动它
autoupdate启动时自动下载更新true / false / "notify"想收通知但不想自动升级时写 "notify"。用包管理器装的它不管——那种升级交给 brew / npm
formatter代码格式化省略 = 关闭;true = 开;对象 = 开内置再配覆盖或自定义它改完文件后自动跑格式化,团队有统一格式时开
lsp语言服务省略 = 关闭;true = 开;对象 = 开内置再覆盖类型化语言项目里开着,能让它"跳定义"而不是翻全文
instructions额外的指令文件路径或 glob 数组,如 ["CONTRIBUTING.md", ".cursor/rules/*.md"]规则分散在好几个文件里时,比全塞进 AGENTS.md 好维护
shell用哪个 shell 跑命令短名或绝对路径;不写就按系统自动选Windows 上想固定用 pwsh 时
share分享模式"manual"(默认)/ "auto" / "disabled"代码敏感就别用 "auto";想彻底关掉写 "disabled"
snapshot文件改动快照,/undo 与 /redo 的底座默认开大仓库、子模块多时它可能拖慢索引并占磁盘;关掉就不能用界面回滚
compaction上下文压缩策略auto 默认 true、prune 默认 false、reserved 是预留的 token 缓冲对话经常撞上限、或想省 token 时调
watcher.ignore文件监听忽略哪些路径glob 数组仓库里有大量生成物、监听吵得慌时
default_agent不指定时默认用哪个代理必须是主代理;写错会退回 build 并警告你就是想默认进 Plan 模式时
subagent_depth子代理还能不能再派子代理默认 1;0 表示完全禁止派子代理,2 表示允许多一层想编排"多层小代理"时;或者反过来想彻底关掉这个能力
plugin从 npm 加载插件包名数组,如 ["opencode-helicone-session", "@my-org/custom-plugin"]想扩功能时;插件文件也可以直接放 .opencode/plugins/
disabled_providers / enabled_providers哪些提供商不加载 / 只加载哪些提供商 ID 数组见 09;注意前者优先级更高
attachment.image图片输入的预处理上限(把图片统一缩放成一致的规格再发出去)默认超过 2000×2000 像素或 5242880 字节的 base64 就缩;auto_resize 设 false 则改为直接拒绝截图模糊、看不清小字时,把这几个上限调大

两个占位符,让配置不写死秘密

官方支持两种替换:{env:变量名} 取环境变量,{file:路径} 取文件内容。

{
  "$schema": "https://opencode.ai/config.json",
  "model": "{env:OPENCODE_MODEL}",
  "provider": {
    "anthropic": {
      "options": {
        "apiKey": "{env:ANTHROPIC_API_KEY}"
      }
    }
  }
}
# 从文件里读密钥,避免把密钥写进配置文件
{
  "instructions": ["./custom-instructions.md"],
  "provider": {
    "openai": {
      "options": {
        "apiKey": "{file:~/.secrets/openai-key}"
      }
    }
  }
}
⚠️ 环境变量没设时不是报错,是"变成空串"

官方写明:If the environment variable is not set, it will be replaced with an empty string.(环境变量没设时,它会被替换成空字符串。)这意味着你少设一个变量,不会看到"配置错误",只会看到"认证失败"或"模型不存在"——排查时先往这里想。另外 {file:…} 的路径可以是相对于配置文件的位置、绝对路径、或 ~/ 开头。

常被问到的几个环境变量

变量类型它干什么
OPENCODE_CONFIG字符串指定配置文件路径(插在全局与项目之间那一层)
OPENCODE_CONFIG_DIR字符串指定一个自定义配置目录,会在全局配置和 .opencode 之后加载,所以能盖掉它们
OPENCODE_CONFIG_CONTENT字符串直接内联一段 JSON 配置,运行时覆盖
OPENCODE_TUI_CONFIG字符串指定自定义的 TUI 配置路径
OPENCODE_PERMISSION字符串内联的权限配置 JSON
OPENCODE_DISABLE_AUTOUPDATE布尔关掉自动更新检查
OPENCODE_DISABLE_AUTOCOMPACT布尔关掉自动上下文压缩
OPENCODE_ENABLE_EXA / OPENCODE_ENABLE_PARALLEL布尔打开对应的联网搜索工具(见 12)
OPENCODE_SERVER_PASSWORD / OPENCODE_SERVER_USERNAME字符串给 serve / web 加基础认证;用户名默认 opencode
OPENCODE_GIT_BASH_PATH字符串Windows 上指定 Git Bash 的位置
OPENCODE_DISABLE_CLAUDE_CODE布尔完全关掉对 .claude 目录(提示词 + 技能)的读取
OPENCODE_DISABLE_MODELS_FETCH布尔不从远端拉模型清单(离线或内网时有用)

接一个 MCP 服务器:让模型多出几只手

MCP(Model Context Protocol,模型上下文协议)是"给模型接外部工具"的一套标准接口。接上之后,那个服务器提供的工具会和内置工具一样出现在模型手里。

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "mcp_everything": {
      "type": "local",
      "command": ["npx", "-y", "@modelcontextprotocol/server-everything"]
    },
    "my-local-mcp-server": {
      "type": "local",
      "command": ["npx", "-y", "my-mcp-command"],
      "enabled": true,
      "environment": {
        "MY_ENV_VAR": "my_env_var_value"
      }
    },
    "my-remote-mcp": {
      "type": "remote",
      "url": "https://my-mcp-server.com",
      "enabled": true,
      "headers": {
        "Authorization": "Bearer MY_API_KEY"
      }
    }
  }
}

# 接上之后,在提示里直接点名那个服务器的工具
use the mcp_everything tool to add the number 3 and 4
字段本地(local)远程(remote)它是干什么的
type必填,写 "local"必填,写 "remote"选哪种连接方式。旧教程里写的 "stdio" 已经不是现在的取值了
command必填—怎么启动这个 MCP 服务器;是个数组,比如 ["npx", "-y", "包名"]
url—必填远程 MCP 服务器的地址
headers—可选随请求带的请求头,用来放鉴权信息
environment可选—启动这个服务器时设的环境变量
cwd可选—服务器进程的工作目录;相对路径从工作区算起
enabled可选可选开关。组织下发的远程配置里常有 "enabled": false,你在自己配置里写 true 就能打开
timeout可选可选拉取这个服务器的工具清单时最多等多久,默认 5000 毫秒
oauth—可选需要 OAuth(一种"跳到你浏览器里点同意、再换一张临时通行证"的授权方式)时的配置;不写也会自动处理——它收到 401(服务器说"你没登录")就会自己发起授权流程
# 命令行管 MCP:加、列、授权、退授权、排查
opencode mcp add
opencode mcp list
opencode mcp auth my-oauth-server
opencode mcp logout my-oauth-server
opencode mcp debug my-oauth-server

# 一个接数据库的例子(官方文档里的另一种写法:type 用 local,command 是数组)
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "database": {
      "type": "local",
      "command": ["npx", "-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
    }
  }
}

# 想临时停掉某一个而不从配置里删:把它的 enabled 设成 false
{
  "mcp": {
    "jira": {
      "type": "remote",
      "url": "https://jira.example.com/mcp",
      "enabled": false
    }
  }
}

# 需要手填客户端凭据时(服务器方给你的)
{
  "mcp": {
    "my-oauth-server": {
      "type": "remote",
      "url": "https://mcp.example.com/mcp",
      "oauth": {
        "clientId": "{env:MY_MCP_CLIENT_ID}",
        "clientSecret": "{env:MY_MCP_CLIENT_SECRET}",
        "scope": "tools:read tools:execute"
      }
    }
  }
}
⚠️ MCP 不是"越多越好",它吃上下文

官方专门写了一节注意事项:When you use an MCP server, it adds to the context. This can quickly add up if you have a lot of tools.(用 MCP 服务器会增加上下文,工具一多就涨得很快。)它还点了名:GitHub 那个 MCP 服务器特别占 token,很容易把上下文顶满。够用就行,别一次挂一堆。想临时停掉某个服务器,把它的 enabled 设成 false,不用从配置里删。

更多现成的 MCP 服务器怎么配,官方有一个单独页面:opencode.ai/docs/mcp-servers。想少装东西试一下,可以用官方文档里那个只提供一个加法工具的测试服务器 @modelcontextprotocol/server-everything。

💡 微调小抄:三个你可能马上要用的片段

后面这几段是配置里能写、但你在别处不一定看得到的组合,按需取用。

# 1. 服务器选项(serve / web 共用)
{
  "server": {
    "port": 4096,
    "hostname": "0.0.0.0",
    "mdns": true,
    "mdnsDomain": "myproject.local",
    "cors": ["http://localhost:5173"]
  }
}

# 2. 自定义格式化器(保留内置的,只加/改某一个)
{
  "formatter": {
    "prettier": { "disabled": true },
    "custom-prettier": {
      "command": ["npx", "prettier", "--write", "$FILE"],
      "environment": { "NODE_ENV": "development" },
      "extensions": [".js", ".ts", ".jsx", ".tsx"]
    }
  }
}

# 3. 只允许某些提供商使用(企业里常见的白名单写法)
{
  "experimental": {
    "policies": [
      { "effect": "deny", "action": "provider.use", "resource": "openai" }
    ]
  }
}

experimental 这一层官方标了警告:它不稳定,可能不加通知就改或删掉。企业场景用它,个人场景别依赖它。

14AGENTS.md:写给 AI 的项目说明书

如果说 10 管的是"它能做什么",这一节管的是"它知不知道该怎么做"。答案是:靠项目根目录那个叫 AGENTS.md 的文件。官方对它的定位是:里面的指令会被放进模型的上下文里,用来把它的行为调成适合你这个项目的样子。

/init 到底做了什么

不用手写。敲一条命令它就替你建:

/init

官方对它的描述值得逐句读,因为它决定了你该期待什么:它会扫一遍仓库里的重要文件、在代码本身答不上来时问你几个有针对性问题,然后创建或更新 AGENTS.md。它重点记的是这五类东西:

💡 已经有一份 AGENTS.md 会怎样

官方写明:If you already have an AGENTS.md, /init will improve it in place instead of blindly replacing it.(如果你已经有 AGENTS.md,/init 会就地改进它,而不是盲目替换。)所以「手写一份 + 后面用 /init 补」是可行路线,但每次跑完还是 !git diff 看一眼它改了什么更稳。

一份可以照抄结构的 AGENTS.md

下面是官方文档里的示例。它的写法很克制——只写"命令 + 约定 + 结构",不写状态、不写历史。这个取舍值得学:这份文件每次会话都会被读进去,写多了等于每次都在多花你的上下文预算。

# SST v3 Monorepo Project
This is an SST v3 monorepo with TypeScript. The project uses bun workspaces for package management.
## Project Structure
- `packages/` - Contains all workspace packages (functions, core, web, etc.)
- `infra/` - Infrastructure definitions split by service (storage.ts, api.ts, web.ts)
- `sst.config.ts` - Main SST configuration with dynamic imports
## Code Standards
- Use TypeScript with strict mode enabled
- Shared code goes in `packages/core/` with proper exports configuration
- Functions go in `packages/functions/`
- Infrastructure should be split into logical files in `infra/`
## Monorepo Conventions
- Import shared modules using workspace names: `@my-app/core/example`

放哪一份、哪一份说了算

位置作用范围优先级什么时候用它
项目根目录的 AGENTS.md只在这个目录及其子目录生效本项目内最高团队约定,应该提交进 Git
~/.config/opencode/AGENTS.md你所有 OpenCode 会话低于项目里的那一份你自己的个人习惯(官方特别提醒:这个不会提交、不共享给团队)
项目里的 CLAUDE.md只在这个目录及其子目录生效只在没有 AGENTS.md 时才用你从 Claude Code 迁过来,还不想改文件名时
~/.claude/CLAUDE.md你所有 OpenCode 会话只在没有 ~/.config/opencode/AGENTS.md 时才用同上,全局版
📖 优先级的确切规则

官方给的查找顺序是:先从当前目录往上找本地文件(AGENTS.md、CLAUDE.md),然后是 ~/.config/opencode/AGENTS.md,最后是 ~/.claude/CLAUDE.md。每一类里第一个命中的赢——所以你同时有 AGENTS.md 和 CLAUDE.md 时,只有前者会被用。这条规则解释了那个经典困惑:"我明明改了 CLAUDE.md 怎么没用?"

不想要 Claude Code 那套兼容,就关掉

# 完全关掉对 .claude 的读取(提示词 + 技能)
export OPENCODE_DISABLE_CLAUDE_CODE=1

# 只关 ~/.claude/CLAUDE.md 这份提示词
export OPENCODE_DISABLE_CLAUDE_CODE_PROMPT=1

# 只关 .claude/skills 里的技能
export OPENCODE_DISABLE_CLAUDE_CODE_SKILLS=1

规则文件不止一份时,用 instructions 汇总

很多项目已经有自己的规范文档(CONTRIBUTING.md、.cursor/rules/……)。与其把它们复制进 AGENTS.md,不如让 OpenCode 直接去读:

{
  "instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md"]
}

它和 Plan 模式不是一回事

这两个是新手最容易混的一对,因为它们都"让 AI 更懂规矩",但管的是完全不同的两件事:

AGENTS.md(+ instructions)Plan 模式(permission)
它回答的问题它知不知道该怎么做:项目用什么命令、代码放在哪、有什么约定它允不允许动手:能不能改文件、能不能跑命令
生效方式内容进模型上下文,影响它的判断在工具被调用时拦一道,影响它能不能做
配错了的表现它会用错命令、改错地方,但会真去改它一直来问你,或者你根本没发现它在改
什么时候该动新项目、新团队、目录结构变了进生产项目前、要它只出方案时
💡 一条实用经验:AGENTS.md 越短越有用

官方示例通篇只讲"结构 + 命令 + 约定",没有一句是"当前正在做什么"。原因很直接:这份文件每次会话都会被读一遍,写进去的历史备注、临时状态、过期待办,全都是每次都要重新读一遍的噪音。要放"今天在做什么",用任务清单工具或直接在对话里说。

15六个真实场景

前面讲的是零件。这一节把零件拼成六件真事,每一件都给一段能直接抄进去的话。注意每段的写法有共同点:都给上下文(@文件)、都给验收标准("加测试""只看失败的"),最后一件还先自己把现场贴进去(!命令)。

先按你的任务挑一个

你要干的事用哪个模式关键写法对应场景
刚接手一个陌生代码库Plan 或只读提问先让它给结构总结,再逐块问 @目录/场景一
加一个新功能Plan → Build先说清需求、要它列改动文件,确认后再实现场景二
修一个具体 bugPlan引用具体文件 + 描述可复现的现象,并要它加测试场景三
大规模重构Plan 先试跑先在一个目录上试,确认它理解了模式再铺开场景四
补测试Build明确覆盖范围(正常流程 + 错误场景)场景五
审查最近的改动Plan自己先 !git diff 把改动摆出来,再让它审场景六
只想问个技术问题不启动界面也行opencode run "问题",跑完就退07

场景一:理解陌生代码库

别一上来就"给我讲讲这个项目"——那样你得到的是一篇概括。更有效的做法是先要一张地图,再按块追问。

给我这个项目的整体架构做一个总结
重点关注 @src/api/ 目录下的路由设计

如果 @src/api/ 这种目录级引用让它一次读太多文件,就换成"先列文件、再逐个问":

先列出 @src/api/ 下面所有的路由文件,不要读内容。
然后告诉我哪个文件负责处理用户登录。

场景二:加一个新功能

先用 Plan 出方案,确认后再切 Build。这是整套用法里最省返工的一步。

# 1. 按 Tab 切到 Plan 模式,然后说需求
我想给用户系统加一个"最近登录时间"字段。
先分析一下需要改哪些文件,给我一个方案。

# 2. 看方案、提意见(这一步不要跳)
数据库迁移你打算怎么做?线上已经有数据了,不能停机。

# 3. 按 Tab 切回 Build,再让它动手
方案看起来不错,开始实现吧。

场景三:修一个具体的 bug

这个场景的关键是:把"能复现的现象"说出来,而不是只说"有 bug"。前者能让它验证自己的修复,后者只能让它猜。

@src/utils/auth.ts 里的 login 函数有问题,
用户输入空密码时不会报错。帮我修复并加上测试。

# 更好的版本:把复现步骤也给出来
@src/utils/auth.ts 的 login 函数在 password 传空字符串时返回成功。
我在 @src/utils/auth.test.ts 里加了这条用例但它失败了:
!npm test -- auth.test.ts
先看失败信息,再修 login,不要改测试。

场景四:代码重构

重构最容易失控,因为它涉及的文件多。先小范围试跑是这里唯一值得记住的技巧。

帮我把 @src/components/ 里的 class 组件
全部重构成 functional component + hooks

# 更稳的做法:先让它在一个文件上证明它理解了模式
先只改 @src/components/UserCard.tsx 这一个文件,
按 functional component + hooks 重写一遍,其他文件先别动。
改完告诉我你做了哪几处等价变换。

场景五:写测试

给 @src/services/api.ts 写单元测试,
覆盖正常流程和错误场景

想让它写得像你团队的样子,就把现有的测试文件也引用上——一个例子顶十句描述:

给 @src/services/api.ts 写单元测试。
格式和断言风格参考 @src/services/user.test.ts,
要覆盖正常流程、网络错误、以及返回空数据三种情况。

场景六:审查最近的改动

这一类最值得用 ! 前缀:你自己先把现场贴进去,它就不用猜"最近"是哪几次。

审查一下最近的改动,关注安全性和性能问题
!git diff HEAD~3

如果改动很多、你又只想看有风险的部分:

!git diff HEAD~3 --stat
上面这些文件里,只挑涉及认证和数据库查询的改动来审。
每条问题按"文件:行 · 问题 · 为什么危险 · 怎么改"列出来。
📖 这六段的共同结构

回头看一眼会发现它们都是同一个模板:目标(要什么) + 上下文(@文件 / !命令) + 约束(别改测试、只改一个文件、只看某几类) + 产出格式(列出来 / 加测试 / 给方案)。这四样缺哪个,它就只好自己猜哪个——而它猜错的时候,你花的返工时间比多打那两行字贵得多。

16十个最常见的坑

下面这些是真实会撞上的。前三类是"刚装完"的坑,中间是"用起来"的坑,最后两条是"你以为配好了其实没有"的坑——那两条不发脾气、不报错,最危险。

第一类:装完就卡住

症状真实原因怎么办
敲 opencode 提示命令不存在安装目录不在 PATH 里;或者命令存在但 shell 缓存了旧的路径表Homebrew 装的一般在 /opt/homebrew/bin(Apple 芯片)或 /usr/local/bin;npm 装的是 npm bin -g 那个目录。加进 PATH 后重开终端
公司机器不允许 curl | bash那是一条"下载脚本直接执行"的命令,很多安全策略会拦换包管理器那条(npm install -g opencode-ai 最常见),或者去 Releases 页面下对应平台的二进制
Windows 上各种怪问题原生 Windows 的终端与文件系统集成和 Linux 差异大官方推荐用 WSL;opencode web 的文档也明确说 Windows 上请从 WSL 里跑

第二类:接不上模型

症状真实原因怎么办
界面里看不到任何模型还没接提供商,或者接的那家被 disabled_providers 关掉了敲 /connect;已经接过就用 opencode auth list 确认;再确认配置里没把它列进禁用清单
一直报认证失败Key 前后带了空格;或者 {env:…} 引用的变量根本没设(没设不会报错,只会变成空串)重新粘一次 Key;用 echo $ANTHROPIC_API_KEY 这类命令确认变量真的有值
提示模型名不存在拼错了 provider/model 里的任一半用 opencode models 把准确的名字打出来,照抄;刚上新模型时加 --refresh
公司网络下连不上要走代理或自建网关在 provider.<名字>.options.baseURL 里换成你的地址

第三类:用起来不对劲

症状真实原因怎么办
它不懂我项目的习惯,答得笼统没跑 /init,项目里没有 AGENTS.md跑一次 /init 并把它提交进 Git;规则分散时用 instructions 汇总(见 14)
让大模型干杂活,账单涨得快主模型和"起标题"这类小事共用了一个贵模型配 small_model 指一个便宜模型;机械劳动时用 F2 临时切到小模型
对话越长它越笨、越慢上下文快满了。它每次都要把整段历史重新读一遍先用 /compact 压一次;话题已经换了就直接 /new。任务告一段落时 /new 比 /compact 更划算——后者本身就是一次大请求
说了半天它还是找错文件没给上下文,它在靠猜用 @ 把该看的文件点出来;要它先看现场就用 !命令(见 17)
它说"找不到某个文件"grep / glob 底层是 ripgrep,默认遵守 .gitignore,被忽略的文件它也看不到在项目根建 .ignore,用 !node_modules/ 这种写法放开要搜的路径

最后两条:没有报错,但已经在出血

🚨 坑 A:它在改你的文件,而你没意识到

默认权限是全放行的。这意味着从你敲完第一句话起,它就可能已经在动你的源码,而且不会有任何提示。三个可靠的症状:你不确定它刚才改了什么、git status 里出现了你没写过的改动、或者它在 Build 模式下"顺手"改了别的东西。
修法:进生产项目前,在项目根目录的 opencode.json 里写 {"permission": {"bash": "ask", "edit": "ask"}}。之后养成一个习惯——每次让它改完,先 !git diff 看一眼再继续。

🚨 坑 B:权限规则写反了,等于没配

官方规则是"最后一条匹配的赢"。所以下面这两种写法的效果正好相反:

# ❌ 反了:git push 会命中后面那条 "*",结果所有命令都是 ask
"bash": { "git push *": "deny", "*": "ask" }

# ✅ 对了:把兜底的 "*" 放前面,具体规则放后面
"bash": { "*": "ask", "git status *": "allow", "git push *": "deny" }

另一个同源的坑:写 "git status" 挡不住带参数的命令,因为匹配的是解析后的完整命令(比如 git status --porcelain)。要挡住带参数的写法,得写 "git status *"。

排错:先跑这三条命令

出问题时不要凭感觉猜,先把机器上的事实读出来。这三条覆盖了绝大多数情况:

# 1. 版本对不对(也是确认 PATH 通不通)
opencode --version

# 2. 到底接了哪几家提供商
opencode auth list

# 3. 当前这份配置最终解析成了什么(能看出哪一层盖掉了哪一层)
opencode debug config

# 附:想看它把请求发去哪、报了什么,就把日志级别压到 DEBUG
opencode --print-logs --log-level DEBUG

# 附:怀疑是插件在捣乱时,用"纯净模式"跑一次(不加载外部插件)
opencode --pure
💡 排查配置问题时的一个诀窍

配置是八层合并的,所以"我明明写了对的"和"它就是没生效"可以同时为真。opencode debug config 会把合并之后的结果打印出来——托管配置的键也会出现在里面(官方文档里就举了这个例子)。所以怀疑配置没生效时,别看源文件,看这个输出。

17成对示例:同一件事的两种问法

同一件事,两种说法,结果的差距通常不是"它聪明不聪明",而是你有没有把它需要的东西放到它面前。下面四对都是可以直接对照的。

第一对:修一个 bug

❌ 没有上下文、没有验证方式
帮我修复这个 bug

它会怎么做:先问你是哪个 bug,或者自己去猜一个。你花在来回澄清上的时间,通常比多打两行字更贵。

✅ 引用文件 + 复现现象 + 验收标准
@src/auth.ts 的 login 函数在空密码时不报错。
!npm test -- auth.test.ts
先看失败信息,再改 login,不要改测试。

它会怎么做:直接读文件、看测试输出、改实现,而且知道"不能靠改测试让它变绿"。

第二对:让它改代码但别乱改

❌ 范围没封边
把这个项目里的 class 组件都改成函数组件

问题在哪:范围是整个项目,它可能改几十个文件、动到测试和样式,而你要的是"先看一下它理解得对不对"。而且这种规模你没法一口气审完 diff。

✅ 先在一个文件上验证理解
先只改 @src/components/UserCard.tsx 这一个文件,
按函数组件 + hooks 重写,其他文件先别动。
改完告诉我你做了哪几处等价变换。

好在哪:一个文件的 diff 你能三分钟看完,而且"告诉我做了哪几处变换"这句会迫使它把隐含判断说出来——判断错了你当场就能发现。

第三对:问它"为什么"

❌ 把命令输出留在自己脑子里
我的构建为什么这么慢?

它会怎么做:只能给一堆通用的可能性清单。它看不到你的构建到底慢在哪一步。

✅ 把现场贴进去
!npm run build --profile
上面是我们项目的构建输出,最慢的三步是哪些?
只分析这三个,不要重写构建配置。

好在哪:它回答的是你项目的事实,不是通用建议。"不要重写构建配置"这句同时挡住了它的过度热情。

第四对:权限

❌ 用默认权限跑生产项目
# 什么也不配 = 所有操作都不问就执行
# 它可能直接跑 git push、跑迁移脚本

风险在哪:不是"它会故意搞破坏",而是它理解错了需求、或者顺手多做了几步——而这几步在默认权限下不会有任何拦截。

✅ 把闸门关到"能过目"的程度
{
  "permission": {
    "*": "ask",
    "read": "allow",
    "bash": {
      "*": "ask",
      "git push *": "deny"
    }
  }
}

好在哪:读还是放开的,所以它照样能理解项目;但"改"和"跑命令"都要你点头,而"推代码"根本轮不到它做。

把好写法归纳成一张模板

四对看下来,会发现"好"的那一栏总是同四样东西。它不是提示词工程,就是把任务说清楚的常识:

要素它回答什么怎么写
目标我要什么结果一句话说清是"修好""加上""解释"还是"只出方案"
上下文它该看哪些材料@文件 指出该看的代码;!命令 把当前现场贴进去
约束哪些事不许做"不要改测试""只改这一个文件""不要重写构建配置"
产出格式结果长什么样"列出来""按文件:行 · 问题 · 为什么危险 · 怎么改"
📖 一个诚实的分界

这套模板能大幅降低"它跑偏"的概率,但它不能保证结果正确。模型会答错、会在长对话里忘记前面的约束、会自信地编出一个不存在的函数名——所以"改完 !git diff 看一眼"和"关键改动自己跑一遍测试"这两件事没有替代品。把 OpenCode 当成一个产出很快、但需要验收的合作者,比当成一个可信赖的自动机器更接近事实。

18什么时候别用它

这一节不属于开头(开头该给的是"怎么用"),但它确实该存在——因为它决定你会不会在错误的地方浪费一周。

五件它不适合的事

场景为什么不适合更合适的做法
代码不能离开你的机器,而你又不想跑本地模型模型调用是把上下文发到提供商的服务器上;联网搜索类工具还有额外的外部依赖接本机的 Ollama / LM Studio;或者用 permission 把 webfetch、websearch 直接 "deny"
你只想"敲字时有个补全"它的交互模型是"你下达任务、它整段动手",不是逐字提示;为这个用途装它,反而多一个终端窗口要管继续用编辑器里的补全工具,两者可以并存
追求"完全无人值守地改对代码"它产出很快,但没有验收能力:它不知道你的业务规则,也不承担后果把它当"需要验收的合作者":改完看 diff、跑测试;关键路径上留人工过目
在一个没有 Git 的目录里指望能回滚/undo 和 /redo 的内部实现依赖 Git,项目不是仓库时这两个命令不工作先 git init 并做一次初始提交;或者严格用 Plan 模式,只让它出方案
临时跑一次、又不想装东西它是个本地程序,装了才有;虽然有 Docker 那条路,但那也要能拉镜像用 docker run -it --rm ghcr.io/anomalyco/opencode,或者干脆用你已有的工具

它和"直接问模型"的分工

这一条能帮你省订阅费,也能帮你省时间:

✅ 交给 OpenCode

要读你项目里好几个真实文件才能回答的问题;要真的改文件、跑命令、看输出的活;批量的机械改动;需要反复"改—跑—看结果"的循环。

📖 交给普通对话

问一个和你的代码库无关的技术概念;让它解释一段你随手贴过去的小代码;写一段通用正则或 SQL;讨论方案但不需要它读仓库。这些不需要"手和脚",用带项目上下文的代理反而更绕。

⚠️ 三样东西别省

① 别省 diff 的眼睛——它是产出工具,不是审查工具;② 别省权限配置——默认全开是为了让你上手快,不是让你长期这么用;③ 别省密钥的隔离——用 {env:…} 或 {file:…},别把 Key 直接写进要提交进 Git 的 opencode.json。顺带一提,.env 系列文件默认就在 read 权限的拒绝清单里,这是官方给你的默认保护,别把它打开。

19术语对照表

下面这十七个词在文中反复出现。第三列不是翻译,是"它在整套体系里为什么重要、以及别拿它当什么用"——同一个词用错地方,往往就是一次配置事故。

术语用日常语言说是为什么重要 / 何时用 · 别当什么用
编程代理(coding agent)能自己读代码、改代码、跑命令的 AI 程序,不只是给建议OpenCode 的核心定位。它的产出是"改好的文件",所以你把话当"下任务"说,而不是当"提问"说。别当补全插件用——它的价值恰在"会自己动手",你只想补全就不需要它
斜杠命令(slash command)在输入框里敲 / 开头触发的命令,如 /init这些是"你操作工具"的开关,不是发给模型的话——所以 /undo 会撤销而不是让模型"撤销一下"。别在给模型的提示词里混用斜杠命令,正文里它不生效
TUI终端用户界面;就是敲 opencode 之后那个全屏窗口日常主界面,四块区域(顶部状态 / 中部消息 / 底部输入 / 右下角模式)。别把它当成"一堆命令行参数"——它是有输入框、有快捷键、有面板的完整应用
提供商(provider)卖"模型调用能力"的那家公司或服务,比如 Anthropic、OpenCode Zen、你本机的 Ollama换提供商意味着换账单、换 Key、可能换模型清单。别和"模型"混为一谈——同一件货在不同店家那里价格和表现都可能不同
模型(model)真正做"思考"的那个大语言模型配置里写成 provider/model-id,斜杠前是店家、后面是货;换它就是换脑力和价钱。别以为"选了模型 = 装了模型"——它始终跑在提供商那边
主代理(primary agent)你正在对话的那个助手,内置有 Build 和 Plan用 Tab 轮换;它决定"这一轮用什么模型、带什么权限"。别在模糊需求下直接用 Build 让它乱改——先切 Plan 出方案,是省返工的关键分流
子代理(subagent)被主代理派去做专项活的小助手,内置有 General、Explore、Scout把"读一大堆文件"的脏活放到它自己的会话里干,只把结论带回来,从而让主对话的上下文保持轻量。别把需要主决策的事交给它——它看不到你们刚才的讨论
工具(tool)代理手上真正能操作项目的动作:读、改、写、搜、跑命令、抓网页……权限就是按工具配的(bash、edit、read……)。别把工具和权限混着说:工具是"它能做什么",权限是"允不允许它做"
权限(permission)给每个工具定的三档态度:放行 / 问你 / 禁止OpenCode 默认几乎全放行,所以这是唯一一道由你控制的闸。别当它是可选装饰——不配它,AI 就会在你没看的时候改文件、跑命令
AGENTS.md项目根目录里写给 AI 的"说明书"(类似 Claude Code 的 CLAUDE.md)用 /init 生成;它决定"AI 知不知道你项目的命令和约定"。别把历史备注和临时状态灌进去——这份文件每次会话都会被读一遍,写多了等于每次都在花你的上下文预算
MCPModel Context Protocol,给模型"接外部工具"的一套标准接口要接数据库、Jira、GitHub 这类外部能力时用;接上之后那些工具和内置工具一样出现在模型手里。别一次挂一堆——每个 MCP 服务器都往上下文里塞工具,官方点名 GitHub 那个特别占 token
LSP语言服务协议;让编辑器/工具能问"这个符号定义在哪、谁引用了它"让 AI"跳定义"而不是"翻全文找",在类型化语言的大项目里能明显减少读文件量。别以为它是必装项——OpenCode 里它是实验性工具,要显式开 OPENCODE_EXPERIMENTAL_LSP_TOOL=true
上下文窗口(context window)模型一次最多能读进去的文本量,有上限它解释了"为什么对话越长它越笨"——历史占满了,新的信息就挤不进去。别把"它忘了"理解成它变傻了:那是窗口满了,用 /compact 或 /new
Token模型读写文本的最小计量单位;大致可以理解成"一小段字",中文里常常一个字或两个字算一个它是计费和容量的共同单位:你付的钱按 token 算,模型的上下文上限也按 token 算。别拿"字数"估成本——代码和中文的 token 密度差很多
压缩(compaction)把一长段对话压成一份摘要,继续往下聊长会话续命时才值得花——它本身也是一次不小的请求。别把压缩当日常操作:话题已经换了,/new 开一段新的通常更省更干净
快照(snapshot)记录文件改动的一套内部机制,是 /undo 与 /redo 的底座"大胆让它改、错了能退"的前提。别以为它在任何目录都能用:它依赖 Git,项目不是仓库时这两个命令不工作。大仓库里它还可能有索引慢、占磁盘的问题,能关(关了就不能界面回滚)
前缀键(leader key)快捷键的"开场白":先按它,再按一个字母,两个键合起来才算一条OpenCode 默认是 Ctrl+X,文档里写成 <leader>;默认等 2000 毫秒。别单独按它就等结果——它自己什么都不做;不习惯就在 tui.json 的 keybinds 里换掉
确认弹窗(ask)权限设成"问你"之后弹出来的那个框,有三个选项:只批这一次 / 这一类都批 / 拒绝它是"你参与决策"的唯一入口,所以看清它写的命令再点。别顺手点"这一类都批"——那个批准只对当前这段会话有效,但覆盖的范围是"同一类模式"(比如所有 git status*),点错一次等于这段会话里这类命令全放行
📖 最容易混的三对,一句话记住

提供商 vs 模型:店家 vs 货。主代理 vs 子代理:跟你说话的 vs 被派出去的。AGENTS.md vs Plan 模式:前者让 AI"知道怎么做",后者让 AI"不许动手"——一个管脑子,一个管手。

20一页纸速查

这一节是留给你第二遍回来查的。不需要从头读。

装完到用顺:一份检查清单

#做这件事怎么知道做对了
1装上并确认命令可达opencode --version 吐出版本号(本文校对时是 1.18.30)
2接上一个提供商opencode auth list 能列出你接的那家
3在一个真实项目里初始化项目根目录多了一个 AGENTS.md,内容讲的是"命令 + 结构 + 约定"
4跑通一次只读问答你用 @文件 提问,它答的内容确实是那个文件里的东西
5走一遍 Plan → BuildPlan 里它先给你方案;切到 Build 说"开始"它才动手
6验证 /undo 真的能撤它改完之后 /undo,!git diff 回到改动前的状态
7把权限收紧opencode debug config 的输出里能看到你配的 "bash": "ask"
8把 AGENTS.md 交进 Git!git status 里它不在未跟踪列表里

按"我想做什么"查

第三列写清"在哪儿敲",因为其中有几条不是敲在 OpenCode 的输入框里的。

我想做什么敲什么在哪儿敲
装上curl -fsSL https://opencode.ai/install | bash系统终端
确认版本opencode --version系统终端
升级 / 卸载opencode upgrade / opencode uninstall系统终端
接提供商/connect(或 opencode auth login)TUI 里 / 系统终端
看接了哪几家opencode auth list系统终端
看有哪些模型opencode models(加 --refresh 刷新)系统终端
进项目cd 项目目录 然后 opencode系统终端
让 AI 认识项目/initTUI 输入框
引用文件@路径/到/文件.ts消息里
先跑个命令看现场!git status消息里
切开发 / 分析模式Tab / Shift+TabTUI 键盘
换模型/models,或 F2 在最近用过的之间切TUI
撤销 / 重做/undo / /redo(或 ctrl+x u / ctrl+x r)TUI
压上下文 / 开新会话/compact / /newTUI
切会话/sessions(别名 /resume、/continue)TUI
分享 / 取消分享/share / /unshareTUI
导出成 Markdown/exportTUI
看它跑了什么/detailsTUI
退出/exit(别名 /quit、/q)TUI
不用界面问一句opencode run "你的问题"系统终端
浏览器里用opencode web --port 4096系统终端
自己下了个会话文件想导入opencode import session.json系统终端
查配置到底解析成了什么opencode debug config系统终端
管 MCP 服务器opencode mcp add / opencode mcp list系统终端

四份配置模板,按需抄

下面四段覆盖了绝大多数人的实际需求。第一段是最该抄的那一份。

# ① 最小安全配置:读放开、改和跑命令要问、推代码直接禁
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "*": "ask",
    "read": "allow",
    "grep": "allow",
    "glob": "allow",
    "bash": {
      "*": "ask",
      "git status *": "allow",
      "git push *": "deny"
    }
  }
}

# ② 主模型 + 杂活模型分开,密钥走环境变量
{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-5",
  "small_model": "anthropic/claude-haiku-4-5",
  "provider": {
    "anthropic": {
      "options": { "apiKey": "{env:ANTHROPIC_API_KEY}" }
    }
  }
}

# ③ 一个只读的子代理(审查用,永远不改文件)
# 存成 ~/.config/opencode/agents/review.md,或用 /review 点名它
---
description: Reviews code for quality and best practices
mode: subagent
permission:
  edit: deny
  bash: ask
---
You are in code review mode. Focus on code quality, edge cases,
performance, and security. Provide feedback without direct changes.

# ④ 一条自定义命令:把"跑测试 + 只看失败 + 给建议"压成一个词
# 存成 .opencode/commands/test.md,然后敲 /test
---
description: Run tests with coverage
agent: build
---
Here are the current test results:
!`npm test`
Focus on the failing tests and suggest fixes.

99一句话总结

🎯 核心要点

OpenCode 是一个跑在终端里的开源编程代理——它本身不含智能,靠你 /connect 接上的提供商提供模型;你用 @ 把文件喂给它、用 ! 把现场贴给它、用 Tab 在 Plan 和 Build 之间切换来先出方案再动手、用 /undo 给自己留一条退路,而这一切的前提是先把默认全开的权限关到"改东西要问你"。

98参考来源与证据边界

来源清单

本文的每条事实都对着下面这些一手来源核过。日期栏写的是抓取时页面上标注的"最后更新"或接口返回的时间。

来源用它核了什么抓取日
github.com/anomalyco/opencode仓库描述原话、许可证、Star 数、贡献者页数、默认分支与提交数2026-09-12
GitHub Releases API(最新版)版本号 v1.18.30、发布日期 2026-09-09、该版更新内容2026-09-12
npm registry:opencode-ainpm 上的最新版本号(与 GitHub release 一致)2026-09-12
opencode.ai/docs(Intro)安装方式全清单、Prerequisites、/connect 三步、Plan/Build 与 /undo 的官方叙述2026-09-10 页脚标注
docs/tui全部斜杠命令与各自别名、/undo 依赖 Git 的原话、tui.json 全部选项与默认值、EDITOR 设置2026-09-10 页脚标注
docs/cliCLI 子命令与 flag、upgrade/uninstall 的 flag、环境变量全表(含 Experimental 一节)2026-09-10 页脚标注
docs/keybinds默认键位:<leader>u/<leader>r、f2、tab、子会话的 ↓/→/←/↑ 等具体映射2026-09-10 页脚标注
docs/config八层优先级的确切顺序、合并语义、常用配置项与默认值、{env:}/{file:} 替换、托管配置路径2026-09-10 页脚标注
docs/permissions三档动作、十四个权限键、通配符与「最后匹配者胜」、--auto 的边界、doom_loop 与 external_directory 的默认值2026-09-10 页脚标注
docs/agents主代理/子代理的类型定义、五个内置代理的定位、三个隐藏系统代理、全部 Agent 选项与 steps/maxSteps 的废弃说明2026-09-10 页脚标注
docs/tools全部内置工具清单与各自权限键、ripgrep 与 .ignore 的行为、websearch 的前置条件、LSP 工具的开关2026-09-10 页脚标注
docs/mcp-serverslocal/remote 两种类型与全部字段、超时默认 5000ms、OAuth 自动处理、上下文占用的官方提醒2026-09-10 页脚标注
docs/rulesAGENTS.md 的官方示例、四处查找位置与优先级、/init 的行为、Claude Code 兼容与三个开关变量2026-09-10 页脚标注
docs/references引用别名的字段表、别名命名限制、Git 引用异步刷新、引用与外部目录权限的关系2026-09-10 页脚标注
docs/commands自定义命令的两种写法、$ARGUMENTS/$1、!`命令`、@文件 三种占位语法2026-09-10 页脚标注
docs/providers「通过 AI SDK 与 Models.dev 支持 75+ 提供商」原话、凭证文件位置、baseURL/blacklist/whitelist 的用法2026-09-10 页脚标注
docs/zen「只有少数模型适合当编程代理」的原话、Zen 的三步建立理由、模型与端点清单2026-09-10 页脚标注
docs/web · docs/share · docs/ideweb 的 hostname/密码注意点、分享链接的公开性原话与三种模式、IDE 扩展的自动安装与排错步骤2026-09-10 页脚标注

证据边界:哪些地方我核不到一手来源

时效说明

本文的档案是 tool、时效标记是 evolving(演进型),校对日期 2026-09-13,版本锚点是 anomalyco/opencode v1.18.30(2026-09-09 发布)。这个项目迭代很快——光是在我核对的那一天,默认分支就有新提交。所以下面这几类内容最可能先过期,请以官方源为准:

📖 自己复核本文的一手方法

三条命令就能把本文最核心的事实自己验一遍(这是全文唯一需要你自己动手的判据):

# 1. 版本锚点是不是真的
curl -sSL https://registry.npmjs.org/opencode-ai/latest | python3 -c "import json,sys;print(json.load(sys.stdin)['version'])"

# 2. hero 里的仓库数字
curl -sSL https://api.github.com/repositories/975734319 | python3 -c "import json,sys;d=json.load(sys.stdin);print(d['full_name'],d['stargazers_count'],d['license']['spdx_id'])"

# 3. 斜杠命令清单的原页面
curl -sSL https://opencode.ai/docs/tui/ | grep -o '/themes' | head -1

第 3 条用的是最糙的抓法(直接在 HTML 里搜字符串),够用来判断"这个命令还在不在文档里"。想更准就打开那个页面自己看命令列表。

⌂