Workflows & UI Extensions
Workflows
Section titled “Workflows”Workflows define multi-step agent pipelines — sequences of phases that transform a task from specification to deployed code.
Workflow definition
Section titled “Workflow definition”Workflows are markdown files with a structured format:
---name: Widget Pipelinedescription: Build, test, and deploy widgets end-to-end.status: active---
## Steps
### research- skill: researching-codebase- timeout_minutes: 15
### plan- skill: planning-implementation- timeout_minutes: 20- depends_on: research
### build- skill: implementing-code- timeout_minutes: 60- depends_on: plan
### test- skill: iterating-on-tests- timeout_minutes: 30- depends_on: build- gate: true- max_retries: 2
### review- skill: packaging-for-review- timeout_minutes: 15- depends_on: testWorkflow fields
Section titled “Workflow fields”| Field | Type | Description |
|---|---|---|
name | string | Display name. |
description | string | What the workflow does. |
status | string | draft, active, or archived. |
Step fields
Section titled “Step fields”| Field | Type | Description |
|---|---|---|
skill | string | The skill ID to execute for this step. |
timeout_minutes | number | Maximum time before the watchdog kills the step. |
depends_on | string | Step ID that must complete first. |
gate | boolean | If true, step must pass before successors run. |
max_retries | number | How many times to retry on failure. |
Running workflows
Section titled “Running workflows”Workflows can be started through:
- MCP tool:
session_delegate({ workflow_id: "widget-pipeline", project: "/path/to/project" }) - Dashboard: Click “Run” on a workflow in the Workflows view
- Automations: Triggered on a schedule or event
UI Extensions
Section titled “UI Extensions”Plugins can extend the Recursive dashboard with new views, panels, navigation items, and custom renderers.
A view is a full-page Svelte component that gets its own route in the dashboard:
{ "ui": { "views": [ { "id": "widgets", "label": "Widgets", "icon": "box", "route": "widgets", "component": "./ui/WidgetsView.svelte", "detailPanel": "./ui/WidgetDetailPanel.svelte" } ] }}The component receives props from the Recursive shell:
<script> let { selectedId = $bindable(null) } = $props();</script>
<div class="widgets-view"> <!-- Your view content --></div>Navigation
Section titled “Navigation”Add entries to the sidebar navigation:
{ "ui": { "nav": [ { "route": "widgets", "label": "Widgets", "icon": "box", "shortcut": "Mod+6", "order": 60, "surface": "sidebar.nav.widgets" } ] }}The order field controls position in the sidebar. Built-in items use 10-40; plugins should use 50+.
Commands
Section titled “Commands”Add entries to the command palette (Cmd+K):
{ "ui": { "commands": [ { "id": "nav-widgets", "label": "Go to Widgets", "icon": "box", "section": "Navigation", "type": "navigate", "route": "widgets", "shortcut": "Mod+6", "keywords": ["widget", "components"] } ] }}Stores
Section titled “Stores”If your view needs reactive state, declare a store module:
{ "ui": { "store": "./ui/widgets-store.ts", "sseEvents": ["widgets"] }}The store module should export initialization and update functions that the dashboard shell calls.
Chat renderers
Section titled “Chat renderers”Custom renderers display rich UI for specific tool call results in the chat feed:
{ "ui": { "chatRenderers": [ { "kind": "widget_create", "component": "./ui/WidgetCreateCard.svelte" } ] }}When an agent calls widget_create and the result appears in the chat, your component renders instead of the default JSON view.
Svelte component guidelines
Section titled “Svelte component guidelines”- Use CSS classes from
src/app.cssfor consistent styling - Follow the 38px compact header pattern for view headers
- Add tooltips to all icon-only buttons
- Use SVG icons from the Recursive icon set (not emoji)
- Ensure viewport-aware positioning for popovers and dropdowns