OpenCode Server 使用指南
术-操作 · 术层 skill 全文
本页是 <code>rules/skills/opencode_server_usage_guide.md</code> 的逐字投影(仅隐私清洗,零改写)。
时点提示:本页是仓内文件 rules/skills/opencode_server_usage_guide.md 的逐字投影(仅做隐私清洗:仓库根绝对路径→相对路径、家目录→~/;除此零改写)。若源文件后续有修订,以仓内真源为准。
Skill: OpenCode Server 使用指南
元数据
- 类型: API Guide
- 适用场景: OpenCode Server REST API 调试、
cli_agent的 OpenCode channel 维护、长驻 agent 编排、多 session 并发、跨模型 provider 路由(含国产模型和 Antigravity 免费层) - 前置条件:
opencode serve已通过 launchd 常驻(~/Library/LaunchAgents/com.opencode.server.plist),监听http://localhost:4096;OPENCODE_USERNAME/OPENCODE_PASSWORD在环境变量里(通常periodic_jobs/ai_heartbeat/.env) - 关键文件:
tools/cli_agent/router.py(生产 caller 入口)、periodic_jobs/ai_heartbeat/src/v0/opencode_client.py(OpenCode channel adapter 内部 wrapper)、tools/llm_runtime/providers.conf(provider/model/key/fallback 统一 registry)、~/.config/opencode/opencode.json(OpenCode 主 config) - 最后更新: 2026-07-18(tier 改名为 family-channel 形式,
opencode:canonical 名改glm-oc:,旧名仍可用;MiniMax provider 已从 opencode.json/config.json 清除)
什么时候用 OpenCode Channel(而不是 CC agent invocation)
生产脚本不要直接导入 OpenCodeClient。默认通过 tools/cli_agent/router.py 调用;OpenCode 只是 router 的一个 channel,失败时进入 claude-zai / claude-kimi / native Claude / Codex 等 fallback。
适合这些场景:
- 定时 cron 任务的首选 channel:observer、reflector、daily newsletter 等。server 常驻,零启动开销,3600 秒长 timeout 支持 agentic 任务
- 多 session 并发:一次扫多个目录(例如
library_observer.py对contexts/library/下每个子目录起一个 session),用 REST API 天然并发比起 N 个 CC 子进程更便宜 - 成本敏感的大吞吐任务:默认 tier 是
glm-oc:high(旧名opencode:high仍可用),真实模型由LLM_GLM_HIGH_MODEL决定 - 需要访问国产模型或 Antigravity 免费层:110 个 provider 打包,connected 的一批含
zai-coding-plan,googlevia Antigravity,kimi-for-coding,zhipuai-coding-plan,opencode等(MiniMax 相关 provider 已清除) - 长生成任务 + phase pipeline:daily_newsletter / ai_news_survey 这种 200 行 prompt、多阶段、需要派 subagent 的任务
不适合 OpenCode 的场景(应该走 CC agent invocation):
- 任务需要读 CC 自己的 JSONL 对话记录(OpenCode 看不到 CC 的状态)—— 典型反例
tools/ux_observer.py就是因为这个原因被标记为 deprecated - 需要 workspace
SessionStarthook 动态注入必读规则(OpenCode 的instructions字段是静态的且需要重启 server) - 一次性 ad-hoc 调研 / 代码编辑 / LLM-as-Judge(CC
claude -p的四种模式更成熟) - 需要 Anthropic 原生 Opus 深度推理(OpenCode 里
anthropicprovider 的 apiKey 是占位符,实际没接入)
术语澄清
OpenCode=opencodeCLI + 同一个二进制启动的 headless serverOpenCode Server=opencode serve启动的常驻 HTTP 服务,默认localhost:4096,工作区通过 launchdcom.opencode.server托管OpenCodeClient=periodic_jobs/ai_heartbeat/src/v0/opencode_client.py里的 Python wrapper 类,供CliAgentRouter的 OpenCode adapter 和低层诊断使用;生产 caller 走 router,不直接导入它oh-my-openagent= 一个 OpenCode plugin(原名oh-my-opencode,已 rename),通过 category 路由注入 18 个命名 agent(Sisyphus/Hephaestus/Metis/Prometheus/Atlas/Momus/librarian/explore/oracle 等希腊神话 +内建 build/general/plan/compaction/summary/title)Antigravity= Google 提供的 IDE 代理,让用户通过 Google 账号免费访问 Claude Opus 4.6、Gemini 3 Pro 等顶级模型;由opencode-antigravity-authplugin 提供provider/model的 ID 形如zai-coding-plan/glm-5.1或google/antigravity-claude-opus-4-6-thinking,send_message的model_id字段可以只写 model 部分,client 自动推断 provider;上层 caller 应传 router tier alias 而不是 OpenCode raw model
五条硬规则(OpenCode agent invocation 场景)
| # | 规则 | 原因 | 做法 |
|---|---|---|---|
| 1 | 不要直接传 agent 字符串到 payload | 2026-03-26 事故 + 2026-04-03+ server 回归:agent.variant NPE。Server 把 agent 当对象访问但 OpenAPI schema 声明为 string | OpenCodeClient.send_message(agent=...) kwarg 已被故意保留但不转发;调用方的 --agent 参数当前是 no-op。若确需 agent 选择,走 opencode run --agent <name> CLI |
| 2 | 生产 caller 走 CliAgentRouter;adapter 内部不要手拼 REST payload | router 统一处理 fallback/quota/context;OpenCodeClient 保留 provider auto-detect、空 200 兜底、timeout 处理、session 清理 | caller: CliAgentRouter().dispatch(...);adapter/诊断:OpenCodeClient.create_session(...) + send_message(...) |
| 3 | 请求接通但返回 quota 文本也必须 fallback | OpenCode 层可能是 200/accepted,但 provider 内容表示 GLM/Kimi/OpenAI 已限额 | router 用 LLM_RATE_LIMIT_REGEX 只在 provider 的 durable 错误内容上识别(不扫 stderr 回显,避免正常输出里的 quota 字样被误判),记录 quota scope 并跳过;跳过冷却 scope 前若过了 next_probe_at 会 live probe 自动复活。机制见 ai_agent_cli_guide.md 的「配额与虚假冷却防护」节 |
| 4 | session 创建后显式管理生命周期 | sqlite (~/.local/share/opencode/opencode.db) 会膨胀;大量未 delete 的 session 影响查询性能 | 用完一次性任务:client.delete_session(sid);保留可追溯的需要人工审核的任务:像 reflector.py 那样不 delete;CLI 用户通过 --keep-session 显式 opt-in |
| 5 | 选 raw model 看 /provider/connected,生产 alias 看 providers.conf | all 返回 110 个 provider,绝大多数没凭证,直接用会超时或 auth 失败 | 诊断时查 connected;生产只维护 glm-oc:high / glm-oc:medium / glm-oc:low 等 alias(2026-07-18 起 canonical 名;旧 opencode:high/medium/low 和 opencode:glm-* 只作兼容) |
Workspace 规则注入(单独说明):OpenCode 的规则注入走 ~/.config/opencode/opencode.json 顶层 instructions 字段(绝对路径数组),由 server 加载为全局 instructions。修改该字段后必须重启 opencode serve 才能生效——server 不支持 config hot reload。完整架构和重启 SOP 见 config/claude_code_config/rule_injection.md。和 CC 侧的 _MANDATORY.md manifest 需要手动同步(OpenCode instructions 不支持动态 manifest)。
启动目录和认证
OpenCode Server 由 launchd 常驻,工作目录在 ~/context-infra。所有 REST 调用走 Basic auth:
# 环境变量来源:periodic_jobs/ai_heartbeat/.env
OPENCODE_USERNAME=opencode
OPENCODE_PASSWORD=<set-secure-password>
# curl 示例
curl -s -u "$OPENCODE_USERNAME:$OPENCODE_PASSWORD" http://localhost:4096/sessionPython caller 不需要手拼 auth header——OpenCodeClient.__init__ 读环境变量自动构造 Basic header。
核心 API 和 CLI
REST API 关键端点
| Endpoint | Method | 用途 |
|---|---|---|
/session | POST | 创建 session(payload: {"title": "..."}),返回 {"id": "ses_..."} |
/session | GET | 列出所有 session |
/session/{id} | GET | Session 元信息(running, status) |
/session/{id} | DELETE | 删除 session(清理 db) |
/session/{id}/message | POST | 发消息,payload 字段:parts(必)、model.modelID + model.providerID(必)、agent(不要传,见规则 #1)、system(per-message system prompt,9 个 caller 都没用)、noReply, format, variant, messageID |
/session/{id}/message | GET | 读该 session 的所有 message(user + assistant) |
/config | GET | 运行时 config,验证 instructions / small_model 是否生效 |
/provider | GET | 返回 {"all": [...], "connected": [...]},model 选择依据 |
/agent | GET | 返回 18 个注册 agent(含 oh-my-openagent 注入的希腊神话 agent 和 OpenCode 内置 build/general/plan 等) |
/skill | GET | 25 个已注册 skill(OpenCode 没有独立的 skill 调用端点,只能通过 TUI /skill-name 或把 skill 内容 inline 到 prompt) |
/command | GET | 171 个 command(含 OpenCode 内置、skill 派生、plugin 贡献、用户 ~/.config/opencode/commands/*.md) |
CLI 子命令速查
opencode # TUI 交互模式(不在本 skill 范围内)
opencode serve # 启动 headless server(生产走 launchd,不手动跑)
opencode run [message..] # 非交互执行(类似 claude -p)
opencode session list # 列 session
opencode session delete <id> # 删 session
opencode stats # token/cost 统计(读 opencode.db)
opencode agent list # 列 agent(复杂输出,不如 REST GET /agent)
opencode agent create # 创建 agent
opencode models # 列所有 model
opencode db [query] # 交互式 sqlite shell 或直接跑 SQL
opencode db path # 打印 db 路径(~/.local/share/opencode/opencode.db)
opencode db migrate # 迁移旧版 JSON storage 到 sqlite
opencode export <session_id> # 导出 session 为 JSON
opencode attach <url> # 连到远程 opencode server
opencode providers # 管理 provider 凭证
opencode upgrade # 升级二进制不在 skill 范围:acp(Agent Client Protocol)、web(UI)、github、pr、import、mcp、completion、debug、uninstall。
opencode run 非交互模式
CC 的 claude -p 的 OpenCode 对应物:
# 本地 spawn(新进程,session 写入本地 db)
opencode run -m zai-coding-plan/glm-5 "任务描述"
# 附加到运行中的 server(推荐——避免启动开销)
opencode run --attach http://localhost:4096 -p "$OPENCODE_PASSWORD" \
-m zai-coding-plan/glm-5 \
--agent "Sisyphus (Ultraworker)" \
--format json \
"任务描述"
# 继续上次 session
opencode run -c "继续之前的话题"
opencode run -s ses_xxx "继续指定 session"
opencode run --session ses_xxx --fork "分叉出新 session"flag 速查:
| Flag | 作用 |
|---|---|
-m, --model provider/model | 低层诊断用 raw model,如 zai-coding-plan/glm-5.1;生产 caller 用 router tier alias |
--agent <name> | 指定 agent(注意:必须匹配 /agent 返回的完整 name,含空格和括号;REST API 侧传字符串有 bug,但 CLI 侧这条路径是好的) |
--attach <url> -p <pw> | 附加到已有 server,零启动开销 |
-c, --continue | 继续最近的 session |
-s, --session <id> | 继续指定 session |
--fork | 在 -c 或 -s 基础上分叉新 session |
-f, --file <paths> | 附加文件到 message |
--format json | 输出 JSON 而非 formatted text |
--title | 指定 session 标题 |
--variant high/max/minimal | 模型推理强度(reasoning effort) |
--thinking | 展示 thinking block |
--dir | 工作目录 |
gpt-5.6-sol Pro 调用表(2026-07-12)
OpenCode 用 model ID 后缀 + --variant 编码 gpt-5.6 的调用参数(真实 API 参数见 yage.ai 文章):
- model ID 后缀
-pro=reasoning.mode:pro;-fast=service_tier:priority(2× 价低延迟) --variant=reasoning.effort(none/low/medium/high/xhigh/max;无ultraeffort,最高是max)- 真实 model ID 只有
gpt-5.6-sol/-terra/-luna,gpt-5.6-sol-pro-max-fast是社区梗、不是真 ID
经 OpenCode 调(openai provider = ChatGPT Pro 订阅 oauth):
| 调用 | model ID | --variant | mode | service_tier | 说明 |
|---|---|---|---|---|---|
| 标准低/中/高 | gpt-5.6-sol | low/medium/high | standard | standard | 对应 codex:low/medium/high |
| 标准 xhigh | gpt-5.6-sol | xhigh | standard | standard | 工作区默认档(codex:xhigh) |
| 标准 max | gpt-5.6-sol | max | standard | standard | 标准模式最高推理 |
| 标准 fast | gpt-5.6-sol-fast | 默认 | standard | priority | 低延迟(2×价) |
| Pro X-High(默认1) | gpt-5.6-sol-pro | xhigh | pro | standard | Pro + xhigh |
| Pro Max(默认2=Ultra) | gpt-5.6-sol-pro | max | pro | standard | Pro 最高推理(API 可调最高) |
| Pro Max Fast(可选) | gpt-5.6-sol-pro | max | pro | priority | Pro 最高+低延迟(2×价) |
| Terra / Terra-Pro | gpt-5.6-terra[-pro] | max | std/pro | standard | Terra 模型 |
| Luna / Luna-Pro | gpt-5.6-luna[-pro] | max | std/pro | standard | Luna 模型 |
router tier(codex-oc 通道,经 OpenCode):
codex-oc:high= gpt-5.6-sol(标准,不带 variant,走 server 默认 effort)codex-oc:pro-xhigh= gpt-5.6-sol-pro + variant xhigh(Pro 默认1)codex-oc:pro-max= gpt-5.6-sol-pro + variant max(Pro 默认2 = "Ultra")
Codex 现有 tier(codex-exec 通道,保持不动):low/medium/high/xhigh/max/ultra/terra/luna。其中 codex:ultra 是 Codex 产品层多智能体编排(4 agent 协同),不是 API effort,OpenCode 经 Responses API 调不到——所以 OpenCode 侧"Ultra"只能落到 pro + max。
五种调用范式
对标 CC agent invocation 的四种模式(Research/Edit/Test/Judge),OpenCode 实际的使用由 9 个 caller 归纳出 5 种范式:
范式 A:Daily Agent(观测/反思/审计)
场景:每天或每周定时跑的 agentic 任务,需要自主扫描、过滤、写入记忆或发警报。
特征:
- 静态 prompt 模板 + 少量字段插值
- 默认
DEFAULT_PRIMARY(当前是 OpenCode routecodex-oc:high;它不等同于 Codex CLI effort profile)。需要直接 Codex 且用户未指定 effort 时,使用 workspace policycodex:xhigh - router 同步阻塞并记录
DispatchResult - 幂等性预检(避免重复写)
- OpenCode session 生命周期由 router adapter 内部清理
参考实现:periodic_jobs/ai_heartbeat/src/v0/observer.py、jobs/crontab_monitor.py
骨架:
from tools.cli_agent import CliAgentRouter, DEFAULT_FALLBACK_CHAIN, DEFAULT_PRIMARY
prompt = OBSERVER_TEMPLATE.format(kb_path=kb, date=target_date)
result = CliAgentRouter().dispatch(
task_name=f"daily-observer-{target_date}",
prompt=prompt,
primary=DEFAULT_PRIMARY,
fallback_chain=DEFAULT_FALLBACK_CHAIN,
)
if result.is_error:
raise RuntimeError(result.summary())范式 B:Extract + Delegate(提取 + 委派外部工具)
场景:从 raw data 里提炼结构化信息,然后通过 shell 调用本地 CLI 落地到专用系统(TODO、邮件、Kit 订阅)。
特征:
- Prompt 告诉 agent:"找到 X,然后用
bash tools/todo/todo.py add ...落地" - Agent 的输出不是 markdown,而是一系列 shell 调用
- 去重预检(把现有数据拼进 prompt)
- 同步阻塞
- 跨工具链:OpenCode agent → shell → 本地 CLI tool
参考实现:jobs/todo_extractor.py
范式 C:Long-form Content(长文生成 + 多 phase pipeline)
场景:需要 parallel subagent 调研 + 多 phase 写作 + 自我审视的长流程任务(AI 日报、周报、newsletter)。
特征:
- 复杂 prompt(100+ 行),严格的 phase 顺序和成功标准
- Agent 必读方法论文档(
rules/axioms/,rules/skills/workflow_parallel_subagents.md) - OpenCode raw channel 可能出现首次空 200;router adapter 已把空结果当失败进入 fallback
- 是否保留追溯材料由业务脚本自己的输出文件决定,不再依赖 OpenCode session
- Agent 内部派 subagent 做并行调研(走
/agent里的librarian/explore等希腊神话 subagent) - model profile 由 router tier alias 决定,例如
glm-oc:high、claude:high、codex:high
参考实现:jobs/daily_newsletter.py、jobs/ai_news_survey.py
Router 典型代码:
result = CliAgentRouter().dispatch(
task_name="daily-newsletter",
prompt=prompt,
primary="glm-oc:high",
fallback_chain=["claude-zai:high", "claude-kimi:medium", "claude:high"],
)
if result.is_error:
raise RuntimeError(result.summary())范式 D:Pipeline(Observer → Reflector 两阶段)
场景:同一份数据先做粗粒度观测,再做提炼。两个 session 顺序执行,阶段间通过文件传状态。
特征:
- 两个独立 session(不是一个 session 两次 message)
- 每阶段独立 prompt、独立
wait_for_session_complete - 阶段二可选跳过(
--observer-only) - 阶段间通过文件(
observations.md→insights.md)传递状态
参考实现:tools/library_observer.py(活用);tools/ux_observer.py(已标记 deprecated——因为 OpenCode 子进程无法访问 CC 的 JSONL 对话数据,这类任务已迁移到 CC 内联规则)
范式 E:CLI Passthrough(裸 prompt 透传)
场景:把 ad-hoc prompt 提交给 OpenCode 不加任何自定义逻辑。
特征:
- Prompt 从 CLI 参数来,不模板化
--model、--no-wait、--keep-session都是 flag- 无幂等预检、无二次 send
参考实现:tools/opencode_job.py
当前状态:tools/opencode_job.py 已变成 generic router wrapper。历史 --agent、--no-wait、--keep-session 参数只为兼容旧脚本保留,不再控制 OpenCode session。
模型路由决策表
对照代码实际使用情况 + oh-my-opencode category + Antigravity 层:
| 任务特征 | 推荐 tier alias | 理由 |
|---|---|---|
| 结构化 prompt、日常 agent 执行 | glm-oc:high | 低成本,真实模型 ID 在 LLM_GLM_HIGH_MODEL |
| 低延迟/探针/轻量任务 | glm-oc:medium 或 claude-zai:medium | 真实模型 ID 在 LLM_GLM_MEDIUM_MODEL |
| 需要 Kimi 订阅 | kimi-oc:medium 或 claude-kimi:medium | OC medium=K2.7 Coding 256K;wrapper 主/Opus=K3 1M、普通 sub-agent=K2.7 256K |
| 需要 native Claude 深推理 | claude:high | OAuth/Keychain scope,通常只作 fallback |
| 需要 Codex/OpenAI 独立交叉验证 | codex:high / codex:low | 通过 codex exec channel adapter |
| DeepSeek 推理/编码(1M context, OpenAI 兼容) | deepseek:high(v4-pro) / deepseek:low(v4-flash) | key 在 .env DEEPSEEK_API_KEY;2026-06-21 接入 |
| Ollama Cloud 任意模型(35 个,云端订阅) | ollama:high + model_override 指定具体模型 | key 在 .env OLLAMA_API_KEY;见下「指定具体模型」 |
当前 connected 的 provider(minimax / minimax-cn-coding-plan 已于 2026-07-18 从 opencode.json/config.json 清除):anthropic, google, glm, kimi-for-coding, openai, zai-coding-plan, zhipuai-coding-plan, opencode, deepseek, ollama(后两者 2026-06-21 接入)。
不要用 /provider/all 里的其他 100 个 provider(OpenRouter、Cerebras、Groq、Cloudflare 等),它们没凭证。
指定具体模型(DeepSeek / Ollama / 任意 OpenCode model)
OpenCode 的 model 由 provider/model 决定,三种由浅入深的指定方式:
- OpenCode CLI 直接指定(一次性 / 调试):
- ```bash
- opencode run --attach http://localhost:4096 -p "$OPENCODE_PASSWORD" -m deepseek/deepseek-v4-pro "..."
- opencode run --attach http://localhost:4096 -p "$OPENCODE_PASSWORD" -m ollama/glm-5.2 "..."
- ```
- router tier alias(生产 caller 首选,预定义档位):
- ```python
- CliAgentRouter().dispatch(task_name="t", prompt="...", primary="deepseek:high") # deepseek-v4-pro
- CliAgentRouter().dispatch(task_name="t", prompt="...", primary="deepseek:low") # deepseek-v4-flash
- CliAgentRouter().dispatch(task_name="t", prompt="...", primary="ollama:high") # 默认 qwen3-coder:480b
- ```
model_override指定任意模型(Ollama 35 模型任选的核心机制,也是派发 worker session 时指定模型的方式):- ```python
- CliAgentRouter().dispatch(task_name="t", prompt="...", primary="ollama:high", model_override="glm-5.2")
- CliAgentRouter().dispatch(task_name="t", prompt="...", primary="ollama:high", model_override="deepseek-v3.2")
- # session_dispatch 同样支持(派独立 worker session 时指定模型):
- dispatch_helper(task_name="t", prompt="...", channel="ollama:high", model_override="kimi-k2.7-code")
- ```
-
model_override替换 tier 的 model_id,provider_override替换 provider_id;仅 opencode channel 生效,override 优先于 tier 默认值。
- wrapper 满额时保持 provider 家族纯净:
- ```bash
- # Kimi wrapper 满额时,用 Ollama Cloud 调 Kimi 2.7 Code。
- printf 'Return exactly: OK\n' | python3 tools/cli_agent/router.py \
- --task-name probe-ollama-kimi \
- --primary ollama:high \
- --model-override kimi-k2.7-code \
- --fallback \
- --timeout 300
# GLM wrapper 满额时,用 Ollama Cloud 调 GLM 5.2。
printf 'Return exactly: OK\n' | python3 tools/cli_agent/router.py \
--task-name probe-ollama-glm \
--primary ollama:high \
--model-override glm-5.2 \
--fallback \
--timeout 300
```
这里的空 --fallback 是刻意的:该 worker 要的是 Kimi/GLM 家族本身,失败时不要落到默认 Claude/Kimi/ZAI fallback 链伪装成功。此路径不需要本机有 ollama CLI;实际调用面是 OpenCode provider ollama + Ollama Cloud OpenAI-compatible API。
Ollama Cloud 当前可用模型(GET https://ollama.com/v1/models,会随时间变):deepseek-v4-pro/flash、deepseek-v3.1:671b、deepseek-v3.2、glm-5.2/5.1/5、kimi-k2.7-code/k2.6/k2.5、qwen3-coder:480b、qwen3.5:397b、gpt-oss:120b/20b、minimax-m3/m2.7/m2.5、mistral-large-3:675b、gemma4:31b、nemotron-3-ultra/super、gemini-3-flash-preview 等 35 个。新增/弃用模型重跑 provider sync(见 job adhoc_jobs/context_infra_base_tooling_buildout_20260615/opencode_provider_expansion_deepseek_ollama_20260621)。
2026-06-27 live probe:kimi-k2.7-code 与 glm-5.2 直连 /v1/chat/completions 成功;router ollama:high + model_override 成功。r006 证据在 adhoc_jobs/context_infra_base_tooling_buildout_20260615/alldomain_design_optimization_20260620/runs/r006_20260627_strict_domain_provider_cell_implementation_run/raw/domain_dispatch/cross_platform_hook_bridge/{kimi_2_7,glm_5_2}/ollama_router_probe_20260627_1435_*。
Server 生命周期管理
启动(已自动化)
通过 macOS launchd 常驻:
- Plist:
~/Library/LaunchAgents/com.opencode.server.plist - Label:
com.opencode.server - Command:
~/.opencode/bin/opencode serve --port 4096 --hostname 0.0.0.0 - Env:
OPENCODE_SERVER_PASSWORD=<set-secure-password> - RunAtLoad + KeepAlive: true(开机自启 + 崩溃 respawn)
- stdout/stderr:
/tmp/opencode.log//tmp/opencode.error.log(几乎空白——日志主要在 sqlite 里) - WorkingDirectory:
~/context-infra
查看状态:launchctl list | grep opencode(输出 PID + label)。
优雅重启(修改 instructions 或 config 后必做)
# 1. 确认没有正在运行的 session
curl -s -u "$OPENCODE_USERNAME:$OPENCODE_PASSWORD" http://localhost:4096/session | \
python3 -c "import json,sys; d=json.load(sys.stdin); print(f'active: {len(d)}')"
# 2. 看 cron 是否马上要启动新任务(heartbeat observer/reflector 等)
crontab -l | grep -iE "opencode|heartbeat"
# 3. graceful 杀进程(launchd 会自动 respawn)
pkill -TERM -f "opencode.*serve"
# 4. 验证新 config 已生效
curl -s -u "$OPENCODE_USERNAME:$OPENCODE_PASSWORD" http://localhost:4096/config | \
python3 -c "import json,sys; d=json.load(sys.stdin); print('instructions:', d.get('instructions'))"没有专用的 opencode restart 子命令。launchd KeepAlive: true 是重启的唯一机制。
Session 持久化
- 数据库:
~/.local/share/opencode/opencode.db(sqlite + WAL) - 相关目录:
snapshot/,storage/,tool-output/,log/在~/.local/share/opencode/ - Session ID 格式:
ses_2a0a...(26 字符) - 重启后 resume: ✔ sqlite 持久化,
/session/{id}/messageREST 可以继续读写,opencode run -s <id>也能恢复 - 查询 db:
opencode db "SELECT * FROM session LIMIT 10"或sqlite3 ~/.local/share/opencode/opencode.db
崩溃模式
launchd KeepAlive 保证 fatal crash 自动 respawn。但注意:agent.variant NPE 不是 fatal——server 继续运行,只有触发它的那条 message 变成空 200。所以 launchctl list 里看到 PID 稳定不变不等于没有 bug 在日志里堆积。要监控实际健康度需要看 /tmp/opencode.error.log。
Skill 和 Command 系统
OpenCode 有自己的 skill/command 生态,和 Claude Code 格式相同但调用机制不同:
| 维度 | Claude Code Skill | OpenCode Skill |
|---|---|---|
| 文件格式 | YAML frontmatter + Markdown body | 完全相同 |
| 注册路径 | ~/.claude/skills/<name>/SKILL.md + plugin | ~/.config/opencode/skills/<name>/SKILL.md + plugin + ~/.agents/skills/(跨 AI 工具共享) |
| 触发方式 | Agent 基于 description 自主匹配 + 显式 /skill-name | TUI 里 /skill-name 显式触发;REST API 没有专用 skill trigger,只能把 skill 内容 inline 到 prompt |
| 子代理协同 | Sub-agent 继承父 skill 上下文 | 通过 agent mode + category 路由到不同模型 |
| 命令行管理 | 没有专门的 claude skill 子命令 | 也没有 opencode skill 子命令,只能 GET /skill 或 TUI |
当前 workspace 里 ~/.config/opencode/skills/ 下有 15 个原生 skill:build-inspector, complexity-guard, concept-modeler, deep-research, git-forensics, llm-radar, nexus-mapper, nexus-query, orchestrated-development, orchestration-planning, project-background-research, report-template, runtime-inspector, skill-creator, travel-itinerary-research。GET /skill 还会扫到 ~/.claude/skills/ 和 ~/.agents/skills/ 的内容(25 个总数)。
~/.config/opencode/commands/ 下有 8 个用户定义 command(ag-off/on/status, omo-anti/cn/status, to-anti/cn),格式是 markdown + frontmatter,body 用 ! 前缀表示 shell 命令:
---
description: 禁用 Antigravity 插件
---
!`~/.local/bin/ag off`GET /command 返回 171 条(用户自定义 8 + plugin 贡献的约 150 个)。
OpenCode 的 agent / skill / command 三者的关系:category(ultrabrain/deep/artistry/quick)→ 路由到具体的 agent(Sisyphus/Hephaestus/...)→ agent 内部可用 skill 和 command。对于 REST API caller,这一整套机制基本用不上——直接走 send_message + model_id 即可,agent/skill 留给 TUI 用户和 opencode run 用户。
踩坑速查
OpenCodeClient 源码暴露的失败模式
| 触发条件 | 症状 | 处理 | 常见原因 |
|---|---|---|---|
OPENCODE_PASSWORD 未设 | __init__ 抛 ValueError | 启动前 source .env | .env 缺失 |
create_session 网络异常 | 返回 None | caller 必须判空退出 | server 未启动、port 冲突 |
send_message 返回 200 + 空 body | 触发 45s _wait_for_first_assistant_message 轮询 | 找到 = accepted_empty_response;找不到 = None + 打印 model 建议 | agent 字段触发 NPE(规则 #1)、prompt 过长、model/provider 拼错 |
| 非 200 响应 | 打印 Server returned {status} + HTTPError | 返回 None | 认证失败(401)、server 崩溃(500)、payload 校验失败(400) |
| JSON 解析失败 | 打印前 200 字符 | 返回 None | server 返回 HTML 错误页 |
wait_for_session_complete 7200s 超时 | 打印 max_wait exceeded | 返回 False | session 卡在 tool call(web search 长时间无响应) |
历史事故
事故 1(2026-03-26):agent: "OpenCode-Builder" 导致全部 session 空 200。排查过程在 contexts/daily_records/claude/2026-03-26.md:14146-14279。修复:删除 send_message 的 agent kwarg 和 payload。
事故 2(2026-04-03 起,未完全愈合):/tmp/opencode.error.log 持续报 TypeError: undefined is not an object (evaluating 'agent.variant') at createUserMessage。新版 server 的 createUserMessage 期望 agent 是对象(.variant 字段),拿到字符串就 NPE。OpenAPI schema 还声明为 string,这是 plugin/core 三层 schema 不一致。
现状:opencode_client.py 的 send_message kwarg 签名保留 agent=None 以兼容老 caller,但不转发到 payload——作为防线阻止事故复发。完整解决方案等待 OpenCode 上游修 schema。
oh-my-opencode → oh-my-openagent 自动迁移
Server 启动时自动把 opencode.json 里的 oh-my-opencode plugin 名迁移到 oh-my-openagent(/tmp/opencode.error.log 顶部有记录)。但 config.json 没被动——如果手动编辑时修改了 opencode.json,重启会再次幂等迁移。不要编辑 config.json(已废弃备份)。
已知限制速查
| 问题 | 现象 | 解法 |
|---|---|---|
instructions 字段不生效 | GET /config 返回 instructions: None | 重启 opencode serve(launchctl kickstart -k gui/$(id -u)/com.opencode.server) |
_MANDATORY.md 和 opencode.json.instructions 不同步 | 只改了 CC 那一个 manifest | OpenCode 不支持动态 manifest,必须手动同步两份 |
anthropic provider 可能失败 | OpenCode 内部 anthropic/claude-opus-* key 可能是占位符 | 生产不要把它作为 OpenCode raw model;需要 native Claude 用 router 的 claude:high |
漏传 model_id | fallback 到 antigravity-gemini-3-flash | 生产 caller 传 tier alias 给 router,adapter 内部显式传 model |
| Long prompt 首次空 200 | send_message 返回 None | 范式 C 的"继续"兜底 |
agent 字段触发 NPE | 日志 agent.variant TypeError | 不要传 agent 字符串(规则 #1) |
OpenCode-Builder agent 不存在 | 历史 bug | opencode_job.py 的 --agent 当前是 no-op |
glm-5.1 读超大日志触发 context overflow | server 返回 error / Prompt is too long(GLM-5.1 硬 200K 上限,包含 instructions 注入的 rule 文件 + 用户 prompt + 日志) | tools/cli_agent/router.py 已集成大文件提示、runtime overflow 识别、跨 context fallback |
observer.py PROMPT_TEMPLATE 有硬编码的幂等性跳过 | OBSERVATIONS.md 已含 Date: {target_date} 时,agent 直接回复 "Entry already exists, skipping" 不写文件 | 抢救模式下绕过:要么手动从 OBSERVATIONS.md 删除 stale 条目,要么在 prompt 里覆写幂等检查("本次是 complete log rescan,忽略既存 Date 条目,追加新的") |
Cron 环境缺 OPENCODE_PASSWORD | OpenCodeClient.__init__ 抛 ValueError | router 返回 client_init_failed 并 fallback 到 wrapper tier;.env 仍需可读,以便 OpenCode channel 正常工作 |
extract_claude_conversations.py mtime 窗口 bug(已修复,遗留坑) | 原代码 -1 <= diff <= 1 筛选 JSONL 文件,长周期 session(mtime 漂移到目标日期之外)被整个丢弃 | 已修为 mtime >= target_date。2026-04-05 发现时 7 天日志丢了 41 个 session,最严重的 04-04 只有 3/13 sessions。未来改 extraction 逻辑时一定要用 --force + 完整验证脚本重跑一次 |
todo_extractor.py 一次吞多天日志导致注意力稀释 | --days 5 塞 ~1.7MB 内容,Opus 只提取 11 条 TODO(其中 04-01 那天有 17 个 session 的活跃度,提取为 0 条) | 改成 per-day 调用,每次只扫 1 天日志。v3 Opus per-day 从 11 条提升到 22 条(+100%),其中 04-01 从 0→3。tools/cli_agent/router.py 的 todo_extractor 迁移已采用 per-day 模式 |
实战备忘
- 所有生产 Python caller 通过
CliAgentRouter调用;只有 router adapter、低层诊断或 OpenCode 专项调试直接用OpenCodeClient - Cron 任务默认保留 session 的设计(reflector / daily_newsletter / ai_news_survey)是为了追溯,但 db 会膨胀。定期用
opencode db "SELECT COUNT(*) FROM session"监控,或者opencode session list后手动清理 - 修改
opencode.json后永远要curl /config验证运行时实际加载了什么——disk / runtime 不一致是常态 opencode stats可以读 db 里的 cost/token 统计,但比 CC agent invocation 的total_cost_usd精度低(聚合粒度是 day,不是 call)- 并发场景:REST API 天然支持多 session 并发。不需要
threading,HTTP 就是并发原语 - 调试 session 内部:
opencode export <session_id>出 JSON,或者sqlite3 opencode.db直接看 - 和 CC 生态的桥接:如果任务需要同时读 CC 的 claude_logs,不要走 OpenCode——那条路在
ux_observer.py已经证伪(OpenCode 子进程看不到 CC 的状态文件)
相关文件索引
Config 层
~/.config/opencode/opencode.json— 主配置,含instructions+ MCP + provider + plugin~/.config/opencode/config.json— 旧版配置,不要编辑(字节级接近 opencode.json 但无 instructions)~/.config/opencode/oh-my-opencode.{json,cn.json,anti.json}— category → 模型路由(国产 vs Antigravity)~/.config/opencode/oh-my-openagent.jsonc— 新版 plugin 配置(rename 之后)~/.config/opencode/antigravity.json—opencode-antigravity-authplugin 配置(账号池、轮换、rate limit)~/.config/opencode/skills/— 15 个原生 skill~/.config/opencode/commands/— 8 个用户 command
运行时
~/Library/LaunchAgents/com.opencode.server.plist— launchd 启动配置/tmp/opencode.log//tmp/opencode.error.log— 服务日志(几乎空白)~/.local/share/opencode/opencode.db— session sqlite~/.local/share/opencode/{storage,snapshot,tool-output,log}/— 附属数据~/.opencode/bin/opencode— 二进制~/.local/bin/claude-zai— ZAI wrapper(跨生态参考)
Caller 层(查 tools/INDEX.md 优先)
opencode_client(periodic_jobs/ai_heartbeat/src/v0/opencode_client.py)— 统一入口 wrapperopencode_job(tools/opencode_job.py)— 通用 CLI 提交器library_observer(tools/library_observer.py)— 范式 D 活用ux_observer(tools/ux_observer.py)— 已 deprecated,保留代码仅供参考periodic_jobs/ai_heartbeat/src/v0/{observer,reflector}.py— 范式 Aperiodic_jobs/ai_heartbeat/src/v0/jobs/{daily_newsletter,ai_news_survey,todo_extractor,crontab_monitor}.py— 范式 B/C
相关文档
config/claude_code_config/rule_injection.md— 三层规则注入架构,OpenCode 在第 3 层rules/skills/claude_code_self_evoke_call_codex_loop.md— CC agent invocation 对标 skillcontexts/survey_sessions/opencode_usage_research_20260405_manual.md— 本 skill 的原始调研报告tools/claude/PROVIDERS.md— CC agent invocation 引擎的统一管理索引,OpenCode 和 CC 的决策边界也在那里展开
和 CC Self-invoke 的任务路由决策表
| 任务特征 | 选择 | 理由 |
|---|---|---|
| 定时 cron 任务(观测/审计/日报) | OpenCode | Server 常驻无启动开销;glm-5 成本低;长 timeout 自然支持 |
| 多 session 并发(N 个目录同时 observer) | OpenCode | REST API 天然支持;N 次 CC 启动贵 |
| 需要 workspace 规则强制加载 | CC(更靠谱) | CC 的 SessionStart hook 动态读 _MANDATORY.md;OpenCode 的 instructions 需要重启才生效 |
| 需要读 CC 的 JSONL / claude_logs | CC 内联规则 | OpenCode 子进程看不到 CC 的状态文件(ux_observer deprecated 的原因) |
| 深度推理(架构设计、代码审查、TODO 执行) | CC (Opus) | Anthropic 模型 + 完整的 hook/skill/settings 生态 |
需要 Skill tool 主动匹配 | CC | OpenCode 的 skill 是 command 形态,不 auto-match |
| 长文本生成(newsletter、周报) | 当前 OpenCode + 深模型 | 历史原因,daily_newsletter 建在 OpenCode 生态;理论上 CC Opus 也能做 |
| E2E 测试 / LLM-as-Judge | CC (claude-zai 包月 GLM) | 已有 skill claude_code_self_evoke_call_codex_loop.md 规范化 |
| Ad-hoc 一次性任务 | 二者皆可 | 取决于当前上下文生态 |
一句话总结:OpenCode = 定时后台 + 多并发 + 成本敏感;CC Self Evoke / Call Codex / Loop = 深度推理 + workspace 强规则 + 交互级任务。不是替代,是成本/能力矩阵的不同单元。