Support OpenCode 2 alongside OpenCode 1 - #5
Open
kylemclaren wants to merge 3 commits into
Open
Conversation
OpenCode 2 replaces the plugin API. A plugin no longer returns hooks from a `server` function: it exports a `setup` function, registers servers and commands with transforms, and intercepts live operations with hooks. One package can serve both releases, because each release resolves a different package export. OpenCode 1 resolves `./server`, and OpenCode 2 resolves `.`, so neither release loads the other's file. - `src/v1.js` keeps the OpenCode 1 plugin. Its configuration, permission, and hook behavior does not change. - `src/v2.js` adds the OpenCode 2 plugin. - `src/shared.js` holds what does not differ: the server defaults, the naming rules, the guidance text, the command templates, the trigger pattern, and the destructive tools. Behavior differences that the two plugin APIs force: - OpenCode 2 gives plugins no permission draft, so the plugin changes a decision from `allow` to `ask` in the `permission.evaluate` hook. A configured `deny` never reaches the hook. - OpenCode 2 has no compaction hook, so the compaction instruction is part of the guidance text there. OpenCode 1 keeps its hook. - OpenCode 2 separates the MCP `startup`, `catalog`, and `execution` timeouts, and adds the `oauth` and `codemode` options. The guidance text changes for both releases. It now names the `sprites_file_*` tools, which the Sprites MCP server offers, in place of the previous base64 transfer advice. It also names the `mcp auth` command of the release that is running. Tests cover both releases: the export map through Node resolution, each entry point directly, the real OpenCode 1 CLI, and a real OpenCode 2 service. `test/context.js` replays transforms and disposes registrations the way the runtime does, and `test/type-contract.ts` asserts that it stays assignable to the real plugin contract. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiiJqxPLpgfJXG5fvTUa73
`/sprites-status` failed with "Expected array at [\"files\"]". The command executor passed `files`, `agents`, and `skills` to `session.prompt` even when the caller sent no attachments. Prompt validation accepts an absent key, but it rejects a key whose value is undefined. Build the attachment keys only when they carry entries. The fake plugin context records the prompt input without validating it, so a unit test alone cannot catch this. The new test asserts the absence of the keys, and the fix is verified against a real OpenCode 2 service: the command fails with the reported error before it, and succeeds after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiiJqxPLpgfJXG5fvTUa73
kylemclaren
marked this pull request as ready for review
August 27, 2026 19:35
aezell
reviewed
Aug 27, 2026
aezell
left a comment
Collaborator
There was a problem hiding this comment.
There's a thing called codemode that I think we want to default to false because if true it changes how it calls the MCP tools in a way that our server doesn't yet support. We can add that support but the fastest way is to set it to false for now.
OpenCode 2 groups MCP tools in Code Mode by default. The model then reaches them through a dispatcher, as `tools.sprites.<tool>(input)`. The Sprites MCP server does not support that call shape yet, so the plugin sets `codemode` to `false` on the server it registers. The `sprites_*` tools are then on the model's own tool list. A real model request carries 24 Sprites tools with Code Mode off, and none with it on. The `codemode` option still accepts `true`, for use after the server supports the dispatcher. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiiJqxPLpgfJXG5fvTUa73
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OpenCode 2 replaces the plugin API. A plugin no longer returns hooks from a
serverfunction: it exports asetupfunction, registers servers and commands with transforms, and intercepts live operations with hooks.One package can serve both releases, because each release resolves a different package export. OpenCode 1 resolves
./server, and OpenCode 2 resolves., so neither release loads the other's file.src/v1.jskeeps the OpenCode 1 plugin. Its configuration, permission, and hook behavior does not change.src/v2.jsadds the OpenCode 2 plugin.src/shared.jsholds what does not differ: the server defaults, the naming rules, the guidance text, the command templates, the trigger pattern, and the destructive tools.Behavior differences that the two plugin APIs force:
allowtoaskin thepermission.evaluatehook. A configureddenynever reaches the hook.startup,catalog, andexecutiontimeouts, and adds theoauthandcodemodeoptions.The guidance text changes for both releases. It now names the
sprites_file_*tools, which the Sprites MCP server offers, in place of the previous base64 transfer advice. It also names themcp authcommand of the release that is running.Tests cover both releases: the export map through Node resolution, each entry point directly, the real OpenCode 1 CLI, and a real OpenCode 2 service.
test/context.jsreplays transforms and disposes registrations the way the runtime does, andtest/type-contract.tsasserts that it stays assignable to the real plugin contract.