Problem
@sema-lang/opencode-sema is an OpenCode v1 plugin factory. Its default export returns a config hook, so OpenCode v2 will not run it. Configuration migration alone is insufficient: v2 requires a stable plugin ID and a setup(ctx) implementation.
Current behavior to preserve or explicitly replace
The v1 config hook currently:
- resolves the Sema binary with
SEMA_PATH > plugin path option > sema;
- warns through the OpenCode client when the resolved binary is unavailable;
- adds a
sema LSP command (sema lsp) without replacing a user-owned entry;
- adds a
sema MCP server (sema mcp) without replacing a user-owned entry;
- adds a
.sema formatter (sema fmt $FILE) unless its option/environment/global configuration disables it; and
- injects the bundled Sema guide unless its option/environment disables it.
Existing unit tests cover these defaults, precedence rules, opt-outs, non-clobbering behavior, warning behavior, and the default/named export aliases.
Required implementation
- Replace the v1 SDK dependency and types (
@opencode-ai/plugin) with an @opencode/plugin version compatible with the OpenCode v2 release this package targets. Update peer dependency metadata, lockfile, build output, and package exports as needed.
- Default-export
Plugin.define({ id: "sema", async setup(ctx) { ... } }). Keep sema stable because v2 scopes persistent state and diagnostics by plugin ID.
- Register the MCP server through
ctx.mcp.transform. Add the local sema server only when no entry with that name already exists; use [resolvedBinary, "mcp"] and the native v2 MCP shape. Do not overwrite a user-owned entry.
- Read and validate
ctx.options using the existing path, formatter, and instructions contract. Preserve environment precedence and ~ expansion. Preserve SEMA_DISABLE_FORMATTER and SEMA_DISABLE_INSTRUCTIONS semantics where the related v2 behavior exists.
- Replace the v1 client logger with a documented v2-safe warning mechanism. A missing binary must produce a useful diagnostic without stopping plugin setup.
- Replace the v1
instructions config mutation. V2 currently accepts instructions configuration but does not resolve it. When instructions are enabled, load the bundled guide during setup and inject it with the v2 session context hook using the documented model-visible system-message shape. Do not add it when the existing opt-out is set.
- Add a compatibility entrypoint only if we continue to support OpenCode v1. The v2 documentation supports a combined default export with v2
setup() and v1 server() only for v1.18.29+. If retained, narrow the supported v1 range, keep the old config-hook implementation separate, and test both runtimes. Otherwise, make this a v2-only major release and document the breaking support boundary.
Known v2 limits and user-facing behavior
- LSP: OpenCode v2 accepts
lsp configuration but currently has no LSP runtime, built-in servers, diagnostics, or LSP tool. Its plugin API also has no LSP transform. Do not claim that this release provides working Sema LSP integration. Document the manual v2 LSP configuration as forward-compatible only, and open a follow-up when OpenCode exposes an LSP runtime/registration API.
- Formatter: v2 supports static
formatter configuration, but the v2 plugin context exposes no formatter transform. Do not silently pretend the v1 auto-registration still works. Document the exact native v2 formatter.sema configuration snippet and decide whether the formatter plugin option is removed/deprecated or only applies to the v1 compatibility path.
- MCP config: v2 uses
mcp.servers in file configuration, while the plugin should use the documented MCP transform API.
Documentation and release work
- Update the README install/configuration examples from v1
plugin tuple syntax to v2 plugins object syntax.
- Document the plugin ID, supported OpenCode versions, v1 support policy, every option/environment variable, and the v2 LSP/formatter limitations above.
- Add native v2 configuration examples for the manual Sema formatter and future LSP declaration.
- Add a changelog entry that clearly lists any removed or deferred behavior. Publish as a breaking major release if v1 support is dropped.
Acceptance criteria
References
Problem
@sema-lang/opencode-semais an OpenCode v1 plugin factory. Its default export returns aconfighook, so OpenCode v2 will not run it. Configuration migration alone is insufficient: v2 requires a stable plugin ID and asetup(ctx)implementation.Current behavior to preserve or explicitly replace
The v1
confighook currently:SEMA_PATH> pluginpathoption >sema;semaLSP command (sema lsp) without replacing a user-owned entry;semaMCP server (sema mcp) without replacing a user-owned entry;.semaformatter (sema fmt $FILE) unless its option/environment/global configuration disables it; andExisting unit tests cover these defaults, precedence rules, opt-outs, non-clobbering behavior, warning behavior, and the default/named export aliases.
Required implementation
@opencode-ai/plugin) with an@opencode/pluginversion compatible with the OpenCode v2 release this package targets. Update peer dependency metadata, lockfile, build output, and package exports as needed.Plugin.define({ id: "sema", async setup(ctx) { ... } }). Keepsemastable because v2 scopes persistent state and diagnostics by plugin ID.ctx.mcp.transform. Add the localsemaserver only when no entry with that name already exists; use[resolvedBinary, "mcp"]and the native v2 MCP shape. Do not overwrite a user-owned entry.ctx.optionsusing the existingpath,formatter, andinstructionscontract. Preserve environment precedence and~expansion. PreserveSEMA_DISABLE_FORMATTERandSEMA_DISABLE_INSTRUCTIONSsemantics where the related v2 behavior exists.instructionsconfig mutation. V2 currently acceptsinstructionsconfiguration but does not resolve it. When instructions are enabled, load the bundled guide during setup and inject it with the v2 session context hook using the documented model-visible system-message shape. Do not add it when the existing opt-out is set.setup()and v1server()only for v1.18.29+. If retained, narrow the supported v1 range, keep the old config-hook implementation separate, and test both runtimes. Otherwise, make this a v2-only major release and document the breaking support boundary.Known v2 limits and user-facing behavior
lspconfiguration but currently has no LSP runtime, built-in servers, diagnostics, or LSP tool. Its plugin API also has no LSP transform. Do not claim that this release provides working Sema LSP integration. Document the manual v2 LSP configuration as forward-compatible only, and open a follow-up when OpenCode exposes an LSP runtime/registration API.formatterconfiguration, but the v2 plugin context exposes no formatter transform. Do not silently pretend the v1 auto-registration still works. Document the exact native v2formatter.semaconfiguration snippet and decide whether theformatterplugin option is removed/deprecated or only applies to the v1 compatibility path.mcp.serversin file configuration, while the plugin should use the documented MCP transform API.Documentation and release work
plugintuple syntax to v2pluginsobject syntax.Acceptance criteria
pluginsconfiguration appears inopencode plugin listwith IDsema.sema mcpwith the resolved binary and preserves a user-definedsemaMCP server.pathand the two environment toggles retain their documented precedence and behavior.References