Repository navigation
Description
Summary
TUI plugins stopped loading in the next nightly channel after builds that migrated TUI config into cli.json. Plugin entries in tui.json (string/tuple form) and cli.json ({package, options} form) are both ignored — the TUI runtime never attempts to load them. Adding the same plugin to the server config (opencode.jsonc plugins) makes the server load it as a server plugin and crash with TypeError: undefined is not an object (evaluating 'context.storage.memory') because TUI-only context capabilities do not exist server-side.
Environment
- opencode version:
0.0.0-next-17297(also reproduced on0.0.0-next-17296) - OS: Linux Fedora 43,
7.1.7-100.fc43.x86_64 - Terminal: tmux (
TERM=xterm-256color, truecolor) - Shell: fish
- Install/channel:
next(npm global install of@opencode-ai/cli) - Active plugins: local TUI plugin
/home/samarth/repos/live-token-info/src/index.tsx(id: live-token-meter, usescontext.storage.memoryandcontext.ui.slot("prompt.footer.end")); previously also@renjfk/opencode-voice
Reproduction
-
Create a local TUI plugin module:
index.tsxwith/** @jsxImportSource @opentui/solid */,import { Plugin } from "@opencode-ai/plugin/tui", andPlugin.define({ id, setup(ctx) { ctx.storage.memory(...); ctx.ui.slot("prompt.footer.end", ...) } }). -
Add it to
~/.config/opencode/tui.jsonas a tuple:"plugin": [ ["/path/to/plugin.tsx", { "charsPerToken": 4, "showTotals": true }] ]
(Same form used by the working
.opencode/tui.jsonexample for thetui-smokefixture in this repo.) -
Restart the TUI (
opencode2). -
The plugin does not load. No entry appears in
~/.local/state/opencode/plugin-meta.jsonand no client-side log messages are emitted. -
Alternative: add the same plugin to
~/.config/opencode/opencode.jsoncas"plugins": [{ "package": "/path/to/plugin.tsx", "options": {...} }]and restart. The server log shows:msg="loading plugin" id=/path/to/plugin.tsx entrypoint="/path/to/plugin.tsx?mtime=..." message="failed to load plugin" plugin.id=live-token-meter cause="Cause([Die(TypeError: undefined is not an object (evaluating 'context.storage.memory'))])"
Expected Behavior
TUI-kind plugins load in the TUI client with the TUI plugin context (storage, ui, theme, data), either from client config entries (tui.json tuples / cli.json {package, options}) or through server-side kind detection that routes them to the client without executing setup with a server context.
Actual Behavior
- The TUI runtime ignores all client-config plugin entries (no attempts recorded in
plugin-meta.jsonor logs) since thecli.jsonmigration appeared innext-17098(server log:migrated cli configon 2026-08-10). - Server-config entries load the module as a server plugin and crash in
setuponcontext.storage.memorybeing undefined. - Timeline confirmation: TUI plugin
@renjfk/opencode-voiceloaded successfully 46 times until thenext-17055era (last load 2026-08-09) and never again after the migration landed; thetui-smoke.tsxfixture loaded once on 2026-07-02 and has not re-loaded since.
Additional Context
Config used for reproduction:
// ~/.config/opencode/tui.json
"plugin": [
["/home/samarth/repos/live-token-info/src/index.tsx", { "charsPerToken": 4, "showTotals": true }]
]
// ~/.config/opencode/cli.json (rewritten each start by the built-in migration)
"plugins": [
{ "package": "/home/samarth/repos/live-token-info/src/index.tsx", "options": { "charsPerToken": 4, "showTotals": true } }
]- Stable channel 1.18.16 still contains the legacy client-side flow (
loading tui config/skipping invalid tui configmessage strings) and does not exhibit the regression. The nightly binary (next-17297) no longer contains those strings, which matches the client runtime no longer reading client config. - Consistently reproducible across roughly 10 client restarts.
- No workaround found; the server-config entry must be removed to stop the crash on every start. The plugin itself is unaffected (module imports fine; the failure happens inside
setupwith a server context).
Activity
rorshopping commentedon Aug 12, 2026
Tried to reproduce this on current
dev(dab2637). The primary symptom — TUI plugins not loading at all — doesn't reproduce there: a plugin declared only intui.json(e.g.{ id, tui }) still loads and activates in the TUI runtime.The crash does reproduce, and the mechanism matches what you found: a TUI-only plugin is processed by both runtimes when it's listed in both configs. The server runtime (
PluginLoader.loadExternalwithkind: "server") imports it independently and rejects it —readV1PluginthrowsTypeError: Plugin <spec> must default export an object with server()— which is where the nightly'scontext.storage.memoryerror comes from (TUI-only capabilities missing server-side). The TUI runtime loads the same spec fine. Removing the plugin from the server config stops the server-side error and the TUI plugin still works.I've put a 4-case reproduction test at
packages/opencode/test/plugin/issue-42051.test.ts(server-reject, tui-load, removal-fixes, double-processing). Happy to open a PR if a server-side guard against TUI-only plugins would be useful — e.g. treating a TUI-only module as a no-op (or a clearer warning) in the server runtime instead of afailed to load pluginlog.github-actions commentedon Oct 13, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.