1. 从 planning-with-files 说起:为什么我要给 opencode 写 codecraft 插件
planning-with-files 这个项目你可能刷到过,它的核心思路很朴素:让 AI 代理像 Manus 那样工作,把任务计划、研究发现、进度日志持久化成 markdown 文件,而不是全部塞在上下文里。它本质上是 Claude Code 的一个 skill,靠文件系统做“外部记忆”,让长任务不会因为上下文窗口被截断而丢失方向。我第一眼看到就觉得这个模式对写代码的 agent 特别合适——因为写代码本身就是“计划、查资料、改、验证”的循环。
问题是它只支持 Claude Code。我平时主力用 opencode,一个终端里的开源编码代理,配置简单、启动快,插件机制也开放。于是我就想,能不能用 opencode 自己给自己写一个类似 planning-with-files 的插件?这就是 codecraft 的由来。codecraft 要做的事情很明确:在 opencode 会话里自动维护三个文件——task_plan.md(任务计划)、findings.md(研究发现)、progress.md(进度日志),在关键节点提醒 agent 更新它们,而不是全程干预。
这篇文章聚焦的是完整开发流程:怎么在 opencode 里写这个插件、怎么对比 planning-with-files 的设计、怎么通过 TaoToken 统一 Key 和 API 通道把模型能力接进来,最后交付可复制的配置片段和本地验证步骤。适合谁看?如果你在用 opencode、Claude Code 或者类似的编码代理,想自己写插件扩展能力,又不想在多个模型供应商之间来回切换 Key,那这篇就是给你准备的。我踩过的坑包括插件导致 opencode 启动白屏、tool is not defined报错、缓存目录残留导致模块找不到,这些都会在排障章节里讲清楚。
先说结论:codecraft 不是一个复杂的插件,它的价值在于“文件即记忆”这个模式。opencode 的插件 API 很简洁,简洁到你一开始根本判断不出插件到底加载成功没有。所以我会把验证步骤写得足够细,让你能确认插件真的生效了。
2. TaoToken 统一 Key 接入:opencode 前置准备与模型通道配置
在写插件之前,得先把模型通道搞定。opencode 支持多种 provider,但如果你同时用 Claude、GPT、Gemini 或者国产模型,每个都要单独配 Key、单独记 Base URL,管理起来很烦。TaoToken 的作用就是把这些模型能力收敛到一个统一的 Key 和 API 通道上,opencode 只需要认一个 provider 就行。
TaoToken 的官网是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数,配置里填的就是这个干净的地址。你需要先去控制台创建一个 API Key,地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,然后在 API Keys 页面生成密钥:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。
opencode 的配置文件位置分平台。Windows 下在C:\Users\<你的用户名>\.config\opencode\,Linux 下在~/.config/opencode/。这个目录里通常有opencode.json(主配置)和plugin/子目录(放插件)。我建议你先在没装任何插件的情况下启动一次 opencode,确认基础环境是好的,再动插件——这个习惯能帮你省掉后面一半的排障时间。
opencode 的 provider 配置支持 OpenAI 兼容格式。TaoToken 的 API 是兼容 OpenAI 接口规范的,所以你可以把它当成一个自定义 provider 接进去。关键三件套是:Base URL、API Key、Model ID。Base URL 填https://taotoken.net/api,API Key 填你生成的那串,Model ID 填你要用的模型名(比如claude-sonnet-4-5或者你账号里可用的其他模型)。
这里有个细节:opencode 的配置里 provider 的npm字段决定用哪个 SDK 适配器。用 OpenAI 兼容通道时,通常指定@ai-sdk/openai-compatible。如果你不确定,可以先只配一个 provider 跑通,再扩展。TaoToken 的好处是你不用为每个模型单独配一个 provider,一个 Key 就能切换模型,插件里调用模型时也不用关心底层是哪个供应商。
另外提醒一句:不要把生产数据库或者敏感凭据写进插件配置。codecraft 插件本身只读写 markdown 文件,不碰数据库,这一点在设计上就要守住。模型调用走的是 opencode 自己的 provider 通道,插件不直接持有 Key,这样职责清晰,也安全。
如果你打算长期用编码代理跑 Agent 任务,可以考虑 TaoToken 的 Coding Plan,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合高频编码场景。不过这篇文章的重点是插件开发,通道配好能跑通就行。
3. 可复制配置:opencode.json 与 codecraft 插件片段
这一节给你可以直接抄的配置。先看opencode.json,路径是~/.config/opencode/opencode.json(Windows 下把~换成C:\Users\<用户名>)。下面是一个最小可用的 provider 配置,把 TaoToken 作为统一通道接进来:
{ "$schema": "https://opencode.ai/config.json", "provider": { "taotoken": { "npm": "@ai-sdk/openai-compatible", "name": "TaoToken", "options": { "baseURL": "https://taotoken.net/api", "apiKey": "sk-你的TaoToken密钥" }, "models": { "claude-sonnet-4-5": { "name": "Claude Sonnet 4.5" } } } }, "model": "taotoken/claude-sonnet-4-5" }注意model字段的写法是provider/model,也就是taotoken/claude-sonnet-4-5。这个格式在 opencode 里是统一的,插件里如果要用模型,也遵循同样的引用方式。apiKey建议不要硬编码在提交到 git 的文件里,本地用可以,团队协作时换成环境变量引用。
接下来是 codecraft 插件的核心片段。opencode 插件是一个导出函数的 TypeScript 文件,放在~/.config/opencode/plugin/codecraft.ts。下面这段是精简后的骨架,展示了插件如何注册工具、如何写文件:
import type { Plugin } from "@opencode-ai/plugin" import { writeFile, mkdir } from "fs/promises" import { join } from "path" export const CodeCraftPlugin: Plugin = async ({ client, directory }) => { const planDir = join(directory, ".opencode") async function ensureDir() { await mkdir(planDir, { recursive: true }) } return { tool: { codecraft_plan: { description: "创建或更新任务计划文件 task_plan.md", args: { taskName: { type: "string", description: "任务名称" }, objective: { type: "string", description: "任务目标" } }, async execute(args) { await ensureDir() const content = [ `# 任务计划`, ``, `任务名称: ${args.taskName}`, `目标: ${args.objective}`, ``, `## 阶段`, `1. 需求澄清`, `2. 方案设计`, `3. 实现`, `4. 验证`, ``, `## 成功标准`, `- 插件可加载`, `- 三个文件正确生成` ].join("\n") await writeFile(join(planDir, "task_plan.md"), content, "utf-8") return `已写入 ${join(planDir, "task_plan.md")}` } } } } }这段代码里最关键的是tool字段的注册方式。opencode 插件通过返回一个对象来声明它提供的工具,每个工具要有description、args和execute。execute里就是你的业务逻辑。注意我用了directory参数,它是 opencode 传进来的当前工作目录,这样文件会写到项目的.opencode/下,而不是全局配置目录。
对比 planning-with-files 的设计:它是 Claude Code 的 skill,靠 skill 描述文件触发,文件写在项目根目录。codecraft 改成插件形式后,触发方式变成了工具调用,文件写在.opencode/下。两者都是“文件即记忆”,区别在于 codecraft 更依赖 opencode 的插件生命周期,而 planning-with-files 更依赖 skill 的提示词注入。
如果你还想加findings.md和progress.md,照着codecraft_plan再写两个工具就行,结构完全一样,只是文件名和内容模板不同。我建议一开始只做一个工具,跑通了再加,否则调试成本会翻倍。
4. 本地验证:插件加载与任务规划效果实测
配置写完了,怎么确认插件真的加载了?这是 opencode 最让人懵的地方——它太简洁,加载成功和失败在界面上可能都没什么明显提示。我试过几种验证方式,下面这套是最靠谱的。
第一步,确认文件放对位置。插件文件必须在~/.config/opencode/plugin/codecraft.ts,或者项目级的.opencode/plugin/codecraft.ts。opencode 会扫描这两个位置。如果你放错了目录,它不会报错,只是静默不加载。
第二步,启动 opencode。在终端里直接敲opencode。如果启动后是白屏或者黑屏、没有任何输出,大概率是插件初始化时抛异常了。正常启动应该能看到 TUI 界面。这一步是分水岭:能进界面,说明插件至少没把启动流程搞崩。
第三步,手动调用工具验证。在 opencode 会话里输入:
/codecraft plan --taskName "test" --objective "测试插件安装"如果插件注册成功,这个命令会触发codecraft_plan工具,然后在当前项目的.opencode/目录下生成task_plan.md。执行后你应该能看到类似“已写入 /path/to/.opencode/task_plan.md”的返回。
第四步,检查生成的文件。用cat或者编辑器打开.opencode/task_plan.md,内容应该包含任务名称、目标、四个阶段和成功标准。我实测下来,生成的文件长这样:
# 任务计划 任务名称: test 目标: 测试插件安装 ## 阶段 1. 需求澄清 2. 方案设计 3. 实现 4. 验证 ## 成功标准 - 插件可加载 - 三个文件正确生成看到这个文件,基本可以确认插件导入成功、运行成功了。如果你还加了findings.md和progress.md的工具,同样调用一次,确认三个文件都在。
这里有个我踩过的坑:opencode 的插件加载是异步的,有时候你启动后立刻调用工具,插件可能还没注册完。等一两秒再调用,或者先随便发一条消息让会话初始化,再调工具,成功率更高。
另一个验证角度是看日志。opencode 的日志在~/.local/share/opencode/log/下(Windows 是C:\Users\<用户名>\.local\share\opencode\log\)。如果插件加载失败,日志里会有堆栈信息。我遇到过的ReferenceError: tool is not defined就是在日志里看到的,指向插件文件的某一行。这个报错通常是因为你用了tool这个变量但没导入,或者插件 API 版本对不上。
关于“插件到底有没有生效”,我的经验是:不要靠界面判断,靠文件系统判断。只要.opencode/task_plan.md被正确写入,插件就是活的。这个思路和 planning-with-files 一致——文件是唯一可信的状态。
5. 常见报错排查:白屏、tool is not defined 与模块找不到
这一节把我在三台机器上遇到的真实报错逐个拆开。这些报错在 opencode 插件开发里很典型,你大概率也会碰到。
报错一:启动白屏或黑屏,无任何输出。这是最吓人的一个,因为看起来像 opencode 整个挂了。原因几乎都是插件初始化时抛了异常,把启动流程卡住了。我当时的插件在初始化时调用了client.app.log(),这个调用在某些版本下会导致挂起。解决办法有两个:一是把插件文件改名,比如codecraft.ts改成codecraft.tsbak,opencode 扫描不到就不会加载,先恢复启动;二是用opencode run命令让 opencode 自己去修:
opencode run "codecraft插件导入到opencode后,opencode启动无响应(显示黑屏或者白屏,无输出),请解决问题"注意,如果 opencode 崩得太彻底,opencode run也可能卡住。这时候就得手动改名插件文件,先让 opencode 能起来,再让它改代码。我建议开两个 opencode 窗口,一个写代码,一个调代码,一个崩了还有另一个能用。
报错二:ReferenceError: tool is not defined。完整报错类似:
UnknownError ReferenceError: tool is not defined at <anonymous> (G:\opencode\.opencode\plugin\codecraft.ts:78:16)这个报错指向插件文件的第 78 行。原因是你用了tool这个标识符,但当前 opencode 版本的插件 API 里没有导出它,或者你忘了从@opencode-ai/plugin导入对应类型。解决办法是检查你的 import 语句,确认用的是当前版本支持的 API。opencode 版本更新比较快,插件 API 偶尔会变,遇到这种报错先看版本号,再对照官方插件文档调整。
报错三:Cannot find module './chop-string.js'。这个报错出现在 npm 安装的 opencode 版本里:
Error: Unexpected error, check log file at C:\Users\Admin\.local\share\opencode\log\2026-01-13T083643.log for more details error: Cannot find module './chop-string.js' from 'C:\Users\Admin\.cache\opencode\node_modules\codecraft\src\index.js'原因是 opencode 把插件当成 npm 包缓存到了~/.cache/opencode/node_modules/codecraft/,但缓存不完整或者版本对不上。我当时的处理是删掉整个~/.cache/opencode/目录,然后重启。如果还不行,再删~/.config/opencode/里的插件文件,最后删项目里的.opencode/目录。我实测下来,真正生效的是删掉项目里的.opencode/目录——因为那里残留了旧的插件文件,opencode 优先加载了它。
报错四:TypeError: Failed to fetch。这个报错出现在升级 opencode 到一半的时候,界面报Something went wrong。原因是升级过程中有文件缺失,或者还有一个旧的 opencode 进程没关掉。我当时的坑是有一个opencode-cli.exe还在后台跑着,导致重装不干净。关掉所有 opencode 进程再重装就好了。这个报错和插件本身没关系,但会干扰你判断插件问题,所以排障时先确认 opencode 本体是干净的。
排查顺序我总结成一句话:先确认 opencode 本体能启动,再确认插件文件位置对,最后看日志定位插件代码问题。不要一上来就怀疑插件逻辑,很多时候是环境残留。
6. 继续扩展 codecraft:把统一 Key 用在更多 Agent 场景
codecraft 现在能做到的还比较基础:注册工具、写三个 markdown 文件。但它的骨架已经能支撑更多玩法。比如你可以让findings.md在每次 agent 调用搜索或者读文件后自动追加一条记录,让progress.md在每次工具调用后打一个时间戳。这些都可以在插件的execute里加逻辑,不需要改 opencode 本体。
模型调用这块,因为前面已经把 TaoToken 配成了统一 provider,插件里如果要让 agent 做总结或者规划,直接走 opencode 的模型通道就行,不用在插件里再管 Key。这是统一 Key 接入的最大好处:插件代码里不出现任何供应商细节,换模型只改opencode.json里的model字段。
如果你想把 codecraft 用在更长的编码任务上,比如让它自动维护任务计划、在每轮对话后更新进度,那模型调用频率会上去,这时候 Coding Plan 会更合适:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。它针对的就是这种持续编码、Agent 反复调用的场景。
验证模型通道是否正常,可以直接用模型对话页面测一下:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite 。确认 Key 能用、模型能返回,再回到 opencode 里跑插件。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有 Base URL、鉴权方式和模型列表的说明,配置遇到疑问可以对照。
最后说一个我真实的体会:用 opencode 给 opencode 写插件,逻辑上确实有点绕,因为你既是开发者又是使用者,调试的时候分不清是插件的问题还是 opencode 的问题。我的建议是,每加一个功能就验证一次,不要一次写一大堆再测。codecraft 目前测试和评估还是难题,尤其是“插件有没有在关键节点提醒 agent”这种软性行为,很难自动化验证。但至少文件生成是硬指标,先把硬指标跑通,再慢慢调软性行为。
如果你也在用 opencode,建议从最小的codecraft_plan工具开始,跑通文件写入,再逐步加findings和progress。配置片段上面都能直接抄,遇到白屏先改名插件文件恢复启动,再让 opencode 自己修。这套流程我走了三台机器,能复现,也能排障。