关于 opencode-runner
opencode-runner 是将编码任务委托给 opencode 的技能,可从可用的免费云端模型中选择并报告进度。执行前须由用户确认;任务失败时不会自行接手编码。
主要功能
- 01发现符合条件的免费云端模型
- 02由用户选择模型
- 03运行任务前要求确认
- 04通过简短状态检查监控进度
- 05任务结束后清理进程
适用场景
- 01从项目目录委托编码任务
- 02从可用的免费 opencode 模型中选择
- 03无需读取完整日志即可跟踪运行
- 04运行后检查变更文件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ luongnv89/ skills --skill opencode-runner安装后在 Claude Code 中输入/opencode-runner确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
docs/README.mdevals/evals.jsonreferences/edge-cases.mdexpected-output.mdfinal-report.md详细介绍
OpenCode Runner
使用免费模型将编码任务委托给 opencode——零成本,完全自动化。
OpenCode(opencode.ai)是一款终端 AI 编码助手,支持多种提供商和模型。此技能会自动选择当前可用的最佳免费模型、启动任务,并向你报告进度。
前提条件
- 已安装 opencode:必须能成功运行
which opencode;如果尚未安装,请运行npm i -g opencode-ai@latest或brew install opencode进行安装 - 可访问互联网:通过 OpenCode Zen 选择云端模型和执行任务时需要联网
- 项目上下文:处理文件上下文任务时,当前工作目录应为项目根目录
关键规则
-
绝不要自行完成任务。 此技能的唯一用途是将工作委托给 opencode。如果未安装 opencode、无法运行,或者没有可用的免费云端模型,请向用户报告问题并停止。不得改为直接编辑文件、自行编写代码或使用其他工具来完成用户的编码任务。此技能的核心就是由 opencode 完成工作。
-
只选择云端模型。 绝不要选择本地模型(例如
ollama/*、lmstudio/*或任何在 localhost 上运行的模型)。只能选择opencode/*提供商命名空间中的模型,这些模型托管在 OpenCode Zen 上。本地模型的可用性和性能不可预测,而且可能不支持 opencode 所需的工具调用能力。 -
务必清理运行环境。 opencode 会启动后台进程(LSP 服务、MCP 服务、node worker),这些进程在任务完成后仍会继续运行。每种执行路径——成功、失败、出错或超时——都必须以第 6 阶段的清理步骤结束。残留的 opencode 进程会在后台悄悄消耗 CPU 和内存,直到用户发现机器变得异常缓慢。
编辑前同步仓库(强制)
在现有仓库中创建、更新或删除文件之前,先将当前分支与远程同步:
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin
git pull --rebase origin "$branch"
如果工作区不干净,先暂存更改,再同步,然后恢复更改:
git stash push -u -m "pre-sync"
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin && git pull --rebase origin "$branch"
git stash pop
如果缺少 origin 或发生冲突,请停止并在继续之前询问用户。
阶段 1:验证安装
检查是否已安装 opencode,以及是否为最新版本。
步骤 1:检查是否已安装
which opencode && opencode --version
如果找不到 opencode,请告诉用户:
尚未安装 opencode。请使用以下任一命令进行安装:
curl -fsSL https://opencode.ai/install | bash或
npm i -g opencode-ai@latest或(macOS)
brew install opencode
然后立即停止,并在最终报告中注明 BLOCKED — opencode is not installed——不要继续任何其他阶段,不要尝试自行完成任务,也不要编辑任何文件。等待用户安装 opencode 后重新调用此技能。
步骤 2:检查更新
- 运行
opencode upgrade。此命令会升级到最新版本,或确认当前已安装的版本已是最新版本。 - 如果
opencode upgrade返回非零退出码,请告知用户错误信息,并建议手动运行opencode upgrade。然后继续执行第 3 项。 - 再次运行
opencode --version。 - 如果
opencode --version返回非零退出码,请停止,并注明BLOCKED — opencode does not start after the upgrade。不要继续阶段 2。
阶段 2:发现免费模型并让用户选择
查询可用模型,向用户列出免费模型,并让用户选择。如果用户未作选择,则按优先级顺序选择。
opencode models 2>/dev/null
免费模型优先级列表(用户未指定时的默认顺序)
| 优先级 | 模型 ID | 备注 |
|---|---|---|
| 1 | opencode/deepseek-v4-flash-free | 近期表现强劲的免费编码模型 — 首选默认项 |
| 2 | opencode/minimax-m2.5-free | MiniMax 免费档 — 通用能力出色 |
| 3 | opencode/nemotron-3-super-free | NVIDIA Nemotron 免费档 |
| 4 | opencode/big-pickle | 免费备用模型 |
| 5 | opencode/gpt-5-nano | 小型备用模型;仅当 opencode models 将其价格标为 $0 时才免费 |
模型 ID 会不断变化。当某个模型的 ID 位于 opencode/* 命名空间,且满足以下任一条件时,即符合免费档资格:ID 以 -free 结尾、ID 为 opencode/big-pickle,或 opencode models 输出显示价格为 $0。按后缀匹配,而非按完整 ID 精确匹配。如果输出中没有 $0 价格,则不要列出 opencode/gpt-5-nano。
选择逻辑
-
运行
opencode models并收集所有条目。 -
筛除所有非
opencode/*模型 — 忽略任何来自ollama/*、lmstudio/*、nvidia/*或其他命名空间的模型。只有由云端托管的opencode/*模型符合条件。 -
在剩余列表中,仅保留符合免费档资格的模型。
-
按优先级顺序,以编号选项的形式向用户展示免费模型,并将优先级 1 标记为默认项。尽可能使用
<options>格式。示例:我找到了以下可通过 opencode 使用的免费云端模型。请选择一个,或接受默认项。
opencode/deepseek-v4-flash-free(默认 — 优先级 1)opencode/minimax-m2.5-freeopencode/nemotron-3-super-freeopencode/big-pickle
-
如果用户指定了模型,就使用该模型。如果用户说“默认”“你来选”“随便”,或没有指定,则使用优先级最高的可用免费模型。
-
如果没有符合免费档资格的模型,停止并提示
BLOCKED — no free cloud model available— 不要改用本地模型、付费模型,也不要自行完成任务。
隐私说明(始终与模型列表一同显示):OpenCode Zen 的免费模型可能会使用收集的数据来改进模型。
第 3 阶段:执行前确认
调用 opencode 前,向用户展示一屏摘要并获得明确确认。这样可在消耗任何令牌前,发现模型或提示词选择错误。
展示以下内容:
准备委托给 opencode
- 模型:
opencode/deepseek-v4-flash-free(免费档)- 工作目录:
/Users/.../current-project- 上下文文件:
path/to/foo.py、path/to/bar.py(或“无”)- 提示词: (逐字引用提示词,可包含多行)
- 预计耗时: 未知 — opencode 具有非确定性;即使超时也会运行清理操作
确认以继续,或告诉我需要修改什么(模型、提示词、文件)。
然后向用户提供两个 <options>:“继续”和“修改内容”。等待用户确认。用户确认前,不要调用 opencode run。
如果用户要求修改任何内容(更换模型、编辑提示词、添加或移除上下文文件),则返回并更新相应字段,重新展示摘要并再次询问。如果用户取消,则停止并提示 BLOCKED — the user cancelled before the run。
第 4 阶段:执行任务
使用已确认的模型运行编码任务。始终在后台运行,并将输出重定向到日志文件 — 这是第 5 阶段低令牌监控策略的必要要求。
RUN=/tmp/opencode-run-$(date +%s)
( opencode run -m "[confirmed-model-id]" "[confirmed prompt]" > "$RUN.log" 2>&1; echo $? > "$RUN.exit" ) &
echo $! > "$RUN.pid"
echo "opencode started: run=$RUN pid=$(cat "$RUN.pid")"
记录此处打印的 run= 值,并在后续第 5 阶段和第 6 阶段的所有 shell 命令中按原样替换该值。 每次 Bash 调用都会重新启动,因此在读取 "$RUN.log"、"$RUN.pid" 或 "$RUN.exit" 之前,先将 RUN 重新绑定为记录的前缀。.pid 文件是所有权记录:其中保存的是包装子 shell 的 ID,其子进程为 opencode run。opencode 结束时,包装进程会将其退出代码写入 .exit,因为后续的 shell 无法对它调用 wait。
处理多行或复杂提示词
对于涉及文件或需要详细上下文的任务,请使用 --file 标志:
RUN=/tmp/opencode-run-$(date +%s)
( opencode run -m "[confirmed-model-id]" --file path/to/relevant-file.py "[task description]" > "$RUN.log" 2>&1; echo $? > "$RUN.exit" ) &
echo $! > "$RUN.pid"
echo "opencode started: run=$RUN pid=$(cat "$RUN.pid")"
不建议在前台执行——将完整的 opencode 输出流式传回上下文会浪费令牌。Phase 5 监控只读取日志末尾。
Phase 5:以最少令牌进行监控
opencode 的输出很冗长。将完整日志流式传回上下文代价高昂——一次较长的运行就很容易产生超过 10k 个令牌的流式输出。请改用以下轻量级轮询协议。
轮询协议
每次检查只运行一条简短的状态命令。它最多返回约 200 字节,足以了解状态、经过的时间和最新活动行,而无需读取整个日志。
RUN=/tmp/opencode-run-1234567890 # paste the run= value Phase 4 printed
status() {
pid=$(cat "$RUN.pid" 2>/dev/null)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then s=running; else s=done; fi
ec=$(cat "$RUN.exit" 2>/dev/null)
bytes=$(wc -c < "$RUN.log" 2>/dev/null || echo 0)
last=$(tail -n 1 "$RUN.log" 2>/dev/null | tr -d '\r' | cut -c1-160)
printf 'status=%s pid=%s exit=%s bytes=%s last=%q\n' "$s" "${pid:-none}" "${ec:-none}" "$bytes" "$last"
}
status
这一行就是完整的进度样本。不要运行 tail -n 50,不要运行 cat "$RUN.log",也不要流式读取 stdout——这些做法都违背了初衷。
轮询频率(必须遵守)
- 第 1 次和第 2 次轮询前等待 30 秒。之后每次轮询前等待 60–120 秒。
- 最多轮询 6 次。如果第 6 次轮询仍显示
status=running,请询问用户是继续等待还是终止进程。在用户回复前不要再次轮询。如果用户表示继续等待,则按相同规则最多再轮询 6 次。 - 连续两次轮询的
bytes=数值相同,则表示运行已停滞。如果经过 5 分钟仍没有bytes=增长,则表示运行已超时。如果运行停滞或超时,请询问用户是继续等待还是终止进程。只有在用户批准后才能终止,然后按照发生错误、停滞或超时时中的说明操作。
轮询期间的报告内容
每次检查根据 status() 输出报告一行简短信息:
轮询 2(t+60s):运行中,已写入 4.2 KB,最后一行:“正在编辑 src/foo.py …”
不要粘贴原始日志。不要总结 opencode 正在“思考”什么——无法从日志末尾的一行判断。只报告:状态、经过的时间、字节增长情况和最后一行。
完成时
当 status=done 时:
- 只读取日志末尾,不要读取整个日志:
tail -n 40 "$RUN.log"。这是 opencode 最后打印的摘要(变更的文件、使用的令牌、错误)。 - 对运行结果进行分类。
exit=0表示成功。任何其他exit=值都表示失败。exit=none表示包装进程在 opencode 完成前被终止:应视为失败。 - 如果工作目录是 git 仓库,则运行
git status --porcelain,列出发生变更的文件。这是只读操作:绝不编辑、暂存或还原这些文件。 - 不要粘贴完整日志。如果用户要求保留日志,则跳过 Phase 6 第 3 步中删除
"$RUN.log"的操作,并在最终报告中提供其路径。 - 如果任务失败,建议使用 Phase 2 列表中下一个空闲的模型重试。
- 执行 Phase 6 清理——无论成功与否,这都是必需的。
- 打印最终报告(Final Report)。
发生错误、停滞或超时时
- 向用户报告错误或停滞情况(一行,根据最后一次轮询的信息整理)。
- 建议使用下一个空闲的云端模型重试。
- 如果已尝试所有免费模型,建议用户运行
opencode auth list检查提供商身份验证。 - 绝不要自行尝试完成任务作为后备方案。
- 执行 Phase 6 清理——始终必须执行。
- 打印最终报告(Final Report)。
Phase 6:清理(必须执行)
每次执行——无论成功、失败、出错还是超时——都必须以清理结束。opencode 会生成子进程(LSP 服务、MCP 服务、node 工作进程),即使主进程退出后,这些进程仍会继续运行。若不清理,这些孤儿进程会不断累积并消耗系统资源。
第 1 步:终止 opencode 进程树
如果你在后台启动了 opencode,请使用 pidfile 中记录的运行前缀作为所有权凭据:
RUN=/tmp/opencode-run-1234567890 # paste the run= value Phase 4 printed
pid=$(cat "$RUN.pid" 2>/dev/null)
if [ -n "$pid" ]; then
pkill -TERM -P "$pid" 2>/dev/null # opencode runs as a child of the wrapper subshell
kill "$pid" 2>/dev/null
sleep 2
pkill -KILL -P "$pid" 2>/dev/null
kill -9 "$pid" 2>/dev/null
fi
第 2 步:查找并终止孤儿 opencode 进程
- 运行
pgrep -fl "opencode run",列出残留的opencode run进程。 - 如果列出了任何进程,则运行
pkill -f "opencode run"。
此模式不会匹配用户的交互式 TUI 会话(不带子命令的 opencode)。不要终止该会话。
第 3 步:清理临时文件
rm -f "$RUN.log" "$RUN.pid" "$RUN.exit" 2>/dev/null
如果用户要求保留日志(Phase 5,完成时第 4 项),请从此命令中移除 "$RUN.log"。
第 4 步:确认清理
- 运行
pgrep -f "opencode run" >/dev/null && echo cleanup=incomplete || echo cleanup=complete。 - 如果输出
cleanup=complete,则报告:清理完成 — 没有残留的opencode run进程。 - 如果输出
cleanup=incomplete,则警告:警告: 仍有一些opencode run进程在运行。请手动运行pkill -f "opencode run"进行清理。
最终报告
Phase 6 结束后,按以下顺序以简洁文本打印一份最终报告:Result:(COMPLETE、PARTIAL — <reason> 或 BLOCKED — <reason>)、Evidence:(仅列出已运行的检查)、Uncertainty:,然后是 Decision:(需要获得的批准,或 No approval needed.)。如果在 opencode run 启动前停止,则跳过 Phases 4–6,直接打印报告。状态规则、示例和读者检查见 references/final-report.md。
预期输出
完整的示例区块见 references/expected-output.md,其中包含用户在各阶段应看到的内容(模型选择器、确认摘要、低 token 进度轮询、清理确认)。发生错误或超时时,仍会运行清理确认。最终报告示例见 references/final-report.md。
边缘情况
遇到边缘情况时,请阅读 references/edge-cases.md:opencode 缺失、升级失败、没有免费模型、所有模型均失败、卡住或超时、确认被拒绝、TUI 会话已打开、多行提示词、非零退出码或包装器被终止。该文件还包含 opencode 命令参考。
验收标准
只有以下各项均可验证时,才视为技能运行成功:
- 已验证安装 — 第 1 阶段确认
opencode位于 PATH 中,并在执行任何其他操作前报告其版本。 - 仅考虑云端
opencode/*模型 — 筛选步骤会拒绝ollama/*、lmstudio/*、nvidia/*和任何其他命名空间。绝不会选择本地模型。 - 向用户展示免费模型 — 第 2 阶段列出所有可用的免费
opencode/*模型,并将优先级 1 的模型设为默认选项,同时附上隐私说明。用户可以选择一个;如果用户暂不选择,则使用优先级 1 的模型。 - 执行前已获取确认 — 第 3 阶段展示模型、cwd、上下文文件和提示词,并在调用
opencode run前等待用户明确确认。 - 将任务委派给 opencode — 编码任务通过
opencode run执行,而不是由技能直接编辑文件或编写代码。 - 采用低 Token 监控 — 第 5 阶段通过单行
status()辅助函数轮询。绝不流式传回原始日志;每次轮询只报告最后一行、字节数和状态。每次运行最多轮询 6 次。 - 妥善处理停滞/超时 — 连续两次轮询均无字节增长,或 5 分钟内没有字节增长时,向用户请求确认;如果用户批准,则终止并清理。
- 已提供完成摘要 — 当
status=done时,技能只读取tail -n 40 "$RUN.log",根据其exit=值对运行结果分类,并总结已更改的文件和 Token 用量。 - 每条退出路径都会执行清理 — 无论任务成功、失败、出错、停滞还是超时,都会运行第 6 阶段;且第 4 步会在报告声称清理完成前输出
cleanup=complete。 - 已删除临时文件 — 清理期间会删除
"$RUN.log"、"$RUN.pid"和"$RUN.exit",除非用户要求保留日志。 - 不会回退到自身执行 — 如果 opencode 不可用、用户拒绝确认,或所有免费模型均失败,技能都会停止。绝不会回退到自行编辑文件或编写代码。
- 已提供最终报告 — 每次运行(包括停止的运行)都会以
Result:、Evidence:、Uncertainty:和Decision:结束,并通过references/final-report.md中的四项读者检查:首行可找到结果、事实与假设相互区分、每项声明均可追溯到已执行的检查,并明确指出下一步决策。在用户回答这些检查项之前,不得确认其已理解。
阶段完成报告
每个阶段结束后,输出简洁的状态块,以便快速查看通过/失败情况:
◆ [Step Name] ([step N of M] — [context])
··································································
[Check 1]: √ pass
[Check 2]: × fail — [reason]
[Criteria]: √ N/M met
____________________________
Result: PASS | FAIL | PARTIAL
通过使用 √,失败使用 ×,并使用 — 添加简短说明。各阶段(安装、模型发现、确认、执行、监控、清理)的示例状态块见 references/expected-output.md。