opencode icon indicating copy to clipboard operation
opencode copied to clipboard

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

Open vtemian opened this issue 2 weeks ago • 1 comments

Feature hasn't been suggested before.

  • [x] 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]

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]

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]

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

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.

vtemian avatar Dec 31 '25 10:12 vtemian