The dangerous part looks familiar
OpenCode 2 keeps the opencode command and reads the same configuration locations as V1. The official migration guide says the V2 installer replaces the V1 binary. It also says the two versions should not share configuration after you convert files to V2-only shapes.
That creates a nasty failure mode. A terminal can look normal while the binary, plugin contract, server API, or permission vocabulary has changed beneath it. Familiar startup is not migration proof.
Separate the four jobs
1. Identify the binary
Record the resolved executable path and reported version before changing anything. Save the V1 result outside the directories the migration can rewrite. A shell alias, package manager shim, or old process can make a version check lie by omission.
2. Inventory what V2 translates
The migration guide says supported V1 config can be normalized in memory. It also lists fields that V2 accepts but ignores with a warning. Read the warnings. An accepted file is not the same as an active rule.
3. Port the real breaks
V1 plugin implementations do not run in V2. Integrations that call the server API also need the V2 client contract. Those are code migrations, not search-and-replace chores.
4. Replay one workload
Verify the model, credentials, agents, permissions, MCP servers, and plugins in a project you can discard. Then run a small workload whose expected file changes and denied actions are known in advance.
Permission order is part of behavior
V2 uses an ordered permissions array. The last matching rule wins. A broad rule followed by a narrow exception behaves differently from the same lines in reverse order.
{
"permissions": [
{ "action": "shell", "resource": "*", "effect": "ask" },
{ "action": "shell", "resource": "git status *", "effect": "allow" },
{ "action": "shell", "resource": "git push *", "effect": "deny" }
]
}
The names changed too. V1 bash, task, and write/patch map to V2 shell, subagent, and edit. The permission docs also warn that shell directory inference is best effort. A neat wildcard is not a sandbox.
Keep the rollback boring
Preserve the V1 binary source, config copy, plugin code, client revision, and one known-good workload result. Do not call the migration complete until V2 passes the same expected allow and deny checks. If rollback depends on reconstructing yesterday's setup from memory, there is no rollback.