opencode (SST)

一句话定位

opencode 是 SST 团队维护的开源终端/服务化编码 agent,整体用 TypeScript + Bun 实现, 底层构建在 Effect 函数式效应框架之上(每个服务是 Effect.Service/LayerEffect.gen(function* () {...}) 写法贯穿全仓)。仓库当前处于双实现并存的中间态: 真正跑在用户机器上的是 packages/opencode/src/(V1,本文档绝大多数论断的证据来源); packages/core/src/ 是一套尚未成为默认路径的 Effect-native 重写(V2,见 specs/v2/*.md 与根目录 CONTEXT.md),本文档中凡引用 V2 spec 的内容均明确标注为 “设计意图 / 未上线”,不作为当前行为断言。

核心架构总览(目录结构关键路径 + 引用的 commit)

Commit: eb6ff0c1e049e5dfb6f61eb74f925c0a8007490c(浅克隆单 commit,commit 时间 2026-07-06 13:35:10 UTC,2026-07-07 拉取)。

opencode/ (Bun workspaces monorepo)
├── packages/opencode/src/   — V1,实际 shipped 的 CLI/server 实现,本文档主要证据来源
│   ├── session/             — 主循环(prompt.ts)、压缩(compaction.ts/overflow.ts)、
│   │                          事件处理(processor.ts)、系统提示组装(system.ts)、
│   │                          reminders.ts、instruction.ts(AGENTS.md 发现,未深挖)
│   ├── tool/                — 工具定义(tool.ts)、注册表(registry.ts)、
│   │                          task.ts(subagent)、shell.ts(bash 执行+静态分析)
│   ├── agent/                — Agent 定义(agent.ts)、subagent-permissions.ts
│   ├── permission/           — 权限引擎(index.ts)
│   ├── skill/                — Skill 发现与加载(index.ts/discovery.ts)
│   ├── plugin/                — 插件 loader
│   └── mcp/                  — MCP 客户端(stdio/SSE/StreamableHTTP)
├── packages/core/src/        — V2,Effect-native 重写中,未成为默认路径
│   ├── database/migration/   — Drizzle/SQLite 迁移,event-sourced session 存储
│   └── observability.ts, observability/otlp.ts — OTel 导出
├── packages/plugin/src/index.ts — 插件 Hooks 类型定义
├── packages/tui, packages/server, packages/sdk(-next) — 终端 UI / HTTP API / 生成客户端(未深挖)
├── packages/stats            — opencode.ai 公开用量排行榜网站,与训练无关
├── packages/docs              — 空的 Mintlify 起始模板,**不是**真实 opencode.ai 公开文档内容
├── CONTEXT.md(根目录,226 行)— 官方 V2 设计文档,定义 System Context / Context Epoch 等术语
└── specs/v2/session.md, specs/v2/tools.md — 官方 V2 设计 spec

V1/V2 通过 spec 中提到的 “V1-to-V2 shadow bridge” 共存(specs/v2/session.md), V2 尚不是默认运行时路径。

Agent Loop(主循环 / 何时继续何时停)

Shipped(V1)主循环在 session/prompt.tsrunLoop(sessionID)(约 1081-1339 行), 是一个 while(true) 循环,每轮迭代:

  1. 通过 MessageV2.filterCompactedEffect 加载消息;
  2. 若最后一条 assistant 消息已完成且无待执行 tool call → break 退出;
  3. 优先处理排队中的 subtask/compaction 任务(约 1142-1159 行);
  4. 通过 compaction.isOverflow 检查 token 溢出 → 触发 compaction.create({auto:true})continue
  5. 解析当前 agent,计算 isLastStep = step >= agent.steps(agent 可配置最大步数上限,默认 Infinity),应用 SessionReminders.apply(向历史注入合成 reminder);
  6. 创建新的 assistant 消息,取得 SessionProcessor.Handle(见 processor.ts),经 SessionTools.resolve 解析可用工具,组装系统提示数组(env + instructions + mcpInstructions + skills),调用 handle.process(...)
  7. handle.process 返回 "compact" | "stop" | "continue"processor.ts 679-682 行):needsCompaction"compact"blocked || error"stop";否则 "continue"
  8. 收到 "stop" 则跳出循环,否则继续(若为 "compact" 先触发压缩)。

停止条件:assistant 的 finish 原因不是 tool-calls,且无待执行 tool call,且 lastUser.id < lastAssistant.id(没有新内容需要响应)。Doom-loop 防护processor.tsDOOM_LOOP_THRESHOLD = 3,检测到 3 次连续相同 tool call(相同工具+ 相同输入)会强制触发 doom_loop 权限 ask,而非无限循环。

每轮模型流式响应由 session/llm.tsLLM.stream(本次未深挖)驱动,产出事件流 (reasoning-start/delta/endtool-input-*tool-calltool-resulttool-errorstep-start/finishtext-start/delta/endprovider-errorfinish),由 processor.tshandleEvent 消费。

V2 设计(未上线):specs/v2/session.md 描述更形式化的 SessionRunner/ SessionExecution/SessionRunCoordinator 模型,含显式 “Session Drain”(一次执行 span)、steer vs queue 两种 inbox 投递模式、resume/wake 入口——这是目标架构, 不是当前行为。

记忆与上下文管理(压缩、长期记忆、会话持久化)

Shipped 压缩机制(session/compaction.ts 562 行 + session/overflow.ts):

  • Token 预算 = model.limit.input - reservedreserved = config.compaction.reserved ?? min(20_000, maxOutputTokens)overflow.tsusable());
  • isOverflow() 在累计 token ≥ 可用预算时触发(compaction.auto 配置可关闭);
  • 压缩算法(compaction.ts):把历史切成”轮次”(turns() —— 一轮 = 从一条用户消息到下一条),保留最近若干轮原文(DEFAULT_TAIL_TURNS = 2,预算感知,preserveRecentBudget = 可用预算的 25%,夹在 2k-8k 之间),更早的部分用专门的 compaction agent + agent/prompt/compaction.txt 提示词摘要(“anchored context summarization assistant… If the prompt includes a <previous-summary> block, treat it as the current anchored summary… merging in new facts”);
  • 重复压缩会更新已有的滚动摘要而非从头重来(specs/v2/session.md 119 行,与 V1 行为一致);
  • PRUNE_MINIMUM/PRUNE_PROTECT 常量(20k/40k token)与 PRUNE_PROTECTED_TOOLS = ["skill"] 表明工具输出裁剪也是压缩流程的一部分(保护 skill 工具输出不被裁剪);
  • 溢出触发的压缩:若 provider 调用本身因上下文溢出失败,processor.tshalt()(约 599-625 行)捕获 SessionV1.ContextOverflowError 并设 needsCompaction=true(仅一次重试:压缩+重建,非循环,与 V2 spec 中”仅剩一次物理尝试”的表述一致)。

长期/会话持久化:SQLite via Drizzle(packages/core/src/database/*),event-sourced (V2 spec 定义的 session.next.* 事件族;V1 通过 session/session.ts 的消息分页已经 落盘持久化)。Session 可 fork(session.ts 接口中的 fork),有父子关系(subagent session 带 parentID)。

系统提示动态组装 = runLoop 调用时拼接的 4 个部分(prompt.ts 约 1257-1269 行): sys.environment(model)(per-model 基础提示 + 环境块 + 项目引用)、 instruction.system()(AGENTS.md 发现,本次未完整读 session/instruction.ts,237 行)、 sys.mcp(agent, permission)(MCP server 说明块)、sys.skills(agent)(可用 skill 列表)。另外 session/reminders.ts 把合成 reminder 注入消息历史本身(而非系统提示), 用于 plan-mode 进出、build-mode 切换等(prompt/plan.txtprompt/build-switch.txtprompt/plan-mode.txt)。

V2 设计文档(CONTEXT.md,官方、未上线)把这一套形式化为由”Context Source”组成的 “System Context”,包裹在一个”Context Epoch”内——一个对 provider 缓存友好的不可变 基线,只能通过在安全的轮次边界插入的持久化”Mid-Conversation System Messages”改变, 从不在流式过程中改变;压缩会开启新的 Context Epoch。明显是为了 prompt-cache 友好性(避免每次小的上下文变化就使 Anthropic/OpenAI 的前缀缓存失效)。

工具体系(定义/调用协议/注册/权限)

定义:tool/tool.tsTool.define(id, init) —— 每个工具有 descriptionparameters(Effect Schema.Decoder)、可选 jsonSchema 覆盖、execute(args, ctx)。 注册时统一包一层:schema 解码 + 统一的执行后输出截断(truncate.output)+ OpenTelemetry span(Effect.withSpan("Tool.execute", {"tool.name", "session.id", "message.id", "tool.call_id"}))。

注册表(tool/registry.ts,451 行):内置工具列表(invalid, question?, shell, read, glob, grep, edit, write, task, fetch, todo, search, skill, patch, execute?(codemode), lsp?, plan?),另外:

  • 项目自定义工具:配置目录下任意 tool/*.{js,ts}tools/*.{js,ts} 文件,动态 import()(命名空间=文件名);
  • 插件工具:来自已加载插件的 Hooks.tool map,从 Zod schema 桥接到 JSON Schema(zodJsonSchema),含一处文档化的历史 bug 兼容 shim(args ?? {} 归一化,引用 GH issue 27630);
  • 按模型条件可见性:apply_patch 工具只在部分 GPT 模型下展示(modelID.includes("gpt-") && !includes("oss") && !includes("gpt-4")),否则展示 edit/writewebsearch 仅在 webSearchEnabled(providerID, {exa, parallel}) 标志开启时展示;
  • tool.definition 插件钩子可在每轮发送给模型前修改某个工具的 description/parameters/jsonSchema。

权限集成是逐工具在 execute 内通过 ctx.ask(...) 完成的(例如 shell.ts 在用 tree-sitter 静态解析命令找到涉及路径后调用 ctx.ask({permission: "bash"|"external_directory", patterns, always, metadata}))。

输出边界:tool.tswrap() 中统一截断——每个工具结果都过 truncate.output(), 超限输出写入受管临时文件(tool/truncation-dir.ts,本次未完整读)并替换为有界预览

  • outputPath 元数据,与 specs/v2/tools.md 中形式化的 “Managed Tool Output File” 一致(V1 代码已提前实现该模式)。

Prompt 设计(系统提示结构、动态组装)

基础系统提示按模型家族在 session/system.tsprovider(model) 中选择: gpt-4/o1/o3 → beast.txt;其他 gpt 且 id 含 “codex” → codex.txt;其他 gpt → gpt.txt;gemini-* → gemini.txt;claude → anthropic.txt;trinity → trinity.txt;kimi → kimi.txt;否则 → default.txtdefault.txt(96 行,全文 读完)在结构上高度接近 Anthropic 自家 Claude Code 系统提示:包含 “Tone and style” / “Proactiveness” / “Following conventions” / “Code style: DO NOT ADD ANY COMMENTS unless asked” / “Doing tasks” / “Tool usage policy” / “Code References” 等分节, 部分措辞近乎逐字(例如 <4 lines 简洁性规则、file_path:line_number 引用惯例、 并行工具调用指示)。这是一个可观察到的相似性事实,不是”直接抄袭”的证据——原文 判断为佐证性观察,不作确凿溯源结论。

动态组装发生在每轮 prompt.ts 中(同”记忆”节所述):环境块 + AGENTS.md 指令 + MCP 指令 + skill 列表,拼接为一个系统消息字符串数组(不是单一 blob)——数组元素似乎 映射为发给 provider 的多条独立系统消息/块。

任务专用提示:agent/prompt/title.txt(标题生成)、summary.txt(摘要生成)、 explore.txtexplore subagent 专用提示)、compaction.txt(压缩 agent 使用)。

Reminders(session/reminders.ts)注入的是合成用户轮文本部分(标记 synthetic: true),而非系统消息,例如 agent 为 plan 时自动注入 PROMPT_PLAN, 或从 plan-agent 轮次切回 build 时注入 BUILD_SWITCH 文本。

插件钩子 experimental.chat.system.transform(修改系统消息数组)与 experimental.chat.messages.transform(修改整个消息数组)赋予插件任意的系统提示 修改能力(标记为 “experimental”,CONTEXT.md 的 “Flagged ambiguities” 中明确指出 尚未移植到 V2 —— 仅 V1 有此逃生口)。

Router / 编排(任务分解、多 agent、子 agent)

没有独立的”router”组件——编排是基于 agent 的,通过 task 工具(tool/task.ts, 347 行)实现:

  • 任何 mode: "subagent""all" 的 agent 都可以经 task(subagent_type, prompt, description, task_id?, background?) 调用;
  • 内置 subagent(定义于 agent/agent.ts):general(宽泛多步 subagent,禁用 todowrite)、explore(只读的快速代码搜索 agent——仅允许 grep/glob/list/bash/webfetch/websearch/read,其余全拒,配专用提示 explore.txt);
  • 内置主 agent:build(默认,完整权限)、plan(除白名单路径 .opencode/plans/*.md 外禁用一切编辑工具,禁用 task.general,只允许 plan_exit 权限);
  • 隐藏系统 agent:compactiontitlesummary——全部工具禁用 ("*": "deny"),纯文本生成、供循环内部使用;
  • Subagent session 是真正的子 SessionparentID 指向调用方 session; deriveSubagentSessionPermission()agent/subagent-permissions.ts)把父 session 权限与目标 subagent 自身权限规则合并,并强制拒绝 todowrite/task 递归(除非 subagent 显式重新允许)以及任何被配置为 experimental.primary_tools 的主 agent 专属工具;
  • 后台模式(background: true,需 OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS 实验开关):subagent 通过 BackgroundJob.Service 异步运行,完成后一条合成 结果消息(<task id state>...</task> 类 XML 包装,renderOutput())被注入 父 session,如同该工具已经返回,并通过一个 forked effect 的 notify() 通知父 session;
  • task_id 参数允许调用方复用之前的 subagent session 而非重新生成(跨调用的 session 身份复用);
  • 用户自定义 agent 来自 config.agent 条目(name/model/permission/prompt/steps 等覆盖默认值)——多 agent 配置是用户可扩展的,不是硬编码在内置 agent 里。

未发现”planner→executor”式的层级式 router 模式,仅有这一套扁平的 task-dispatch 工具;plan 模式是一种权限受限的 UI 模式,不是独立的规划子系统。

Skill / 插件体系

Skillskill/index.tsskill/discovery.ts):兼容 Claude Code 的 SKILL.md frontmatter 格式(namedescription),从 .claude/skills/**/SKILL.md.agents/skills/**/SKILL.md.opencode/{skill,skills}/**/SKILL.md(glob 常量 EXTERNAL_SKILL_PATTERN/OPENCODE_SKILL_PATTERN/SKILL_PATTERN)发现。一个 skill 工具(tool/skill.ts,70 行)让模型按需加载 skill 正文;系统提示里只列出 name+description(按 agent 权限过滤,经 Permission.disabled(["skill"], ...)), 不含完整正文——与 Claude Code/Claude Skills 中的”渐进式披露”模式一致。远程 skill 包可经 skill/discovery.tspull(url) 拉取——抓取 index.json manifest + 逐个 skill 文件,带版本化的原子替换缓存更新(临时目录 + rename,失败回滚), 存于 ~/.cache (Global.Path.cache)/skills/<name>/。内置 customize-opencode skill 专门教模型 opencode 自身的配置 schema。

插件packages/plugin/src/index.ts 类型定义 + packages/opencode/src/ plugin/loader.ts + plugin/index.ts 运行时):插件是 (input: PluginInput, options?) => Promise<Hooks>。Loader(plugin/loader.ts) 把插件规格解析为 npm 包(按需安装)或本地文件,检查版本兼容性(npm 插件声明 支持的 opencode 版本范围),动态 import(),文件插件依赖未就绪时有一次重试。

完整 Hooks 接口(直接读自 packages/plugin/src/index.ts):disposeevent(订阅全部事件总线事件)、config(修改已解析配置)、tool(注册自定义 工具)、auth(provider 自定义 OAuth/API-key 认证流程)、provider(向 provider 注入自定义模型)、chat.messagechat.params(修改 temperature/topP/topK/maxOutputTokens/provider options)、chat.headerspermission.ask(覆盖 ask/deny/allow 决策)、command.execute.beforetool.execute.before/tool.execute.aftershell.env(向 shell 工具注入环境 变量)、experimental.chat.messages.transformexperimental.chat.system.transformexperimental.provider.small_modelexperimental.session.compacting(自定义压缩提示)、 experimental.compaction.autocontinueexperimental.text.complete。仓库内 自带多个一方示例插件:xai.tsdigitalocean.tscloudflare.tsazure.tssnowflake-cortex.tsgithub-copilot/openai/

自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)

未实现。 未发现 eval 驱动的自我纠错循环、微调管线、reward model 集成,或 “从历史 session 学习”的机制(对 packages/ 全仓搜索 “fine-tun”、 “reinforcement”、“reward model”、“self-improv”、“training data”、 “eval-driven” 均无真实命中)。packages/stats 是 opencode.ai 的公开用量排行榜 网站,与模型训练/自我改进无关。会话摘要(session/summary.ts)和压缩摘要 只服务于上下文窗口管理,不构成跨 session 学习。若未来版本加入此能力,本 commit 中不可见。

可观测性(日志 / trace 格式)

两层:

  1. Effect 原生的 trace/log 原语被广泛使用:Effect.withSpan(...)(在 tool/tool.tstool/registry.ts 的插件工具路径中包裹每次工具执行, 携带 tool.namesession.idmessage.idtool.call_id 属性),以及 Effect.logInfo/Effect.logWarning/Effect.logError 结构化日志(例如 processor.ts 记录 process/SessionProcessor.halt 事件,带 session.idmessageIDerrorstack)。
  2. OpenTelemetry 导出,选择性开启packages/core/src/observability.ts + observability/otlp.ts。若设置环境变量 OTEL_EXPORTER_OTLP_ENDPOINT, 构建 OTLP 日志导出器(OtlpLogger.make)和 OTLP trace 导出器 (@opentelemetry/exporter-trace-otlp-http + NodeSdk.layer + BatchSpanProcessor),resource 属性含 service.name=opencodeservice.versiondeployment.environment.nameopencode.clientopencode.run(进程级运行 UUID),以及任意 OTEL_RESOURCE_ATTRIBUTES。 还显式注册了 AsyncLocalStorageContextManager 作为全局 OTel context manager,使 Vercel AI SDK 自身的内部 span 能正确嵌套在 Effect 的 span 之下——一次刻意的跨库 trace-context 桥接(otlp.ts 注释:“The Effect Node SDK does not register a global context manager, but the AI SDK uses it to parent spans”)。

除 SQLite event-sourced session 存储本身(session.next.* 事件族,按 V2 spec) 外,未发现独立的自定义”trace/replay” JSON 格式;这套事件存储事实上已经是一份 可持久、可回放的轨迹日志(见”轨迹利用”节)。

安全与权限(审批门、密钥管理)

核心引擎:permission/index.ts(全文读完,224 行)。模型: PermissionV1.Ruleset 是有序的 {permission, pattern, action: "allow"|"ask"|"deny"} 规则列表;evaluate(permission, pattern, ...rulesets) 在拼接后的规则集中用 Wildcard.match最后一条匹配规则,无匹配则默认 askask() 遍历某次请求涉及的所有 pattern:任一 deny 短路为 DeniedError;若有 pattern 需要询问,注册一个 Deferred 并发布 Asked 事件(由 CLI/TUI/server 层消费以提示用户);reply() 解析该 Deferred—— "reject" 使该 Deferred 失败(并级联拒绝该 session 同批的其它待处理请求, 即一次拒绝清空整批);"always" 把新规则持久化进内存态 approved 列表(仅进程生命周期内有效,不写盘,除非用户自己的 opencode.json 配置中已有该规则),并回溯性地解析其它已被新规则覆盖的待处理请求。

默认权限集(agent/agent.tsdefaults):基线 "*": "allow",但 doom_loop: "ask"external_directory(项目根目录外的路径)默认 ask (白名单目录例外:截断输出目录、tmp 目录、skill 目录、reference 目录); question: "deny"(question 工具在权限层默认禁用,另外还受工具注册表里 questionEnabled 的客户端类型检查约束);plan_enter/plan_exit: "deny" 默认禁用;以及一条**.env 文件读取 ask 规则**,仿照 GitHub Node.gitignore.env 模式(*.env*.env.* → ask;*.env.example → allow)——即 默认策略中硬编码了一个针对密钥文件的启发式防护。

每个 agent 在此之上叠加覆盖(例如 build agent 允许 question/ plan_enterplan agent 拒绝除白名单 plans-markdown 路径外的一切编辑, 拒绝 task.generalexplore agent 除只读工具白名单外全部拒绝)。

Subagent 权限继承:agent/subagent-permissions.tsderiveSubagentSessionPermission() 把父 session 权限与 subagent 自身规则 合并,并强制拒绝 todowrite/task 递归以及任何配置在 config.experimental.primary_tools 中的工具(保留给主 agent 专用)。

凭据/认证:独立的 Auth/Credential/McpAuth/McpOAuthProvider 服务 (packages/opencode/src/authpackages/core/src/credential.tsmcp/auth.tsmcp/oauth-provider.ts)——本次未逐行深挖,但结构上这些 服务持有 provider API key/OAuth token 及 MCP server 认证信息,与权限规则 系统(“能否触碰这个工具/路径”)职责分离(认证 = “如何向 provider/MCP server 证明身份”)。

沙箱与执行隔离

无沙箱。 官方 V2 spec 明确写明(specs/v2/tools.md 204 行):“Bash is not sandboxed: the spawned shell runs with the host user’s filesystem, process, and network authority.”(Bash 未沙箱化:生成的 shell 以宿主用户的 文件系统、进程与网络权限运行)。V1 的 shell 工具(tool/shell.ts)通过 ChildProcess.make/cross-spawnCrossSpawnSpawner)直接在宿主 OS 上以 宿主用户权限生成命令——工具实现中未发现容器、VM、seccomp/AppArmor profile 或 chroot。

取而代之的是静态预执行风险分析 + 权限门控tool/shell.tstree-sitter-bash/tree-sitter-powershell(经 web-tree-sitter 加载的 WASM 解析器)解析 shell 命令,遍历语法树找出涉及文件的命令 (FILES/CWD/CMD_FILES 命令名集合:rm, cp, mv, mkdir, touch, chmod, chown, cat, cd, ... 及 PowerShell 对应项),解析涉及路径,若任一路径落在 当前项目/实例目录之外containsPath() 检查),触发 external_directory 权限 ask。非文件类命令则触发一个基于粗粒度 pattern (BashArity.prefix(tokens) + " *" 通配符)的通用 bash 权限 ask, 使”always allow”授权能覆盖整个命令族而非单次精确调用。这是尽力而为的静态 分析,明确不具强制力(specs/v2/tools.md:“Best-effort scans of absolute command arguments produce advisory warnings only; they are not sandbox boundaries”)。

命令执行有超时(defaultTimeoutMs,默认 2 分钟,可按次覆盖),可中止 (ctx.abort AbortSignal),输出捕获有界/截断(truncate.tsMAX_METADATA_LENGTH = 30_000 字符,用于实时元数据预览)。

与模型的协同设计

  • 按模型家族分化系统提示(session/system.tsprovider()): Anthropic/OpenAI-gpt/OpenAI-o-series(“beast”)/Codex/Gemini/Kimi/Trinity 各有专属基础提示——即该 harness 显式按 vendor 调整提示风格,而非用一份 通用提示;
  • 按模型选择工具:apply_patch(OpenAI 的 patch 格式)只在部分 GPT 模型下替换通用的 edit/write 工具(tool/registry.tsusePatch 检查)——直接证据表明工具面会适配模型的原生编辑能力;
  • Provider 请求编码通过一层基于 AI SDK 的 LLM/aisdk.ts/ native-request.ts/native-runtime.tssession/llm/*,本次未深挖) 抽象,把 provider 中立的请求映射到各 provider 的具体协议——V2 spec (CONTEXT.md)称之为 “LLM protocol adapter”,明确区分 “Model Request Options”(provider 语义相关)与 “Generation Controls”(provider 中立的 采样参数),是刻意为多 provider 协同设计留出的抽象边界;
  • 推理/思考 token 处理:processor.ts 处理 reasoning-start/delta/end 事件并透传 provider 元数据;CONTEXT.md 明确讨论了 “Native Continuation Metadata”(推理签名、provider 托管的 item ID)只有在同一 provider/model 继续对话时才存活——若模型/provider 切换则退化为纯文本。这是专门针对 Anthropic 扩展思考签名和 OpenAI 加密推理续接语义的设计适配;
  • experimental.provider.small_model 插件钩子专门用于让集成方为轻量任务 (如标题生成)按 provider 替换为更便宜/更快的模型。

轨迹利用(session/trajectory 是否反哺训练/评测)

未发现 session/轨迹反哺训练或评测的证据。属实的部分:session 在 SQLite 中 事件溯源持久化(session.next.* 事件族,sessions.events({sessionID, after}) 持久回放 API,按 specs/v2/session.md),因此支撑此类复用所需 的原始数据在结构上是存在的,但未发现任何代码路径把轨迹导出用于微调、RL 或 benchmark 构建。packages/share/session.ts/share/share-next.ts 实现的是 session 分享功能(大概率是 opencode.ai 的公开可分享会话 链接),这是面向人类的会话转录分享功能,不是训练/评测数据管线。 packages/stats 是 opencode.ai 公开排行榜网站(用量统计聚合),不是 轨迹到训练的桥梁。

与同类 harness 的关键差异(1-3 条,可以先留一句概述,后续 synthesis 阶段会做跨 harness 对比)

  • 整体建构在 Effect 函数式效应框架之上(Effect.Service/Layer/ Effect.gen),这在同类开源编码 agent harness 中较少见,天然带来 统一的 span/日志埋点(Effect.withSpan)和跨库 trace-context 桥接 (AI SDK span 挂靠 Effect span 之下)。
  • 系统提示层面存在与 Claude Code 已知系统提示高度相似的结构与措辞 (session/system.tsdefault.txt),这是本次调研中在同类 harness 里观察到的较明显案例,值得在跨 harness 对比阶段专门列出。
  • V1(shipped)/V2(Effect-native 重写,未上线)两套实现并存于同一 仓库,且 V2 official spec(CONTEXT.mdspecs/v2/*.md)比大多数 同类项目的公开设计文档更形式化、更精确(专门定义 Context Epoch / System Context 等术语),是本次调研中”设计文档质量”维度上的一个正 样本,具体跨 harness 排位留待 synthesis 阶段。
  • 跨 harness 详细对比(agent loop 结构、压缩策略、权限模型等的量化 比较)留待 synthesis 阶段统一处理,此处不展开。

原始源码定位

  • repo: https://github.com/sst/opencode
  • commit/version analyzed: eb6ff0c1e049e5dfb6f61eb74f925c0a8007490c(浅克隆, commit 时间 2026-07-06 13:35:10 UTC,2026-07-07 拉取分析)
  • 关键文件列表(相对仓库根目录):
    • packages/opencode/src/session/prompt.ts(1631 行,runLoop 主循环)
    • packages/opencode/src/session/processor.ts(718 行,事件处理/doom-loop 防护)
    • packages/opencode/src/session/system.ts(系统提示组装)
    • packages/opencode/src/session/compaction.ts(562 行)+ session/overflow.ts(压缩/溢出)
    • packages/opencode/src/session/reminders.ts(合成 reminder 注入)
    • packages/opencode/src/session/session.ts(1018 行,Session CRUD/分页)
    • packages/opencode/src/session/prompt/*.txt(各模型家族系统提示)
    • packages/opencode/src/agent/prompt/*.txt(任务专用提示)
    • packages/opencode/src/tool/tool.ts(工具定义包装)
    • packages/opencode/src/tool/registry.ts(451 行,工具注册表)
    • packages/opencode/src/tool/task.ts(347 行,subagent 派生)
    • packages/opencode/src/tool/shell.ts(646 行,bash 执行+静态分析)
    • packages/opencode/src/agent/agent.ts(454 行,agent 定义)
    • packages/opencode/src/agent/subagent-permissions.ts
    • packages/opencode/src/permission/index.ts(224 行,权限引擎)
    • packages/opencode/src/skill/discovery.ts(141 行)+ skill/index.ts(354 行)
    • packages/opencode/src/plugin/loader.ts(238 行)
    • packages/plugin/src/index.ts(Hooks 接口)
    • packages/opencode/src/mcp/index.ts(MCP 客户端)
    • packages/core/src/observability.ts + observability/otlp.ts(OTel 导出)
    • CONTEXT.md(根目录,226 行,官方 V2 设计文档)
    • specs/v2/session.mdspecs/v2/tools.md(官方 V2 设计 spec)
    • packages/core/src/database/migration/*(Drizzle/SQLite 迁移)

一手源存档(sources/)

存档目录:/Users/zhao/projects/self-wiki/ai-research/sources/harness/opencode/

  • NOTES.md — stage 1 调研员详细笔记(12 维度逐条,含文件路径/行号)
  • key-files/AGENTS.mdkey-files/CONTEXT.md — 根目录官方文档
  • key-files/agent/agent.tskey-files/agent/subagent-permissions.tskey-files/agent/prompt-txt/ — agent 定义与专用提示
  • key-files/session/prompt.tssession/processor.tssession/system.tssession/compaction.tssession/overflow.tssession/reminders.tssession/session.tssession/prompt-txt/ — session 核心实现
  • key-files/tool/tool.tstool/registry.tstool/task.tstool/shell.ts — 工具体系
  • key-files/permission/index.ts — 权限引擎
  • key-files/skill/index.tsskill/discovery.ts — skill 体系
  • key-files/plugin/loader.tsplugin/hooks-index.ts — 插件体系
  • key-files/core-observability/observability.tscore-observability/observability-dir/ — OTel 可观测性
  • key-files/specs/config.mdspecs/instructions.mdspecs/provider-policy.mdspecs/session.mdspecs/tools.md — 官方 V2 设计 spec