Opencode skill
Skill pcx-wave/opencode-skill
Claude Code skill — delegate coding tasks to Opencode, supervise via git diff & save 50-90% Claude token usage
npx -y skills add pcx-wave/opencode-skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 12 stars12 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Delegate a coding task to OpenCode CLI and supervise the result via git diff. Trigger: /opencode <instruction>. Claude orchestrates, OpenCode codes. Also handles /opencodeon, /opencodeoff, /opencodestatus, /opencode-report, /opencode-model-pick, /opencode-model-clear.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
12.5 KB, ~3.3k tokens by cl100k_base, as published. Nobody here has run it
/opencodeon | /opencodeoff | /opencodestatus
Toggle auto-delegate mode — OpenCode automatically handles coding tasks without
requiring /opencode each time.
| Command | Action |
|---|---|
/opencodeon | touch ~/.local/share/opencode-auto.flag → confirm "Auto-opencode ON" |
/opencodeoff | rm -f ~/.local/share/opencode-auto.flag → confirm "Auto-opencode OFF" |
/opencodestatus | run test -f ~/.local/share/opencode-auto.flag && echo ON || echo OFF |
Run the bash command, print one confirmation line, and stop.
/opencode-report
If the user invokes /opencode-report, run ~/tools/delegate-report with any flags extracted from the arguments, display output verbatim, and stop.
| User says | Flag |
|---|---|
| last 7 days, 7d | --since 7 |
| last 30 days, 30d | --since 30 |
| project foo | --project foo |
| only failures, fails | --fails |
| (nothing) | (no flags, full report) |
/opencode-model-pick | /opencode-model-clear
Override the model for all subsequent delegations without editing the script.
| Command | Action |
|---|---|
| /opencode-model-pick model | echo model > ~/.local/share/opencode-model.flag, confirm |
| /opencode-model-clear | rm -f ~/.local/share/opencode-model.flag, confirm back to default |
Run the bash command, print one confirmation line, and stop.
OpenCode Orchestrator
When the user invokes /opencode <instruction>, Claude delegates the implementation
to OpenCode CLI via its headless run mode (opencode run <prompt> --format json),
monitors in real time, and reports.
Known Limits
Hard constraints — not config options.
1. No --max-turns flag
Timeout is the only runaway-control lever. Set timeouts conservatively and decompose tasks.
2. --dangerously-skip-permissions
Passed automatically by the delegate script — all tool calls auto-approved. Review the git diff afterwards.
3. --dir flag
Passed automatically by the delegate script. Sets the working directory for OpenCode.
4. No pseudo-TTY needed
Plain pipe — no script -q -c wrapper required.
5. Free model queue delays
opencode/deepseek-v4-flash-free — no API key cost; may queue during peak usage.
6. Orchestration chain — 5 failure points
| Link | Failure mode | Symptom |
|---|---|---|
| OpenCode CLI | Auth expired, quota hit, network | Immediate exit or silent hang |
| Stream parser | OpenCode changes JSON event schema | Tool calls not detected |
| Token aggregation | step_finish missing or malformed | Tokens logged as 0 |
| git diff | Not a git repo, or OpenCode committed mid-run | Wrong file count |
| JSON log | ~/.local/share/ not writable | Silent log skip |
When a run produces unexpected results, check these links top to bottom.
Step 1 — Detect workdir
git rev-parse --show-toplevelin the current directory.- If ambiguous or no git repo → ask with
AskUserQuestion.
Step 2 — Decompose the task
Critical rule: keep tasks atomic and focused — one objective, one prompt.
| Signal | Action |
|---|---|
| 1 file, ≤ ~10 lines to change, location already known | Do it directly — don't delegate |
| 1 file, logic non-trivial OR location unclear | Delegate |
| 2–3 files, single objective | Delegate |
| >3 files OR multi-step logic OR migrations | Delegate, broken into sub-tasks |
| Size | Definition | Timeout | Approach |
|---|---|---|---|
| Trivial | 1 file, change is obvious and located | — | Skip delegation — edit directly |
| Simple | 1 file, non-trivial logic or unknown location | 180s | 1 opencode call |
| Medium | 2–3 related files, 1 goal | 300s | 1 opencode call with structured prompt |
| Complex | >3 files OR multi-step logic | — | Decompose |
Decomposition for complex tasks:
Sub-task 1: Explore relevant files (180s)
Sub-task 2: Implement change A in file X (300s)
Sub-task 3: Implement change B in file Y (300s)
Sub-task 4: Verify / test (180s)
→ Check git diff between sub-tasks before launching the next.
Step 3 — Write the OpenCode prompt
The prompt must be self-contained.
Structure:
Stack: Python/Flask, SQLAlchemy, SQLite
Key files: app.py (routes + fetch), models.py (Entry)
TASK: [one single thing to do, stated as an imperative]
CONSTRAINTS:
- [what must not break]
- [expected format if relevant]
VERIFY: grep for "def function_name" in file.py and confirm it exists.
Formulation rules:
- One task per prompt — never "also do X and Y"
- Name the exact files to modify
- Include a grep-based verification criterion (not a file re-read)
- Language: English (best model performance)
Prompt adaptations:
- Any task that defines or calls a specific function: include the exact signature —
def validate(data: dict) -> tuple[bool, list[str]]:. - No fixed signature, but conventions matter: point at the file to read first ("read app.py, follow its route/jsonify style") instead — don't do both, they're substitutes.
Verification — always use grep, not file re-read:
VERIFY: grep for "def extract_labels" in app.py and confirm it exists.
Examples:
❌ Bad (too vague, too wide):
Fix the API, add a signal classifier, update the UI with colored badges
✅ Good (atomic, verifiable):
Stack: Python/Flask. Files: app.py, templates/index.html
TASK: In fetch_data(), convert the date string (format "YYYY-MM-DD")
to datetime.date before returning.
CONSTRAINTS:
- Keep the existing route structure
- Use the same import style as the rest of the file
VERIFY: grep for "datetime.date" in app.py and confirm it exists.
Step 4 — Launch OpenCode
~/tools/opencode-delegate "<workdir>" "<prompt>" [timeout-secs] [model]
| Argument | Default | Notes |
|---|---|---|
workdir | — | Absolute path, must exist |
prompt | — | Self-contained task description |
timeout-secs | 300 | Wall-clock kill timer |
model | opencode/deepseek-v4-flash-free | OpenCode model string |
Recommended timeouts:
- Explore only:
120 - Simple change (1 file):
180 - Medium change (2–3 files):
300
Model selection:
opencode/deepseek-v4-flash-free(default) — free, no API key needed, may have queue delaysgoogle/gemini-2.5-flash— cheap, fast (requiresGOOGLE_GENERATIVE_AI_API_KEY)
Examples:
# Simple change
~/tools/opencode-delegate "/path/to/project" "Stack: Flask. File: app.py. TASK: ..." 180
# Background run
~/tools/opencode-delegate "/path/to/project" "..." 300 > /tmp/opencode_out.txt 2>&1 &
# Monitor with: tail -f /tmp/opencode_out.txt
Step 5 — Supervise in real time
The script prints live:
=== OPENCODE START ===
Workdir : /path/to/project
Model : opencode/deepseek-v4-flash-free
Timeout : 300s
Prompt : Stack: Python/Flask. File: app.py ...
======================
[read] app.py
[edit] app.py (+2/-1)
[opencode] Done. Converted date to datetime.date in fetch_data().
Tool calls: 3
OpenCode tokens: 4,800 (4,600 in + 200 out) | ~$0.000000
=== OPENCODE DONE (exit: 0) ===
=== SYNTAX OK (1 file(s) checked) ===
=== UNCOMMITTED CHANGES ===
app.py | 4 ++--
[log] → ~/.local/share/delegate-runs.jsonl (4800 tokens, exit 0, 42.1s)
Event types emitted by the parser:
| Event | Meaning |
|---|---|
[read] | File read |
[edit] | File edited (+additions/-deletions) |
[write] | File created |
[search] | Grep / search tool called |
[shell] | Shell command executed |
[opencode] | Assistant text response |
[WARN] | Tool error detected |
[ERROR] | OpenCode runtime error |
OpenCode never commits. All changes are left unstaged — git checkout . reverts everything if needed.
Red flags to act on immediately:
| Flag | Meaning | Action |
|---|---|---|
[WARN] | Tool error | Read the error, fix manually |
[ERROR] | Runtime error | Check auth, model availability |
exit: 1 or non-zero | OpenCode failed | Read diff, correct prompt |
No [edit] after 60s | Looping or queue delay | Abort if persists |
exit 0 + no [edit] events | WROTE_NOTHING — OpenCode ran but wrote nothing | Do not compensate — fix prompt and relaunch |
=== SYNTAX ERRORS === | Post-run syntax check failed | Fix before committing |
=== OPENCODE TIMEOUT === | Timed out | Check what was done before retrying |
| Same file read 5+ times | OpenCode is circling — run likely lost | Abort, check diff, try again |
Common issues and workarounds:
| Issue | Cause | Fix |
|---|---|---|
| No tool calls, empty response | Model overloaded or queue delay | Retry; increase timeout to 300 |
| Timeout with no writes | Model not responding | Try a different model |
| File not modified despite "done" | OpenCode described but didn't edit | Add "make the edit now, do not describe it" |
[ERROR] API key missing | Provider not configured | Check opencode auth list |
| Exit 124 (timeout) | Task too large for given timeout | Decompose or increase timeout |
Step 6 — Iteration
- Max 3 attempts per sub-task before escalating to the user.
- Between attempts, read the git diff to avoid doubling partial work.
- If OpenCode completed ≥50% and timed out: finish the rest manually rather than relaunching.
Step 6b — Log manual completion
When you finish a task manually (after OpenCode failures), run this:
python3 -c "
import json, datetime, subprocess, os
workdir = subprocess.run(['git','rev-parse','--show-toplevel'], capture_output=True, text=True).stdout.strip() or os.getcwd()
project = os.path.basename(workdir.rstrip('/'))
stat = subprocess.run(['git','-C',workdir,'diff','--stat'], capture_output=True, text=True).stdout
lines_added = sum(int(l.split('+')[1].split()[0]) for l in stat.splitlines() if '|' in l and '+' in l) if stat else 0
files_changed = len([l for l in stat.splitlines() if '|' in l])
tokens_out = lines_added * 10
tokens_in = lines_added * 40
cost = (tokens_in * 3.0 + tokens_out * 15.0) / 1_000_000
entry = {'ts': datetime.datetime.utcnow().isoformat() + 'Z', 'delegate': 'claude-manual', 'workdir': workdir, 'project': project, 'exit_code': 0, 'files_changed': files_changed, 'tokens_in': tokens_in, 'tokens_out': tokens_out, 'tokens_total': tokens_in + tokens_out, 'cost_usd': round(cost, 6), 'cost_estimated': True, 'lines_added': lines_added}
log = os.path.expanduser('~/.local/share/delegate-runs.jsonl')
open(log, 'a').write(json.dumps(entry) + '\n')
print(f'[log] claude-manual -> {project} ~{lines_added} lines est. cost \${cost:.4f}')
"
Run from anywhere inside the project. Flagged cost_estimated: true in the log.
Step 7 — Report to the user
✓ OpenCode finished — <1-line summary>
Files modified:
- path/to/file.ext (+X / -Y lines)
[If problem]:
⚠ <description> — completing manually / retrying?
Ready to commit?
Orchestration rules
- Decompose before delegating — one task, one prompt.
- Check diff between sub-tasks — never launch the next step blind.
- Don't code in OpenCode's place unless OpenCode did ≥50% and timed out.
- Timeout is the only turn limit — decompose rather than extending.
- VERIFY with grep, not re-read —
grep -n "def foo" file.py.
Run Log
Every run appends one JSON entry to ~/.local/share/delegate-runs.jsonl.
The shared ~/tools/delegate-report script can query all runs across delegates.
~/tools/delegate-report # full report
~/tools/delegate-report --since 7 # last 7 days
~/tools/delegate-report --project myapp # filter by project
~/tools/delegate-report --fails # failures only
Useful queries:
# All recent runs
cat ~/.local/share/delegate-runs.jsonl | python3 -m json.tool | less
# Total cost
jq -r '.cost_usd' ~/.local/share/delegate-runs.jsonl \
| awk '{sum+=$1} END {printf "Total: $%.4f\n", sum}'
This skill is improved regularly — run update-skills to pull the latest version of this skill, as well as all your other skills!
What ships with it: 10 files
46.7 KB alongside SKILL.md, 2 of them executable
docs/
- PLAN.md5.4 KB
tools/
- delegate-reportruns17.1 KB
- opencode-delegateruns14.0 KB
- .gitignore42 B
- OPENCODEMODELCLEAR.md351 B
- OPENCODEMODELPICK.md771 B
- OPENCODEOFF.md366 B
- OPENCODEON.md397 B
- OPENCODESTATUS.md276 B
- README.md8.0 KB