UI Contributions

Plugins can declare UI contributions in their manifest to appear in different parts of the desktop app. The desktop app renders generic views based on the plugin’s kind and never imports plugin-specific React components.

How It Works

  1. Your plugin.json declares ui_contributions with slot names, icons, and labels
  2. The desktop app reads these contributions from installed plugins at runtime
  3. Based on your plugin’s kind (e.g., agent_provider), the app selects a generic renderer
  4. The renderer provides the UI framework; your plugin provides the data via JSON-RPC

The desktop app has no compile-time knowledge of your plugin. All UI is rendered dynamically based on the plugin kind and contributions declared in the manifest.

Available Slots

sidebar.item

Adds an icon to the main app sidebar, between the core navigation items and the bottom controls. Clicking the icon navigates to your plugin’s full-page view.

{
  "slot": "sidebar.item",
  "icon": "wand-sparkles",
  "label": "My Plugin"
}
FieldTypeRequiredDescription
iconstringNoLucide icon name. Defaults to "puzzle".
labelstringNoDisplay label. Defaults to the plugin name.
ordernumberNoSort order among plugin sidebar items. Lower values appear first.

Supported icon names: wand-sparkles, bot, wrench, puzzle

page.main

Declares that your plugin provides a full-page view accessible at /plugins/:pluginId. Requires a matching sidebar.item contribution for users to navigate to it.

{
  "slot": "page.main",
  "component": "my-page"
}

The component value is a label for your own reference. The desktop app selects the renderer based on your plugin’s kind, not this field.

Renderers by kind:

KindRendererDescription
agent_providerAgent Plugin PageFull-page agent view with lab selector and chat interface
tool_provider(coming soon)Generic tool page

lab.sidepanel

Adds a tab to the lab detail right sidebar. Users can switch between Run, Agent, and your plugin’s tab while working in a lab.

{
  "slot": "lab.sidepanel",
  "component": "my-panel",
  "icon": "wrench",
  "label": "My Tool"
}
FieldTypeRequiredDescription
componentstringNoLabel for your reference.
iconstringNoLucide icon name for the tab button.
labelstringNoTab button label. Defaults to plugin name.

Renderers by kind:

KindRendererDescription
agent_providerAgent Plugin PanelCompact agent chat scoped to the current lab
tool_provider(coming soon)Generic tool panel

settings.section

Declares that your plugin contributes a section to the Settings page.

{
  "slot": "settings.section",
  "component": "my-settings"
}

Settings section rendering is planned for a future release. Currently, plugin settings are managed through the Plugins section in Settings (enable/disable, permissions, updates).

Example: Agent Provider

An agent_provider plugin that appears in the sidebar, has a full-page view, and contributes a lab sidepanel tab:

{
  "id": "openai.codex",
  "name": "Codex Workspace Agent",
  "kind": "agent_provider",
  "ui_contributions": [
    { "slot": "sidebar.item", "icon": "wand-sparkles", "label": "Codex" },
    { "slot": "page.main", "component": "codex-page" },
    { "slot": "lab.sidepanel", "component": "codex-panel", "icon": "wand-sparkles", "label": "Codex" }
  ]
}

This results in:

┌──────────────────────────────────────────────────┐
│ Sidebar (72px)  │  Main Content                  │
│                 │                                │
│  Dashboard      │  (route-dependent)             │
│  Labs           │                                │
│  Models         │                                │
│  Runs           │                                │
│  Hub            │                                │
│  ─────────      │                                │
│  ✨ Codex  ←plugin                               │
│  ─────────      │                                │
│  🧩 Plugins     │                                │
│  Help           │                                │
│  Settings       │                                │
└──────────────────────────────────────────────────┘

Example: Tool Provider

A tool_provider plugin with no sidebar icon, only accessible from the Plugins page:

{
  "id": "acme.data-exporter",
  "name": "Data Exporter",
  "kind": "tool_provider",
  "ui_contributions": []
}

This plugin is visible in Settings > Plugins and Plugins marketplace but does not add a sidebar icon or lab panel tab.

Not Installed Behavior

When a user visits the Plugins marketplace and your plugin is available but not installed, the desktop app shows a generic install card with your plugin’s name, description, version, and an Install button. No custom UI is needed for this. The marketplace card is generated from your manifest metadata.