OpenCode v2 团队治理实战:多仓库 Policy、灰度发布与故障回滚
这是《OpenCode v2 实战:从零搭建企业级 AI 编程助手》专题第 12 篇。上一篇建立了 Token、质量、可靠性和 ROI 的可观测闭环;本篇把视角从"看清一次运行"提升到"长期运营整个平台",解决多仓库配置漂移、组织级 Policy、变更评审、版本发布、灰度升级与故障回滚。
一个开发者在一个仓库里把 OpenCode 调顺,并不等于团队已经拥有 Agent 平台。人数和仓库数量一旦增长,真正困难的问题会迅速浮现:为什么同一条命令在两个项目中的权限不同?谁能批准新 Provider、新 MCP 和新 Plugin?项目能不能覆盖组织的安全底线?升级后如何知道质量下降来自模型、配置还是客户端?出现问题时,究竟回滚二进制、配置、集成,还是业务仓库?
本文会完成八件事:
- 建立系统、用户、仓库和 Agent 四层治理模型;
- 设计适用于单仓库、Monorepo 和多仓库组织的配置结构;
- 分清 Permissions 与 Policies 的职责、匹配和优先级;
- 给出 Provider、工具、MCP、Skill 与 Plugin 的组织级基线;
- 把配置当成供应链制品,完成评审、测试、版本和发布;
- 设计观察、试点、扩展和全量四个灰度环;
- 建立二进制、配置、集成和会话四类回滚手册;
- 用审计证据和演练把治理从文档变成持续能力。
一、团队治理不是"复制一份配置"
1. 从个人工具到共享控制面
个人使用时,配置的主要目标是顺手;团队使用时,配置同时承担安全边界、成本边界和交付标准。一个看似普通的模型或插件变更,可能影响:
- 哪些代码和文档会被发送到哪个 Provider;
- Agent 能否读取仓库外目录、执行 Shell、调用 MCP;
- CI 中是否会因为等待授权而卡住;
- 生成结果能否复现,历史会话能否解释;
- 故障时能否在分钟级恢复到已知稳定版本。
因此,团队治理的对象不只是 opencode.jsonc,而是一条完整控制链:
text
组织安全底线
→ 机器级受管配置
→ 用户通用偏好
→ 仓库与子目录配置
→ Agent 专属权限
→ Console 下发策略
→ 运行证据与审计
每层都应有明确所有者、变更入口、测试方法和回滚目标。
2. 先区分"建议""默认值"和"硬约束"
很多治理失败,是因为把三类规则混在一起:
| 类型 | 示例 | 应放位置 | 项目能否调整 |
|---|---|---|---|
| 建议 | 推荐 Prompt、参考 Skill | 文档、模板、示例仓库 | 可以 |
| 默认值 | 默认模型、格式化、上下文预算 | 用户或仓库配置 | 可以按边界覆盖 |
| 硬约束 | 禁止外部 Provider、禁止推送、禁止敏感目录读取 | 系统/Console Policy | 不可以 |
如果把所有内容都做成硬约束,开发者会绕开平台;如果把安全底线只写成建议,关键限制迟早被某个仓库覆盖。治理的核心不是规则越多越好,而是让规则强度与风险一致。
3. 定义四类责任人
最小可运行的责任模型可以是:
text
平台团队:维护客户端版本、系统配置、组织 Policy 和发布工具
安全团队:审批 Provider、外发边界、高风险工具与保留策略
仓库维护者:维护项目 Instructions、Agent、命令、测试和局部权限
使用者:选择任务、确认 ask 请求、反馈质量与异常
同一个人可以兼任多个角色,但每类决策仍要有清晰身份。否则出现事故时,只能得到一句"这份配置不知道是谁改的"。
二、先吃透 OpenCode v2 的配置层级
1. 四类配置来源
OpenCode v2 支持系统、用户、项目和 .opencode 目录配置。常见位置如下:
text
系统级
macOS: /Library/Application Support/opencode
Linux: /etc/opencode
Windows: %ProgramData%\opencode
用户级
~/.config/opencode/opencode.jsonc
项目级
<repo>/opencode.jsonc
<repo>/.opencode/opencode.jsonc
系统目录除 opencode.json(c) 外,还能为机器上的用户加载 agents/、commands/、skills/ 和 plugins/。这使它适合承载受管基线,但也意味着一次系统级变更可能影响整台机器,必须经过更严格的发布流程。
2. 普通设置是"就近覆盖"
OpenCode 从当前目录向文件系统根目录查找配置。普通设置的总体原则是:更接近项目的配置覆盖更宽泛的配置,但系统受管配置优先级最高。
假设从 acme/packages/web 启动:
text
~/.config/opencode/opencode.jsonc
acme/opencode.jsonc
acme/packages/web/opencode.jsonc
%ProgramData%/opencode/opencode.jsonc
对同名普通设置,web 可覆盖仓库根配置,仓库可覆盖用户配置,而系统设置最终覆盖它们。不同键会合并保留,不是简单用整份文件替换另一份文件。
3. .opencode 与直接配置不要混用
同一目录树里,OpenCode 先合并直接放置的 opencode.json(c),再合并各级 .opencode/opencode.json(c)。全部 .opencode 配置都会覆盖直接配置。
因此团队最好选择一种约定:
text
方案 A:仓库根只放 opencode.jsonc,其他资产放 .opencode/
方案 B:配置和资产全部收拢到 .opencode/
除非有明确设计,否则不要在多级目录同时混用两种形式。否则维护者看到"更近的文件",却可能因为加载阶段不同而误判实际结果。
4. Policy 的优先级方向相反
普通设置强调项目定制;Policy 强调上级权威。官方文档给出的 Policy 权威顺序从高到低是:
text
连接的 OpenCode Console 工作区
> macOS Managed Preferences
> 系统 opencode.json(c)
> 用户全局 opencode.json(c)
> 各级直接 opencode.json(c)
> 各级 .opencode/opencode.json(c)
这意味着仓库不能重新开启被组织或系统禁止的 Provider、工具或集成。理解这个"反向优先级",是排查"明明项目写了 allow,为什么仍被拒绝"的第一步。
三、多仓库配置应该怎样分层
1. 用三层模型避免复制漂移
推荐把配置拆成三层:
text
L1 组织基线:Provider 白名单、硬拒绝、系统 Agent、审计插件
L2 领域基线:语言栈、构建命令、代码规范、共享 Skill
L3 仓库配置:项目说明、局部 Agent、测试命令、允许目录
L1 由平台和安全团队维护,变化最慢;L2 由领域负责人维护;L3 由仓库维护者评审。不要让每个仓库复制完整 L1,因为复制后的规则不再是基线,而是一批会逐渐分叉的快照。
2. 组织基线只放跨项目不变量
Windows 机器上的系统配置可以保持克制:
json
{
"$schema": "https://opencode.ai/config.json",
"update": "notify",
"policies": [
{ "action": "provider.use", "resource": "*", "effect": "deny" },
{ "action": "provider.use", "resource": "company-ai", "effect": "allow" },
{ "action": "tool.use", "resource": "shell:git push *", "effect": "deny" },
{ "action": "tool.use", "resource": "read:*/.ssh/*", "effect": "deny" },
{ "action": "integration.use", "resource": "mcp:*", "effect": "deny" },
{ "action": "integration.use", "resource": "mcp:github", "effect": "allow" }
]
}
示例中的 Provider 和 MCP 名称是占位符。组织基线的目标是守住边界,而不是替每个项目决定格式化器、默认 Agent 或业务测试命令。
3. 仓库配置描述项目事实
仓库配置适合提交到 Git,让代码和 Agent 行为一起评审:
json
{
"$schema": "https://opencode.ai/config.json",
"default_agent": "build",
"formatter": true,
"instructions": [
"CONTRIBUTING.md",
"docs/architecture/*.md"
],
"commands": {
"verify": {
"description": "Run repository verification",
"template": "Run the documented checks and summarize failures with evidence."
}
}
}
项目文件中不要放长期凭据,也不要假装用项目级 allow 去突破组织级 deny。如果业务确实需要例外,应修改更高层策略并留下审批记录。
4. Monorepo 用目录边界表达差异
Monorepo 可以在仓库根定义公共行为,在子项目定义局部差异:
text
acme/
├── opencode.jsonc
├── AGENTS.md
├── packages/
│ ├── api/
│ │ ├── opencode.jsonc
│ │ └── AGENTS.md
│ └── web/
│ ├── opencode.jsonc
│ └── AGENTS.md
└── .opencode/
├── agents/
├── commands/
└── skills/
根配置保留公共模型、共享命令和仓库级说明;子目录只写差异。每个子项目都复制整套配置,会让一次基线修改变成几十个 PR。
5. 多仓库共享资产要有发布边界
跨仓库共享的 Skill、Command 或 Agent 可以放在独立平台仓库,但业务仓库不应无版本地追踪其 main 分支。推荐发布不可变版本:
text
agent-platform-config/
├── releases/
│ ├── 2026.10.0/
│ └── 2026.10.1/
├── schemas/
├── tests/
└── CHANGELOG.md
业务仓库或部署系统引用明确版本,平台再通过自动 PR 或受管发布逐步升级。这样回滚目标是一个确定制品,而不是"昨天那个差不多能用的目录"。
四、Permissions 与 Policies 必须各司其职
1. Permission 是 Agent 的运行规则
Permissions 控制 Agent 对资源执行动作时是 allow、deny 还是 ask。如果没有规则匹配,OpenCode 使用 ask。同一层规则按顺序匹配,最后一个匹配项生效:
json
{
"permissions": [
{ "action": "shell", "resource": "*", "effect": "ask" },
{ "action": "shell", "resource": "git status *", "effect": "allow" },
{ "action": "shell", "resource": "git diff *", "effect": "allow" },
{ "action": "shell", "resource": "git push *", "effect": "deny" }
]
}
它适合表达"这个 Agent 日常怎样工作":读哪些目录、能否编辑、哪些 Shell 命令免确认、哪些动作必须询问。
2. Policy 是不可绕过的硬护栏
Policies 只有 allow 和 deny,不会弹出确认框。它能控制三类动作:
| Policy action | 控制对象 | 资源示例 |
|---|---|---|
provider.use |
Provider 是否可用 | openai、company-ai |
tool.use |
某次权限检查是否被硬拒绝 | shell:git push * |
integration.use |
MCP、Skill、Plugin 是否加载 | mcp:github、skill:release |
Policy 的 allow 不是授权工具执行,而只是解除更早的广泛 deny;解除后仍由 Agent Permission 决定允许、询问还是拒绝。
3. 两层规则组合起来才安全
一个常见组合是:
text
Permission:git push → ask
Policy: git push → deny
最终结果: deny,不弹窗
即使用户以前选择过 "Allow always",Policy 的硬拒绝仍会覆盖保存的批准。组织底线应该放 Policy;需要人在任务现场判断的动作,才适合放 ask。
4. 通配符没有"越具体越优先"
Permissions 与同一文件内的 Policies 都采用整值通配符,* 匹配零个或多个字符,? 匹配一个字符;多个匹配项中最后一个生效,没有"更具体的模式自动胜出":
json
{
"policies": [
{ "action": "provider.use", "resource": "*", "effect": "deny" },
{ "action": "provider.use", "resource": "company-ai", "effect": "allow" }
]
}
顺序反过来就会把例外再次覆盖。评审工具必须检查顺序,不应只检查是否存在某条规则。
五、设计组织级 Policy 基线
1. Provider 采用默认拒绝
Provider 决定代码和上下文流向哪里,适合使用白名单:
json
{
"providers": {
"company-ai": {
"package": "@opencode/ai/providers/openai-compatible",
"settings": {
"baseURL": "https://ai-gateway.example.invalid/v1"
}
}
},
"policies": [
{ "action": "provider.use", "resource": "*", "effect": "deny" },
{ "action": "provider.use", "resource": "company-ai", "effect": "allow" }
]
}
示例域名故意使用无效保留域。真实端点和凭据应由受管环境注入,不要提交进仓库。Policy 只决定能不能用,并不会配置端点或让缺少凭据的 Provider 变得可用。
2. 高风险工具使用硬拒绝
Shell 拥有宿主用户的文件、进程和网络权限,命令文本的目录推断只能尽力而为。组织级硬护栏应优先拒绝明确不可接受的动作:
json
{
"policies": [
{ "action": "tool.use", "resource": "shell:sudo *", "effect": "deny" },
{ "action": "tool.use", "resource": "shell:git push *", "effect": "deny" },
{ "action": "tool.use", "resource": "read:*/.ssh/*", "effect": "deny" },
{ "action": "tool.use", "resource": "edit:*.env", "effect": "deny" },
{ "action": "tool.use", "resource": "external_directory:*", "effect": "deny" }
]
}
不要试图列举世界上所有危险 Shell 命令。更可靠的做法是缩小 Agent 允许的命令集合,并用 Policy 封死组织明确禁止的边界。
3. 集成按来源和能力审批
MCP、Skill 和 Plugin 都能扩展 Agent,但风险不同:
json
{
"policies": [
{ "action": "integration.use", "resource": "mcp:*", "effect": "deny" },
{ "action": "integration.use", "resource": "mcp:github", "effect": "allow" },
{ "action": "integration.use", "resource": "skill:*", "effect": "deny" },
{ "action": "integration.use", "resource": "skill:code-review", "effect": "allow" },
{ "action": "integration.use", "resource": "plugin:unreviewed-package", "effect": "deny" }
]
}
审批至少要回答:代码来自哪里、版本是否固定、会访问哪些资源、是否产生外部副作用、失败能否安全重试、日志是否可能携带敏感数据。
4. Console 适合做组织最终裁决
连接 OpenCode Console 工作区后,组织策略会追加在所有本地 Policy 之后,因此拥有最终决定权。官方行为包括:
text
Console 策略变化:下一次拉取时生效,通常约一分钟
切换工作区:替换为新工作区策略
断开连接:清除该连接下发的策略
Console 暂时不可达:保留该连接最后一次策略
"不可达时保留最后策略"有利于故障期间继续守住边界,但也要求平台记录最后成功同步时间,并监控长期未更新的客户端。
六、把配置当成供应链制品
1. 一个发布必须能被唯一描述
不要只记录"已升级配置"。一次平台发布至少应包含:
json
{
"release": "2026.10.1",
"opencode": "approved-version",
"config_revision": "git-commit-sha",
"schema_revision": "downloaded-at-build-time",
"providers": ["company-ai"],
"integrations": {
"mcp:github": "approved-version",
"skill:code-review": "2026.10.0"
},
"created_at": "2026-10-25T00:00:00Z"
}
版本号、Commit、依赖版本和构建时间必须不可变。模型别名、远程 Skill 和插件包如果会变化,也要记录解析后的实际版本。
2. 发布仓库与业务仓库分离
一种清晰结构是:
text
agent-platform/
├── managed/
│ ├── windows/opencode.jsonc
│ ├── linux/opencode.jsonc
│ └── macos/opencode.jsonc
├── agents/
├── commands/
├── skills/
├── policies/
├── tests/
├── release-manifest.json
└── CHANGELOG.md
平台仓库负责生成和验证受管制品;业务仓库只保存与自身有关的说明和局部配置。这样组织底线不依赖数百个业务仓库同步合并。
3. 构建时固定 Schema 并验证
OpenCode 官方配置 Schema 位于 https://opencode.ai/config.json。可以在发布流水线中下载、固定摘要并验证所有 JSON 配置:
powershell
$schemaPath = Join-Path $env:TEMP 'opencode-config-schema.json'
Invoke-WebRequest 'https://opencode.ai/config.json' -OutFile $schemaPath
npx --yes ajv-cli validate --spec=draft2020 -s $schemaPath -d '.\managed\**\opencode.json'
Get-FileHash $schemaPath -Algorithm SHA256
JSONC 需要先用稳定解析器转换为 JSON 再校验。Schema 校验只能发现字段、类型和结构问题,不能证明规则顺序、权限边界和业务行为正确。
4. 制品 promotion 优于现场编辑
推荐的发布链路是:
text
Git PR
→ 静态校验
→ 语义测试
→ 沙箱端到端测试
→ 生成不可变制品
→ 观察环
→ 试点环
→ 扩展环
→ 全量环
同一个制品逐环提升,不要在每个环境重新打包。否则测试通过的内容和最终上线内容可能不是同一份。
七、变更评审必须检查语义
1. PR 模板先问影响面
每个变更至少填写:
text
变更类型:客户端 / 配置 / Policy / Provider / MCP / Skill / Plugin / 模型
影响对象:操作系统、团队、仓库、Agent、CI
新增能力:读取、编辑、Shell、网络、外部副作用
兼容性:是否改变默认模型、事件结构、权限 action 或配置字段
观测指标:成功率、验证通过率、P95 耗时、单任务成本、安全拒绝
停止条件:达到什么阈值立即暂停
回滚目标:上一个稳定版本及恢复步骤
没有停止条件和回滚目标的"灰度",本质上只是分批冒险。
2. 静态检查找结构错误
静态检查至少包括:
- JSON/JSONC 可以解析,且通过官方 Schema;
- Policy 的 action、effect 和 resource 合法;
- broad deny 位于例外 allow 之前;
- 仓库中没有密钥、令牌、真实用户目录和内网凭据;
- Plugin、Skill 与 MCP 版本没有无约束漂移;
- 变更清单和发布清单一致。
可以把敏感信息扫描作为阻断门禁:
bash
git diff --cached --check
gitleaks protect --staged --redact
工具名称只是示例,关键是失败必须阻止制品 promotion,而不是在发布后发一封提醒邮件。
3. 语义测试验证最后匹配规则
Policy 的风险通常不在 JSON 语法,而在顺序和优先级。测试应构造明确的输入输出矩阵:
yaml
cases:
- resource: provider:company-ai
expected: allow
- resource: provider:public-provider
expected: deny
- resource: shell:git status --short
expected: permission-layer
- resource: shell:git push origin main
expected: hard-deny
- resource: integration:mcp:github
expected: allow
- resource: integration:mcp:unknown
expected: deny
测试实现可以是平台自己的 Policy 解析器,也可以在隔离环境中驱动真实 OpenCode。最终至少要有一组端到端测试,避免自研解析器与产品行为不一致。
4. 端到端测试覆盖允许与拒绝路径
只测"正常生成一段代码"远远不够。推荐覆盖:
text
允许路径:读取普通源文件、执行只读 Git、运行测试、加载批准 Skill
询问路径:潜在写入、仓库允许但需要人工判断的动作
拒绝路径:外部 Provider、git push、敏感目录、未批准 MCP
恢复路径:服务重启、配置回退、Console 短时不可达
拒绝路径必须验证"确实拒绝且原因可解释",不能只验证进程返回非零。
八、版本兼容与发布纪律
1. 客户端、配置和集成分别版本化
一次运行至少涉及四个变化轴:
text
OpenCode 客户端版本
配置/Policy 版本
模型与 Provider 版本
MCP/Skill/Plugin 版本
把它们压成一个模糊的"平台版本",会让故障定位失去精度;完全独立升级,又会产生未经验证的组合。正确做法是分别记录版本,再用发布清单声明经过验证的组合。
2. 先建立兼容矩阵
最小矩阵可以是:
| 组合 | 客户端 | 配置 | 集成 | 状态 |
|---|---|---|---|---|
| Stable | N | P | I | 全量支持 |
| Canary | N+1 | P+1 | I | 小流量验证 |
| Fallback | N | P-1 | I-1 | 应急回退 |
矩阵不是承诺支持所有笛卡尔积,而是明确哪些组合经过测试。回滚路径也必须在矩阵中,不能等事故发生才第一次组合旧客户端和新配置。
3. 自动更新不适合无门禁生产环境
OpenCode v2 的全局 update 可设置为 disable、notify 或 auto。团队受管环境更适合 notify,由平台流水线评估后再发布:
json
{
"$schema": "https://opencode.ai/config.json",
"update": "notify"
}
官方文档还特别说明:自动安装不会重启已经运行的服务。也就是说,"文件已经升级"不等于"当前会话已经使用新版本"。发布验证必须记录进程重启和生效时间。
4. 破坏性变更单独发布
不要在一次版本中同时更换客户端、默认模型、Provider 路由和权限策略。理想拆分是:
text
Release A:只升级客户端,保持配置与模型不变
Release B:只升级配置 Schema 与 Policy
Release C:只切换默认模型或 Provider 路由
Release D:只升级 MCP/Skill/Plugin
拆分会增加发布次数,却显著缩小故障归因范围和回滚半径。
九、设计四环灰度发布
1. Ring 0:离线观察
先用历史任务和黄金样本做离线回放,不允许真实外部副作用:
text
输入:脱敏后的真实任务、固定 Commit、固定依赖
输出:计划、补丁、工具轨迹、测试结果、成本
比较:稳定版本 vs 候选版本
离线回放适合发现明显退化,但无法覆盖实时权限、网络和协作行为。
2. Ring 1:平台与志愿者试点
选择熟悉系统、能快速反馈的用户和低风险仓库。试点环境保留完整运行版本和错误证据,重点观察:
- 客户端是否启动,配置是否正确加载;
- Policy 是否按预期拒绝,是否出现意外放行;
- ask 数量是否突然增长,工作流是否被打断;
- 任务验证通过率和人工返工是否退化;
- 单任务 Token、耗时和失败重试是否异常。
3. Ring 2:按领域扩展
不要简单随机抽取 10% 用户。更有效的是按风险与技术栈选代表性样本:
text
Windows / macOS / Linux
单仓库 / Monorepo
前端 / 后端 / 数据 / 基础设施
交互式 TUI / CI 自动化
只读审查 / 可编辑构建 / 外部系统集成
每一类至少有真实流量,才有资格判断全量发布风险。
4. Ring 3:全量但保留熔断
全量发布不等于结束。至少在一个观察窗口内保留一键冻结和回退能力,并展示:
text
版本覆盖率
最后成功策略同步时间
运行成功率与验证通过率
P95/P99 耗时
单任务成本
权限 ask/deny 数量
未知副作用与安全告警
5. 用停止条件代替主观感觉
示例停止条件如下,真实阈值应基于团队基线:
yaml
halt_when:
security_bypass: "> 0"
unknown_side_effect: "> 0"
validation_pass_rate_drop: "> 5 percentage points"
p95_latency_increase: "> 25%"
cost_per_verified_task_increase: "> 20%"
permission_prompt_increase: "> 50%"
触发后先冻结扩大范围,再判断回滚哪一层。不要因为"已经发布到 70%"而继续推进。
十、故障回滚必须分层
1. 先判断故障属于哪一层
回滚对象通常有四类:
text
二进制:客户端崩溃、命令或事件格式不兼容
配置:加载失败、默认值错误、上下文或工具行为变化
集成:MCP、Skill、Plugin 故障或权限扩大
模型/Provider:质量、延迟、成本、可用性或合规异常
如果只是某个 MCP 返回错误,回滚整个客户端会扩大影响;如果新客户端无法解析旧配置,只回滚配置也无法恢复。
2. 配置回滚使用不可变版本
推荐发布系统保留 current 与 previous 指针:
text
releases/
├── 2026.10.0/
├── 2026.10.1/
├── current -> 2026.10.1
└── previous -> 2026.10.0
回滚动作是把受管部署切回 previous,重新验证摘要并重启相关服务,而不是现场手工删除几行 JSON。回滚完成后还要验证实际运行版本,不要只看文件内容。
3. 集成故障优先隔离
当新集成异常时,可以先用组织 Policy 硬拒绝:
json
{
"policies": [
{ "action": "integration.use", "resource": "mcp:unstable-service", "effect": "deny" },
{ "action": "integration.use", "resource": "plugin:unstable-plugin", "effect": "deny" }
]
}
被拒绝的 MCP 或 Skill 会被移除,被拒绝的 Plugin 不会加载。隔离可以快速止血,但之后仍要回滚或修复制品,避免临时策略永久化。
4. 服务和会话状态要纳入回滚
OpenCode 的共享后台服务拥有会话、配置、集成、权限和工具执行状态。升级或回退文件以后,运行中的服务可能仍使用旧进程。回滚手册至少要包含:
text
1. 冻结灰度范围和新任务入口
2. 记录当前客户端、配置、策略与集成版本
3. 切换到已验证 fallback 制品
4. 重启共享服务或目标运行实例
5. 用允许、询问、拒绝三条探针验证
6. 恢复小流量并观察
7. 留存事故时间线和受影响任务
外部副作用结果未知时,不得盲目重放任务。先读取目标系统状态,再决定补偿或重试。
5. Console 故障按最后策略运行
Console 暂时不可达时,连接对应的最后一组策略会继续生效。平台应同时监控两件事:策略是否仍在执行,以及多久没有成功同步。短时保留是容错,长期静默则可能让客户端停留在过期规则。
十一、让每次变更都可审计
1. 发布证据比聊天记录可靠
每次 promotion 应自动生成证据包:
text
release-manifest.json
config-hashes.json
schema-hash.txt
policy-test-results.json
e2e-results.json
rollout-decision.md
rollback-target.json
证据包应关联 PR、审批人、Commit、构建任务和部署批次。不要依赖群消息中的"我看过了,可以发"。
2. 运行记录关联发布版本
上一篇建立的 task_id 和 run_id 应继续携带治理版本:
json
{
"task_id": "repo/pr/commit",
"run_id": "unique-run-id",
"opencode_version": "resolved-version",
"platform_release": "2026.10.1",
"config_revision": "git-commit-sha",
"workspace_policy_revision": "resolved-revision",
"model": "provider/model-id"
}
没有这些字段,质量下降时只能猜测是哪个变化造成的。
3. 审计内容也要最小化
治理不等于保存所有对话和文件。建议分层保留:
text
指标层:长期保留聚合指标,不含内容
事件层:保留工具、权限、状态和版本,限制访问
内容层:仅在必要场景保存,脱敏、加密并设置短保留期
凭据层:禁止进入普通日志和制品
既要能解释"为什么被允许或拒绝",也要避免审计系统变成新的敏感数据仓库。
十二、一个可落地的多仓库方案
1. 平台仓库负责生成受管包
平台流水线可以执行:
text
解析 JSONC
→ 官方 Schema 校验
→ Policy 顺序与资源检查
→ 敏感信息扫描
→ 真实 OpenCode 沙箱测试
→ 生成 release manifest
→ 打包并计算摘要
只有全部门禁通过才生成候选制品。
2. 业务仓库只声明局部能力
例如一个只读 Review Agent:
json
{
"$schema": "https://opencode.ai/config.json",
"agents": {
"reviewer": {
"description": "Review code without modifying the repository",
"mode": "subagent",
"system": "Focus on correctness, security, and missing tests.",
"permissions": [
{ "action": "edit", "resource": "*", "effect": "deny" },
{ "action": "shell", "resource": "git diff *", "effect": "allow" },
{ "action": "shell", "resource": "*", "effect": "deny" }
]
}
}
}
Agent 规则会追加在全局 Permission 后,但不会突破更高层 Policy。注意示例中最后一条广泛 Shell 拒绝会覆盖前面的 git diff 允许;正确顺序应将广泛规则放在前面、具体例外放在后面:
json
{
"permissions": [
{ "action": "shell", "resource": "*", "effect": "deny" },
{ "action": "shell", "resource": "git diff *", "effect": "allow" }
]
}
故意展示这个错误很重要:配置能通过 Schema,不代表语义正确。
3. CI 使用独立运行边界
CI 环境没有人回答 ask,因此要显式设计非交互权限,并避免与开发者桌面共用隐式批准。建议:
text
固定客户端与平台制品版本
使用独立凭据和最小权限 Runner
只允许任务需要的命令与目录
外部写入默认关闭
保存结构化事件、测试结果和版本清单
超时后终止,不自动重复未知副作用
CI 的成功标准是产出经过验证的制品,不是 Agent 最终打印了一段看起来正确的文字。
十三、Windows 团队的部署要点
1. 系统基线放在 ProgramData
Windows 系统目录是:
text
%ProgramData%\opencode
可以由企业软件分发系统部署 opencode.jsonc、agents/、commands/、skills/ 和 plugins/。部署前解析绝对路径,避免脚本把相对路径写到错误用户目录。
2. 先预检再原子替换
推荐部署过程:
text
下载候选包到临时目录
验证签名或制品摘要
解析全部配置
运行本机探针
保留当前包为 previous
原子切换 current
重启服务
再次运行探针
不要边下载边覆盖正在使用的目录。半套新文件与半套旧文件是最难诊断的状态。
3. 记录实际生效而不是分发成功
软件分发平台显示"安装成功",只说明文件或安装命令完成。真正的完成证据还包括:
opencode --version返回目标版本;- 系统配置文件摘要与发布清单一致;
- 共享服务已在切换后重启;
- Provider 白名单正确;
- 允许与拒绝探针结果正确;
- 运行记录携带新的平台发布版本。
十四、四类故障演练
1. 无效 Policy 被静默忽略风险
官方说明,无效 Policy statement 会被丢弃,其余列表继续生效,并在服务日志中记录警告。演练应故意放入错误字段,验证发布门禁能提前阻断,同时验证监控会捕获运行时警告。
2. 规则顺序导致意外放行
构造 broad deny 与 specific allow 的正反顺序,确认语义测试能发现差异:
json
{
"policies": [
{ "action": "provider.use", "resource": "company-ai", "effect": "allow" },
{ "action": "provider.use", "resource": "*", "effect": "deny" }
]
}
此配置最终仍会拒绝 company-ai。如果测试只检查"存在 allow",就会给出错误结论。
3. 仓库试图覆盖组织拒绝
在测试仓库写入与系统 Policy 相反的 allow,验证最终仍是拒绝,并且错误信息能指向配置策略或组织策略。这个演练可证明治理底线确实不可被项目绕过。
4. Console 不可达与策略过期
模拟短时断网,验证最后策略继续生效;再模拟超过允许陈旧时间,验证监控告警和升级冻结。恢复连接后,确认新策略被拉取并记录同步时间。
十五、30 天落地路线
第 1 周:盘点与分层
- 盘点客户端、配置、模型、Provider 和集成版本;
- 列出所有仓库中的重复与冲突规则;
- 将规则分类为建议、默认值和硬约束;
- 明确平台、安全、仓库和使用者责任;
- 建立第一个 Stable 组合和 Fallback 组合。
第 2 周:制品与门禁
- 建立平台配置仓库与发布清单;
- 接入官方 Schema、JSONC 解析和敏感信息扫描;
- 为 Policy 顺序、优先级和关键拒绝建立测试;
- 建立沙箱端到端允许/询问/拒绝探针;
- 自动生成摘要、版本和审计证据。
第 3 周:灰度与观测
- 建立离线、试点、扩展和全量四环;
- 把平台发布版本写入运行记录;
- 定义质量、成本、可靠性与安全停止条件;
- 部署策略同步陈旧度和版本覆盖率看板;
- 完成一次候选版本灰度。
第 4 周:回滚与演练
- 实现 current/previous 不可变制品切换;
- 编写二进制、配置、集成和 Provider 回滚手册;
- 演练无效 Policy、顺序错误、组织覆盖和 Console 中断;
- 验证服务重启与实际生效证据;
- 复盘恢复时间、证据缺口和人工步骤。
十六、上线检查清单
配置与权限
- 系统、用户、项目和
.opencode的职责已明确; - 团队理解普通配置与 Policy 的不同优先级;
- 组织底线使用 Policy,而不是可覆盖的项目 Permission;
- broad 规则与具体例外的顺序经过语义测试;
- 外部目录、敏感文件和高风险 Shell 有明确边界。
供应链与发布
- 客户端、配置、模型和集成分别记录版本;
- 官方 Schema 已固定摘要并用于构建校验;
- 制品不可变,同一制品逐环 promotion;
- PR 包含影响面、停止条件和回滚目标;
- 稳定、候选和回退组合都经过端到端测试。
灰度与回滚
- 离线、试点、扩展和全量环覆盖代表性工作流;
- 安全、质量、成本和延迟停止条件可自动判断;
- current/previous 切换不依赖现场编辑;
- 服务重启和生效探针是发布与回滚的一部分;
- 未知外部副作用不会被盲目重试。
审计与运营
- 每次运行携带平台、配置、策略和模型版本;
- 发布证据可关联 PR、Commit、审批和部署批次;
- Console 最后成功同步时间受到监控;
- 日志警告会捕获被丢弃的无效 Policy;
- 审计数据分层、脱敏并有保留期限。
十七、总结
OpenCode v2 的系统配置、项目配置、Permissions、Policies 和 Console 工作区共同提供了团队治理所需的基础能力,但这些能力不会自动组成平台。真正可持续的做法是把它们放进一条经过工程化设计的控制链:
text
把组织底线放进高权威 Policy
→ 把项目事实留在仓库配置
→ 把配置、集成和客户端做成版本化制品
→ 用 Schema、语义测试和端到端探针评审变更
→ 用四环灰度控制爆炸半径
→ 用停止条件触发冻结与分层回滚
→ 用运行版本、审计证据和故障演练持续改进
治理成熟度的标志,不是平台管理员能写出多复杂的 JSON,而是任何一次变更都能回答五个问题:谁批准的、影响谁、怎样验证、何时停止、如何恢复。
至此,《OpenCode v2 实战:从零搭建企业级 AI 编程助手》已经从安装、迁移、模型、客户端形态、Agent 权限、Skills、MCP、上下文、CI、可观测性一路走到组织治理。一个企业级 Agent 平台的闭环也由此形成:既能执行,又受约束;既能扩展,又可评审;既能度量价值,也能在错误发生时可靠恢复。
参考资料
- OpenCode v2 Config 官方文档
- OpenCode v2 Policies 官方文档
- OpenCode v2 Permissions 官方文档
- OpenCode v2 CLI 官方文档
- OpenCode v2 Troubleshooting 官方文档
本文依据 2026 年 10 月 25 日在本机 Edge 中核对的 OpenCode v2 官方文档整理。配置位置、优先级、Policy action、Console 同步行为和更新机制仍可能随版本演进;生产环境应以实际安装版本、官方配置 Schema、服务日志、官方文档和端到端测试为准。文中的组织名称、端点、版本、阈值和路径均为示例,不包含真实凭据或内部地址。