BuildNot yet confirmed elsewhere1 publisher2 min readPublished
OpenCode's v2 upgrade exits 0, then drops v1 plugins at WARN level on first start
In one developer's test, OpenCode 1.19.0's upgrade to v2 left two v1 plugin copies unloaded while the session kept running. The post's loud, silent, absent summary of the three breaking changes does not match its own logs.
The Engineer · Build desk
Three figures from one developer's test. opencode plugin list showed 2 v1 plugins with an empty ID column. The second upgrade run had finished with exit code 0. On first start v2 ran an install producing 26 entries in node_modules.
| Figure | Value | Note | Claim |
|---|---|---|---|
| v1 plugins shown with an empty ID column in plugin list | 2 plugins | 8 | |
| Second run's exit code | 0 exit code | 3 | |
| Installed in node_modules | 26 entries | 11 |
What happened
- The first install attempt hit a 500-second timeout and was killed mid-download with the npm cache at 493 MB; a second run finished from the warm cache and exited 0.
- v2 landed in npm's default global prefix as @opencode/cli@2.0.28, while the v1 install at the custom prefix stayed untouched and still reported 1.19.0.
- On first v2 startup the log said a plugin must export a default definition with an id and an effect or setup function, for the global and project copies alike.
- v2 also wrote a package.json pinning @opencode-ai/plugin in the config directory, installed 26 node_modules entries and added a .gitignore, so a git-tracked config directory gains files.
Why it matters
- exposure The plugin failure raises no dialog and no exit code, so anything that checks only whether the process ran will report a healthy session with the plugin gone.
- cost The first attempt ran 500 seconds, about 8.3 minutes, before the timeout killed it mid-download, so a job capped near that limit fails before v2 finishes installing.
- constraint The help text promises that v1 is removed. With a custom prefix it was not, so scripts that call opencode may reach either version depending on PATH order.
- decision A throwaway HOME contains the config the upgrade rewrites. The post does not say whether npm's default global prefix sat inside it, so a repeat run has to settle that before trusting the isolation.
The write-up's three labels hold up poorly against its logs. The author's summary says one change shouts, one lands silently three steps later, and one never came up [20]. The change that shouts is, on the evidence, the plugin failure, because it is the only failure the run reports [6].
The cause is module shape. A v1 plugin is a named export of an async function that returns hook handlers. A v2 plugin is a default export with an id and a setup or effect function [9]. In the author's test, a v2-shaped file dropped into the same directory loaded at once as acme.hello, while the two v1 files appeared in `opencode plugin list` with an empty ID column [8]. The location survived the upgrade. v2 scanned the singular `plugin/` folders even though its docs describe `plugins/` [10].
The change the post calls silent and late is a migration that runs late. The docs say layered tui.json files become one global cli.json, "migrated on first start" [12]. Neither `opencode2 run "hello"` nor `opencode2 debug config` produced the file [13]. The first TUI start, the default command with a tty, did produce it and logged the move at INFO [14]. tui.json stayed on disk, and `"theme": "opencode"` came out as `{"name": "opencode"}` [15]. A headless check for cli.json would report a migration that had not run yet.
That leaves the third change. Anything talking to the v1 server has to move to `@opencode/client`, and the author had no client integration, so there is nothing first-hand on it [16]. Two of the three documented changes were exercised at all [19].
Every result here is one author with one plugin and one tui.json, according to the dev.to post [1]. The author did not run a default-prefix install, where, as the post puts it, there is only one path, which is presumably why the docs say the two versions cannot coexist [17].
What to watch
- A test with a real @opencode/client integration, since the third documented change has no first-hand result yet.
- A default-prefix run of the same upgrade, to see whether v1 is removed as the help text promises.
- A 2.0.x release that raises the plugin load failure above WARN or accepts the v1 export shape.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence58
- Adoption
- Insufficient
- Hype gap
- Insufficient
- Incentives
- Insufficient
- Confidence55
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
OpenCode 1.19.0 added the `opencode upgrade --major` path to OpenCode 2 on Oct 11; the author ran it against a throwaway HOME with a real v1-era plugin and a real tui.json.
- [2]
The migration guide lists three intentional breaking changes.
- [3]
The first upgrade attempt hit a 500-second timeout and was killed mid-download with the shared npm cache at 493 MB; the second run finished from the warm cache with exit code 0.
- [4]
v2 landed in npm's default global prefix as @opencode/cli@2.0.28 and added two symlinks, opencode and opencode2; the v1 package at the custom prefix was untouched and still reported 1.19.0.
- [5]
The flag's help text says 'upgrade to OpenCode 2 and remove OpenCode 1'; with a custom-prefix install that did not happen, both versions are on the machine and answer to opencode, and PATH order decides which one runs.
- [6]
First v2 startup logged level=WARN 'failed to load plugin' for secret-guard.ts, with the cause that a plugin must export a default definition with an id and an effect or setup function; the global and project copies failed identically.
- [7]
The plugin failure is only a WARN: the server keeps starting, the session works, and there is no error dialog and no exit code.
- [8]
`opencode plugin list` showed the two v1 plugins with an empty ID column, while a v2-shaped plugin placed in the same directory appeared immediately with the id acme.hello.
- [9]
A v1 plugin is `export const SecretGuard: Plugin = async ({...}) => ({ "tool.execute.before": ..., event: ... })`; a v2 plugin is `export default Plugin.define({ id, setup })` or an object with id plus setup or effect.
- [10]
v2 scanned the v1-era singular `plugin/` directories even though the v2 docs describe discovery under `.opencode/plugins/` (plural).
- [11]
On first start v2 created ~/.config/opencode/package.json pinning @opencode-ai/plugin, ran an install producing 26 entries in node_modules, and wrote a .gitignore ignoring node_modules, package.json and package-lock.json.
- [12]
The docs say layered tui.json(c) files become one global cli.json, 'migrated on first start'.
- [13]
`opencode2 run "hello"` and `opencode2 debug config` each produced no cli.json.
- [14]
The first TUI start (the default command, with a tty) logged level=INFO 'migrated cli config' from tui.json to cli.json.
- [15]
tui.json was still on disk after the migration, and the generated cli.json restructured "theme": "opencode" into "theme": {"name": "opencode"}.
- [16]
Anything talking to the v1 server has to move to @opencode/client; the author had no client integration in the test and has nothing first-hand to say about it.
- [17]
On a default install there is only one path, which the author presumes is why the docs say the two versions cannot coexist.
- [18]
The 500-second timeout that killed the first attempt is about 8.3 minutes.
- [19]
Two of the three documented breaking changes were exercised in the test.
- [20]
The author's summary is that one of the three breaking changes shouts at you, one happens silently three steps later, and the third never came up at all.
ReportedContestedSource: dev.to write-up by the test's author2 sources— create a free account to open themView cited source
Sources
1 independent publisher whose own reporting we read for this story.
- dev.toOpenCode 2 Has 3 Breaking Changes. 1 Broke My Startup.
1 article · October 13, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.
Topics
- AI coding toolsFollow
- Plugin migrationFollow
- CLI upgradesFollow