Skip to content

[FEATURE]: Window System as Foundation for UI Plugin Ecosystem #6521

Closed

Description

@vtemian

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

The current OpenCode TUI architecture limits plugins to backend functionality (tools, commands).

Plugins cannot render persistent UI elements like file browsers, git panels, or search results. This document proposes a window system that decouples view rendering from routing, enabling a rich UI plugin ecosystem.


Current Plugin Capabilities

  • ✅ Register tools (AI-callable functions)
  • ✅ Register commands (slash commands)
  • ✅ Emit events
  • ❌ Render persistent UI panels
  • ❌ Create sidebars or split views
  • ❌ Display interactive trees, lists, forms

Plugins can offer IDE-like extensibility

  • NERDTree-style file browser - navigate project, open files in context
  • Git panel - stage, diff, commit without leaving OpenCode
  • Search results pane - persistent results, click to jump
  • MCP tool inspector - monitor tool calls in real-time

None of these is possible with single-view routing.


Current Architecture

flowchart TD
    RP[RouteProvider] --> SW{route.type?}
    SW -->|home| H[Home Component]
    SW -->|session| S[Session Component]
Loading

Limitations:

  1. One view at a time
  2. Route owns the entire screen
  3. No mechanism for plugins to inject views
  4. Navigation replaces everything

Proposed Architecture

flowchart TD
    subgraph Plugins
        P1[File Tree Plugin]
        P2[Git Plugin]
    end
    
    subgraph ViewRegistry
        V1["home → Home"]
        V2["session:* → Session"]
        V3["plugin:filetree → FileTree"]
        V4["plugin:git → GitPanel"]
    end
    
    subgraph LayoutProvider
        LT[Layout Tree]
    end
    
    P1 -->|register| V3
    P2 -->|register| V4
    
    LT --> LR[LayoutRenderer]
    LR -->|resolve viewID| ViewRegistry
    LR --> W1[Window: plugin:filetree]
    LR --> W2[Window: session:abc]
    LR --> W3[Window: plugin:git]
Loading

Layout Tree Structure

graph TD
    Root[Split: horizontal]
    Root --> Left[Window<br/>viewID: plugin:filetree]
    Root --> Right[Split: vertical]
    Right --> Top[Window<br/>viewID: session:abc]
    Right --> Bottom[Window<br/>viewID: plugin:git]
Loading

Plugin View API

Registering a View

// In plugin initialization
import { ViewRegistry, View } from "@opencode/plugin"

// Tree view (file browser, symbol outline)
ViewRegistry.register("my-plugin:files", View.Tree.create({
  id: "my-plugin:files",
  title: "Project Files",
  nodes: [
    { id: "src", label: "src/", icon: "📁", children: [...] },
    { id: "readme", label: "README.md", icon: "📄", children: [] }
  ]
}))
// List view (search results, command palette)
ViewRegistry.register("my-plugin:search", View.List.create({
  id: "my-plugin:search", 
  title: "Search Results",
  items: [...]
}))

View Types

Type Use Case Features
Tree File browsers, symbol outlines Hierarchical, expandable nodes
List Search results, fuzzy finders Flat, searchable, selectable
Text Logs, previews, docs Styled, scrollable, read-only
Form Settings, input dialogs Fields, validation, submit

Opening a Plugin View

// Plugin requests to open its view
opencode.layout.open("my-plugin:files", { 
  position: "left",   // left, right, top, bottom
  size: 0.25          // 25% of screen
})
// Or user opens via command
/open my-plugin:files

Data Flow

sequenceDiagram
    participant U as User
    participant K as Keybind Handler
    participant L as LayoutProvider
    participant R as LayoutRenderer
    participant V as ViewRegistry
    participant C as Component
    U->>K: Ctrl+X |
    K->>L: splitVertical("home")
    L->>L: Update tree state
    L->>R: Re-render
    R->>V: resolve("home")
    V->>R: Home component
    R->>C: Render in new pane
Loading

User Experience

Keybindings (Vim-style)

Action Keybind
Split vertical Ctrl+X |
Split horizontal Ctrl+X -
Navigate Ctrl+X h/j/k/l
Close pane Ctrl+X q
Focus plugin view Ctrl+X 1/2/3...

Example Layout

┌─────────────┬─────────────────────────────┐
│ File Tree   │ Session: "Fix auth bug"     │
│ (plugin)    │                             │
│             │ > Review src/auth.ts        │
│ 📁 src/      │                             │
│   📄 auth.ts │ [AI response...]            │
│   📄 user.ts │                             │
│ 📁 tests/    │                             │
├─────────────┼─────────────────────────────┤
│ Git Status (plugin)                       │
│ M src/auth.ts  [Stage] [Diff] [Revert]    │
└───────────────────────────────────────────┘

Why Not Alternatives?

Approach Problem
Modals/dialogs Block interaction, not persistent, can't reference while typing
Fixed sidebars Not flexible, each sidebar = special case, plugins can't add their own
Plugins render anywhere No consistency, layout conflicts, focus management nightmare
Window system Consistent primitives, user controls layout, plugins just provide content

Conclusion
The window system transforms OpenCode from a chat application into an extensible platform.

By decoupling views from routing and providing typed view primitives, we enable a plugin ecosystem comparable to Vim, VS Code, or Emacs.

Activity

  1. added
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on Dec 31, 2025
  2. added
    opentuiThis relates to changes in v1.0, now that opencode uses opentui
    on Dec 31, 2025
  3. github-actions commented on Dec 31, 2025

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    All three issues are related to improving plugin UI capabilities and creating persistent, interactive UI panels in OpenCode. While this issue proposes a comprehensive window system architecture, the related issues address specific use cases that would benefit from (or complement) this proposal.

    Feel free to ignore if this is intentionally a more fundamental/architectural proposal.

  4. ai-llt commented on Jan 19, 2026

    @ai-llt

    OpenCode 插件 UI 功能请求 - 实际用例 / OpenCode Plugin UI Feature Request - Real Use Cases

    我:整个过程是我和LLM共同测试的,我想保留LLM的想法,只做一些小幅度的修改。我手写的部分会特别标注一下。
    Me: The entire process was tested by me and the LLM together. I want to preserve the LLM's ideas and only make minor modifications. The parts I wrote by hand will be specially marked.

    背景

    我们进行了详细的测试,确认了 Issue #6521 中描述的插件 UI 限制。我们开发了一个 edit_replica 插件来扩展原生 edit 工具的功能。

    我:我最初的想法是每次修改LLM能够看到修改的内容,而不用再去read一次文件提升速度,我不知道你们有没有遇见过edit经常会将代码块代码结构给改坏,这时候单从LSP去提示已经不足以让LLM意识到问题在哪,于是我想:如果LLM能直接看到代码的diff不就能知道问题在哪了吗?也是从这里我意识到显示在TUI面板上的diff结果LLM是看不到的。
    Me: My initial idea was that each time the LLM makes modifications, it could see the changes directly without having to read the file again, thereby improving speed. I don't know if you've encountered situations where edits often mess up the structure of code blocks—in such cases, relying solely on LSP hints isn't enough for the LLM to realize where the problem lies. That's when I thought: if the LLM could directly see the code diff, wouldn't it immediately understand the issue? It was from this realization that I understood the diff results displayed on the TUI panel are not visible to the LLM.

    我: 于是我想通过插件的方式增强Edit的功能于是发现了一下需求。
    Me: So I wanted to enhance Edit's functionality through plugins, and I discovered the following requirements.

    测试结果

    测试 1: metadata() 方法

    // 插件中调用 metadata()
    context.metadata({
      title: "Diff: filename",
      metadata: { diff: "..." }
    })

    结果:

    • ✅ metadata() 方法存在且可调用
    • ❌ UI 没有显示任何变化
    • ℹ️ 只会打印日志

    测试 2: TUI Toast

    // 尝试通过 SDK 触发 toast
    await client.tui.showToast({
      body: { message: "文件已修改", variant: "success" }
    })

    结果:

    • ❌ 插件上下文中无法访问 client.tui
    • ⚠️ 插件无法主动触发 TUI 事件

    结论

    确认的限制:

    • ❌ 插件无法渲染 persistent UI panels
    • ❌ 插件无法显示 diff 信息
    • ❌ 插件无法创建 sidebars 或 split views
    • ℹ️ 插件只能返回字符串给 LLM

    实际用例:edit_replica 插件

    我们开发了一个插件来测试diff display的功能:
    功能:

    • ✅ 完整复制原生 edit 工具的 9 种匹配策略
    • ✅ 返回完整的 unified diff 给 LLM
    • ✅ 提供格式化的变更统计
    • ✅ 机器可读元数据
      代码示例:
    edit_replica({
      filePath: "src/auth.ts",
      oldString: `function login(): void {
      }`,
      newString: `function login(): void {
        const token = validateToken();
        if (!token) throw new Error('Invalid');
      }`
    })

    当前输出:

    ✅ 文件编辑成功 | src/auth.ts
    📊 变更统计:
       +3 行增加
       -1 行删除
    🔍 代码差异:
    ```diff
    @@ -10,3 +10,5 @@
       }
       
    +  const token = validateToken();
    +  if (!token) throw new Error('Invalid');
       return true;
    

    问题:

    • ✅ LLM 可以看到完整的 diff
    • ❌ 用户 UI 中不显示 diff panel
    • ℹ️ 用户需要阅读 LLM 的文本来了解变更

    需求

    迫切需要: 插件能够显示 UI diff panel
    使用场景:

    1. 开发者想可视化查看代码变更
    2. 代码 review 时需要清晰的 diff 显示
    3. 与原生 edit 工具保持一致的用户体验

    建议的解决方案

    基于 Issue #6521 的 Window System 设计,我们建议:

    优先级 1:插件 Diff Panel

    允许插件注册并显示 diff panel:

    // 插件中
    ViewRegistry.register("edit-replica:diff", View.Diff.create({
      id: "edit-replica:diff",
      title: "Diff Preview",
      diff: unifiedDiff,  // 传入 diff 字符串
    }))
    // 显示 panel
    opencode.layout.open("edit-replica:diff", {
      position: "right",
      size: 0.4
    })

    优先级 2:简化版 diff display

    提供简化的 API 专门用于显示 diff:

    // 插件中
    ctx.showDiff({
      title: "File Modified",
      filepath: "src/auth.ts",
      diff: unifiedDiff,
      position: "right"
    })

    建议

    支持 Issue #6521 的 Window System 提案,并提供简化的 API 专门用于显示 diff:
    ctx.showDiff({
    title: "File Modified",
    filepath: "src/auth.ts",
    diff: unifiedDiff,
    position: "right"
    })
    这将大大提升插件生态系统的实用价值。
    感谢官方团队的努力!期待这个功能的实现。

    影响

    如果实现:

    • ✅ 插件可以提供与原生工具相同的用户体验
    • ✅ 提升插件生态系统的实用性
    • ✅ 吸引更多开发者创建插件
      如果不实现:
    • ⚠️ 插件功能受限,只能作为后端工具
    • ⚠️ 限制了插件的实用价值
    • ⚠️ 开发者可能选择 fork OpenCode 而不是写插件

    参考


    我们完全支持 Issue #6521 的 Window System 提案,并提供了这个实际用例来说明为什么插件需要 UI 能力。
    感谢官方团队的努力!期待这个功能的实现。

  5. github-actions commented on Mar 27, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 90 days of no activity. If the issue is still relevant please open a new one.

  6. prg-04 commented on Apr 9, 2026

    @prg-04

    What is the current status of this Window System proposal? Was it implemented? If not, what's the plan?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

discussionUsed for feature requests, proposals, ideas, etc. Open discussionopentuiThis relates to changes in v1.0, now that opencode uses opentui

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions