anomalyco / anomalyco/opencode

tui: plugins no longer load after cli.json config migration (nightly next channel)

Open
#42,051 1 comment 0 reactions 1 assignee View on GitHub

@simonklee is already working on this.

Since Aug 12, 2026.

2.0
Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

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 on 0.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, uses context.storage.memory and context.ui.slot("prompt.footer.end")); previously also @renjfk/opencode-voice

Reproduction

  1. Create a local TUI plugin module: index.tsx with /** @jsxImportSource @opentui/solid */, import { Plugin } from "@opencode-ai/plugin/tui", and Plugin.define({ id, setup(ctx) { ctx.storage.memory(...); ctx.ui.slot("prompt.footer.end", ...) } }).

  2. Add it to ~/.config/opencode/tui.json as a tuple:

    "plugin": [
        ["/path/to/plugin.tsx", { "charsPerToken": 4, "showTotals": true }]
    ]
    

    (Same form used by the working .opencode/tui.json example for the tui-smoke fixture in this repo.)

  3. Restart the TUI (opencode2).

  4. The plugin does not load. No entry appears in ~/.local/state/opencode/plugin-meta.json and no client-side log messages are emitted.

  5. Alternative: add the same plugin to ~/.config/opencode/opencode.jsonc as "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.json or logs) since the cli.json migration appeared in next-17098 (server log: migrated cli config on 2026-08-10).
  • Server-config entries load the module as a server plugin and crash in setup on context.storage.memory being undefined.
  • Timeline confirmation: TUI plugin @renjfk/opencode-voice loaded successfully 46 times until the next-17055 era (last load 2026-08-09) and never again after the migration landed; the tui-smoke.tsx fixture 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 config message 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 setup with a server context).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.