[FEATURE]: Window System as Foundation for UI Plugin Ecosystem
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:
- One view at a time
- Route owns the entire screen
- No mechanism for plugins to inject views
- 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.