MIP-0013 tasks¶
Written by hand, following .claude/skills/mip-tasks/SKILL.md's Step 1 process: that skill has
disable-model-invocation: true, so this file was produced without invoking it as a slash
command; the process it documents was followed manually instead, per /mip-solve-perpetual's
own step 4 (auto-picked MIP, no tasks file existed yet).
Directly transcribed from MIP-0013 §5's own six numbered items; the MIP already enumerated the
build as a task list ("The tryout adds files next to .claude/, deletes nothing, and is one PR
per bullet (mip-tasks)"); this file just gives that enumeration the standard shape.
| # | slug | delivers | tests (must exist before the PR) | depends on |
|---|---|---|---|---|
| 1 | opencode-config-and-jail | pkgs.opencode added to flake.nix's devShell (confirmed present in nixpkgs, opencode 1.18.21, 2026-09-07); a committed opencode.json per MIP-0013 §5 item 1 (local-first ollama/llama3.2 default, share: disabled, the azd */az deployment * deny rule, no secrets); just jail-opencode/just jo (ai-jail, OpenCode's three directories mapped: ~/.config/opencode, ~/.local/share/opencode, ~/.cache/opencode); just opencode-cost (npx ccusage@latest opencode session) |
opencode.json validates against https://opencode.ai/config.json if check-jsonschema is in the shell, else a documented manual check; nix flake check/a real nix develop entry succeeds with opencode on PATH |
— |
| 2 | cost-split-opencode-reader | scripts/cost-split.py gains a second messages() source reading OpenCode's real store, confirmed 2026-09-07 via a live opencode run --model ollama/llama3.2 "..." (task 1's branch) that OQ2 is resolved: there is no storage/message/*/msg_*.json in 1.18.25, only SQLite at $XDG_DATA_HOME/opencode/opencode-stable.db (~/.local/share/opencode/... when unset), table message(id, session_id, time_created, time_updated, data) where data is a JSON blob; an assistant row's data has tokens.{total,input,output,reasoning,cache.{read,write}}, modelID, providerID, cost (always 0, priced downstream, matching the MIP's own note), time.{created,completed}. Needs mapping tokens.{input,output,cache.read,cache.write} into the usage dict shape price() already expects (input_tokens/output_tokens/cache_read_input_tokens/cache_creation_input_tokens) and a providerID/modelID → LiteLLM price-table key (local ollama/* models will price as None/free, same as Claude Code's <synthetic> skip does today, not a bug). --harness claude\|opencode\|all (default all) |
cost-split.py --self-test on a recorded OpenCode SQLite fixture (a tiny real .db file, not fabricated JSON), asserting the same Cost: line shape the Claude reader produces; wired into just quality |
1 |
| 3 | opencode-commands-and-agents | .opencode/commands/mip.md, mip-tasks.md, site-frontend.md (load the matching .claude/skills/ skill, pass $ARGUMENTS); .opencode/agents/mip-reviewer.md and jar-verifier.md (mode: subagent, permission.edit: deny, model unset) |
A live check, recorded in the PR body: opencode's skill tool lists the three marola skills unchanged; /mip//mip-tasks commands resolve |
1 |
| 4 | attribution-and-docs | AGENTS.md's trailer rule names both harnesses (Co-Authored-By: Claude <[email protected]> from Claude Code, Co-Authored-By: opencode <[email protected]> from OpenCode; resolve MIP-0013 §11 OQ1, whether a config key/plugin is needed, before writing this); DEV-FLOW.md §7 gains an OpenCode column; AGENT-SKILLS.md notes which skills load under OpenCode |
A real OpenCode commit's trailer inspected and matched against the stated text | 1 |
| 5 | tryout-task-a | The first of MIP-0013 §5 item 6's two experiment tasks: one Scala task with a named test, from an already-accepted MIP's task list, delivered end to end under OpenCode (just jo, default model first, escalate to a paid model only after two local-model failures on the task's own test) |
Gates green (just build/test/quality), a measured Cost: from task 2's reader, one PR-body line "harness: opencode 1.18.x, model …", a reviewer finding no Critical |
1, 2, 3 |
| 6 | tryout-task-b-and-verdict | The second experiment task (docs/config, not Scala) under OpenCode, same process; then MIP-0013 §7's comparison table (wall time, Cost:, human interventions, review findings) against the two most recent Claude Code task PRs of the same reference MIP, written into MIP-0013 §11 → "Result"; MIP-0013's own Status flips to Accepted (replace) or Rejected (keep Claude Code) based on the table, per §7's stated criteria |
The comparison table itself, committed in the MIP; docs/MIPs/README.md's MIP-0013 row updated to match the new status |
1, 5 |
Sequencing notes¶
- Strictly sequential in practice, not parallel: task 1 is the only real fan-out point (2/3/4 all depend only on 1 and could run in parallel with each other), but 5/6 are the actual experiment and must run after 1-4 exist, in order (6 needs 5's own PR as one half of the comparison).
- Tasks 5 and 6 are genuinely different in kind from 1-4: they require using OpenCode
interactively on a real task, not just writing config; a human (or an agent with real terminal
access to run
opencode/just jolive, not just edit files) does these, not a config-only automation pass. Flagged here so a future run doesn't try to fake task 5/6 by writing the comparison table without actually running OpenCode. - Task 4's attribution wording is gated on OQ1 (§11) being resolved first; don't write the
AGENTS.mdprose change speculatively; if OQ1 turns out to need theopencode-git-trailersplugin, task 4 gains that as a real dependency, not assumed here.