# OpenCode 2 migration: keep your config, port your integrations

> OpenCode 2 keeps supported V1 configuration, but plugins, API clients, and project terminal settings need separate migration decisions.

- Published: Oct 15, 2026
- Author: PiRouter Team, Engineering
- Tags: agents, coding-agents, ecosystem
- Canonical: https://pirouter.ai/blog/opencode-2-v1-migration-boundaries

---
OpenCode 2 does not require you to rewrite your supported V1 configuration before upgrading. The real migration work sits at three boundaries: terminal settings now live in one global file, V1 plugin implementations no longer run, and integrations calling the old server API need a port. Treating those as separate jobs is more useful than converting every configuration key at once ([OpenCode — Migrate from V1](https://opencode.ai/v2/docs/migrate-v1)).

The October 12 [OpenCode 2.0 announcement](https://anoma.ly/notes/opencode-2-0/) brought those changes together publicly. It was not the first appearance of V2: the [official changelog](https://opencode.ai/changelog) already lists v2.0.26 on October 8. By October 14, v2.0.29 was fixing migration-related behavior. For an existing user, the question is therefore less “what launched?” than “which parts of my setup can I trust to carry over?”

## Which OpenCode V1 configuration still works in V2?

Imagine a repository with a custom provider, a review agent, Markdown commands, reusable skills, and one plugin that modifies requests. This is a hypothetical setup, but it exposes the migration's central distinction: the configuration describing the work may remain compatible even when the code extending OpenCode does not.

According to the [V1 migration guide — Use your existing configuration](https://opencode.ai/v2/docs/migrate-v1#use-your-existing-configuration), V2 reads the same system, global, and project configuration locations. Those include `~/.config/opencode/opencode.json(c)`, a project's `opencode.json(c)`, and its `.opencode/opencode.json(c)`. Supported V1 fields are normalized in memory; loading them does not rewrite the source file.

Existing supported agents, command definitions, skills, and other `.opencode/` files are intended to keep working. Native V2 configuration is an optional cleanup, not an admission ticket.

Project instruction discovery deserves its own check. The current guide says V2 discovers `AGENTS.md`, but not the `CLAUDE.md` fallback some V1 projects used. If your setup relied on that fallback, move the guidance into the applicable `AGENTS.md` and verify that it is discovered. The guide also asks you to file a compatibility issue: this is not a fourth intentional breaking change. Instructions guide the agent; they are not a substitute for enforced permission policies ([V1 migration guide — Instruction files](https://opencode.ai/v2/docs/migrate-v1#instruction-files)).

| Part of the V1 setup | What the migration guide promises | What to check |
|---|---|---|
| Supported server configuration | Continues loading from existing locations | Actual provider, model, and permission behavior |
| Agent, command, and skill files | Existing supported definitions remain discoverable | Names, instructions, and supporting files |
| Terminal settings | Supported global settings migrate to `cli.json` | Project-specific preferences separately |
| Plugin implementation | Does not run unchanged in V2 | A V2-compatible implementation |
| Server API integration | Requires migration to the new contract | Requests, responses, and workflow behavior |

![Official migration guide listing the three breaking changes](/blog/images/opencode-2-v1-migration-boundaries-migration.png "The compatibility promise applies to supported V1 behavior, not every accepted field. Source: [OpenCode migration guide](https://opencode.ai/v2/docs/migrate-v1#breaking-changes)")

“Accepted” still needs careful reading. V2 preserves `lsp` configuration, for example, but the guide explicitly says it does not run language servers, expose their tools, or produce their diagnostics. LSP—the Language Server Protocol—powers editor-style code intelligence. A configuration file loading successfully does not restore those capabilities; workflows that relied on them need project lint, typecheck, or compiler commands instead.

Other legacy fields, including `compaction.tail_turns` and `compaction.prune`, are intentionally ignored with a warning. Those are different from a regression in supported behavior, which the guide says should be reported as a compatibility bug ([V1 migration guide — Supported and unsupported fields](https://opencode.ai/v2/docs/migrate-v1#supported-fields-without-direct-native-equivalents)).

That distinction gives you a useful troubleshooting rule: establish whether a setting is supported before assuming either that the upgrade broke it or that rewriting its spelling will fix it.

## cli.json is global, so project terminal settings need a decision

The terminal client is the interface you interact with in a shell, often called a TUI, or terminal user interface. In V1, its `tui.json(c)` settings could be layered. In V2, the terminal client owns one global configuration file:

```text
~/.config/opencode/cli.json
```

This file belongs to the client; the background service does not load it. When `cli.json` is absent, the first V2 terminal startup migrates supported global `tui.json` settings and persisted preferences. It leaves the V1 files unchanged ([V1 migration guide — Terminal client configuration](https://opencode.ai/v2/docs/migrate-v1#terminal-client-configuration)).

The important exclusion is project-local client configuration. It is not migrated, because V2's client configuration is global.

Suppose two repositories previously carried different terminal preferences. The migration does not promise to merge those into context-sensitive V2 profiles. Before copying a project preference into `cli.json`, decide whether you want it to apply everywhere. A successful automatic migration of global settings says nothing about whether the old repository-level experience has been preserved.

There is also a practical diagnostic boundary: the documented automatic migration happens when `cli.json` is absent. If it already exists, do not assume restarting V2 will continually import changes from old terminal files. Inspect the current global configuration and compare the behavior you need.

This is a scope change, not merely a filename change. Server configuration can still be project-specific while terminal presentation settings are global. Keeping those two categories separate prevents an unnecessary rewrite of working project configuration.

![Official documentation for global cli.json migration](/blog/images/opencode-2-v1-migration-boundaries-cli-config.png "The terminal client owns cli.json; project-local terminal settings are not imported. Source: [OpenCode terminal configuration](https://opencode.ai/v2/docs/migrate-v1#terminal-client-configuration)")

## V1 plugins need a code port, not a directory rename

Plugins are the clearest hard break. V2 can discover local plugins in both `.opencode/plugin/` and `.opencode/plugins/`, and the configuration moves from `plugin` to `plugins`. Neither fact makes a V1 implementation executable.

The [official plugin migration guide](https://opencode.ai/v2/docs/build/plugins/migrate-v1/) separates configuration normalization from implementation work. V1 plugin functions returned an object containing tools and hooks. A V2 plugin default-exports a definition with a stable ID and a `setup(ctx)` function, registering its extensions through that context.

A hook runs code at a particular stage of a task. A transform changes definitions or state that OpenCode uses. For a request-editing plugin, start with a concrete question: are you changing the prompt the user submits, or the request about to be sent to the model? Those are different stages, not interchangeable hook names.

For example, the guide maps V1's `chat.message` to the V2 `prompt` hook and `chat.params` to `context`. Those names conceal a meaningful timing difference: `prompt` runs before OpenCode accepts and durably records the submitted prompt, while `context` runs immediately before an agent model request. The guide says transformations that must apply to every model-request kind need separate registration for context, compaction, generation, and titles ([Plugin migration — Register hooks in setup](https://opencode.ai/v2/docs/build/plugins/migrate-v1/#register-hooks-in-setup)).

A plugin that injects review instructions is therefore not ported simply because its initialization completes. The relevant question is whether those instructions reach each request where they are required.

![Official warning that V1 plugin implementations need a code port](/blog/images/opencode-2-v1-migration-boundaries-plugin.png "Renaming a configuration entry does not port implementation code. Source: [OpenCode plugin migration](https://opencode.ai/v2/docs/build/plugins/migrate-v1/)")

Other details affect whether a port holds up outside a demo. The stable plugin ID scopes persistent storage and identifies the plugin in diagnostics. Cleanup functions should stop owned timers, subprocesses, sockets, and subscriptions. Transform callbacks must remain synchronous and must not perform one-time actions such as starting a process: OpenCode can apply those edits again ([Plugin migration — Custom tools, cleanup, and state](https://opencode.ai/v2/docs/build/plugins/migrate-v1/#migrate-custom-tools)).

For maintainers supporting both versions, one package can temporarily expose separate V1 and V2 implementations through a default export. That does not translate hooks automatically, and the documented V1 object-entrypoint support starts at OpenCode 1.18.29. Older supported releases need a different packaging approach ([Plugin migration — Support V1 and V2 from one package](https://opencode.ai/v2/docs/build/plugins/migrate-v1/#support-v1-and-v2-from-one-package)).

Before relying on a port, exercise every extension it registers, test reload and removal, check options and persisted state, and test the installed package—not only a workspace-linked copy. Loading is the beginning of that check, not the result.

## @opencode/client and the embedding SDK solve different problems

The other explicit integration break is the server API: the contract programs use to ask OpenCode to create sessions, send prompts, and perform other operations. The official migration guide says V1 callers must migrate to the V2 API and directs them to `@opencode/client` for the released interface ([V1 migration guide — Server API and clients](https://opencode.ai/v2/docs/migrate-v1#server-api-and-clients)).

That package is for connecting to OpenCode. The announcement describes JavaScript and Effect clients and local-service discovery. Effect is a TypeScript programming ecosystem; you do not have to adopt its API merely because the package offers one.

The similarly named `@opencode/sdk` has a different purpose. It embeds the code powering OpenCode so developers can build their own runtime or a specialized deployment. The announcement explicitly describes this SDK as still in development, with things shifting ([OpenCode 2.0 — The API and SDK](https://anoma.ly/notes/opencode-2-0/)).

That makes the first architectural decision straightforward. If a scheduled script needs to operate an existing OpenCode instance, evaluate the released client contract. If a product needs to run an embedded OpenCode implementation, evaluate the SDK's current state separately. The existence of the client package is not evidence that embedding is a settled migration path.

Porting an API integration also needs more than replacing an import. Compare the request types, response handling, and operations the script depends on. A workflow completing under V1 does not establish its behavior under a deliberately revised server contract. Keep the old integration available until its V2 replacement passes the checks that matter to that workflow.

## October 14 fixes make patch versions part of the migration

The documentation describes an intended compatibility contract. The changelog helps explain why a particular installed build might not yet behave that way.

On October 14, v2.0.29 included two relevant fixes: giving centrally managed configuration precedence over local and user configuration, and allowing migrated V1 `npm` provider configuration to target built-in provider routes. The previous day's v2.0.28 entry also says unknown V1 OpenAI-compatible model options were preserved in migrated request bodies ([OpenCode changelog — v2.0.28 and v2.0.29](https://opencode.ai/changelog)).

These are not reasons to declare every migration unsafe. They are reasons to record the exact patch version before investigating a configuration problem. If a provider route or managed setting behaves unexpectedly on an earlier build, a blanket rewrite may obscure a bug already addressed upstream.

For managed environments, the distinction matters beyond convenience. The current guide puts system configuration and macOS managed preferences above global and project files. It also distinguishes ordinary settings from enforceable policies: administrators should express restrictions as policies, not assume an overridden ordinary setting prevents users from adding resources ([V1 migration guide — Configuration precedence and policies](https://opencode.ai/v2/docs/migrate-v1#use-your-existing-configuration)).

A changelog entry documents a fix, not proof that your environment is regression-free. Verify the restriction you actually depend on.

![Current configuration paths and policy precedence in the migration guide](/blog/images/opencode-2-v1-migration-boundaries-precedence.png "Current documented precedence is the behavior to verify after upgrading; this is not a screenshot of the patch changelog. Source: [OpenCode configuration guide](https://opencode.ai/v2/docs/migrate-v1#use-your-existing-configuration)")

## Validate behavior before converting to native V2 configuration

Start by preserving the V1 setup. Both versions use the `opencode` command and the same configuration locations; they are not installed side by side by default. The guide says to remove a package-managed V1 installation before installing V2. For the CLI upgrade route, the announcement says to start from the latest 1.x release and run `opencode upgrade --major` ([V1 migration guide — Installation](https://opencode.ai/v2/docs/migrate-v1#install-v2); [OpenCode 2.0 — Upgrading](https://anoma.ly/notes/opencode-2-0/)). Follow the path matching your installation method, rather than stacking methods over one another.

Before changing installations, record the exact V1 version and installation method, save configuration and file-based definitions, and record plugin and API-client versions. Check that your installation channel can restore the needed old version. This article has not verified backward compatibility of session data or persistent state; reinstalling V1 is not a promise of lossless rollback.

Then use a representative project to separate three checks:

1. **Retained behavior:** confirm the selected model, credentials, agents, discovered project instructions, permissions, and MCP servers. MCP, the Model Context Protocol, connects agents to external tools. Check any lint or typecheck workflow that previously relied on language-server features.
2. **Ported behavior:** exercise plugins and API integrations explicitly, including reload, cleanup, and failure handling where relevant.
3. **Client preferences:** inspect the global terminal settings and reconcile project-local preferences that were not migrated.

Only after those checks should optional native-format conversion become the next job. V2 allows supported V1 and native V2 fields to coexist at the top level, with valid native values taking precedence for the same canonical setting. It does not recursively infer mixed formats inside individual agents, providers, commands, or models: keep each nested entry entirely in one format ([V1 migration guide — Ask OpenCode to migrate](https://opencode.ai/v2/docs/migrate-v1#ask-opencode-to-migrate)).

Do not point V1 back at configuration converted into V2-only shapes. Keeping a copy matters because a shared path is not a rollback mechanism.

For a setup built mainly from supported configuration and Markdown definitions, V2 adoption can begin without a wholesale rewrite. For a setup whose value depends on plugins or automation, the port and its behavioral checks are the migration. Make native syntax cleanup a separate change, so a broken integration does not disappear inside a much larger configuration diff.

---

## Sources

### opencode.ai

- [OpenCode — Migrate from V1](https://opencode.ai/v2/docs/migrate-v1)
- [official changelog](https://opencode.ai/changelog)
- [V1 migration guide — Use your existing configuration](https://opencode.ai/v2/docs/migrate-v1#use-your-existing-configuration)
- [V1 migration guide — Instruction files](https://opencode.ai/v2/docs/migrate-v1#instruction-files)
- [OpenCode migration guide](https://opencode.ai/v2/docs/migrate-v1#breaking-changes)
- [V1 migration guide — Supported and unsupported fields](https://opencode.ai/v2/docs/migrate-v1#supported-fields-without-direct-native-equivalents)
- [V1 migration guide — Terminal client configuration](https://opencode.ai/v2/docs/migrate-v1#terminal-client-configuration)
- [official plugin migration guide](https://opencode.ai/v2/docs/build/plugins/migrate-v1/)
- [Plugin migration — Register hooks in setup](https://opencode.ai/v2/docs/build/plugins/migrate-v1/#register-hooks-in-setup)
- [Plugin migration — Custom tools, cleanup, and state](https://opencode.ai/v2/docs/build/plugins/migrate-v1/#migrate-custom-tools)
- [Plugin migration — Support V1 and V2 from one package](https://opencode.ai/v2/docs/build/plugins/migrate-v1/#support-v1-and-v2-from-one-package)
- [V1 migration guide — Server API and clients](https://opencode.ai/v2/docs/migrate-v1#server-api-and-clients)
- [V1 migration guide — Installation](https://opencode.ai/v2/docs/migrate-v1#install-v2)
- [V1 migration guide — Ask OpenCode to migrate](https://opencode.ai/v2/docs/migrate-v1#ask-opencode-to-migrate)

### anoma.ly

- [OpenCode 2.0 announcement](https://anoma.ly/notes/opencode-2-0/)
