Skip to content
PricingReleases

plugin.json Manifest Reference

The plugin.json file is the only required file in a plugin. It declares what the plugin provides and how Recursive should load it.

{
"id": "my-plugin",
"name": "My Plugin",
"version": "0.1.0",
"description": "What this plugin does."
}

Unknown fields are ignored with a warning in the plugin’s health panel (typos like skilss get a did-you-mean suggestion); wrong-typed fields are dropped with a warning. Only a missing id prevents the plugin from loading. Validate anytime with the plugin_validate tool.

| Field | Type | Required | Description | |---|---|---|---| | id | string | Yes | Unique kebab-case plugin identifier. | | name | string | No | Display name (falls back to id). | | version | string | No | Semver version, compared against the registry for update checks. | | description | string | No | One-line summary shown in the plugins UI and registry. | | author | string \| object | No | Author attribution — a string or { name, url }. | | homepage | string | No | Project homepage or docs URL. | | color | string | No | Hex color for the icon badge. | | icon | string | No | Icon name from the Recursive icon set. | | thumbnail | string | No | Path to a thumbnail image within the plugin. | | category | string | No | Marketplace category. | | tags | string[] | No | Marketplace search tags. | | appScope | string | No | Which app the plugin applies to: recursive, financial, or shared. | | private | boolean | No | Excluded from registry publishing. | | platforms | string[] | No | OS allowlist (e.g. [“darwin”]); omit for all platforms. | | min_recursive_version | string | No | Minimum Recursive version this plugin supports; enforced at install. |

Each points to a directory or file (relative to the plugin root) that Recursive loads. A string can be a directory (ending in /) or a single file; an array mixes both. When the field is omitted, a conventional directory of the same name is picked up automatically.

| Field | Type | Required | Description | |---|---|---|---| | tools | string \| string[] | No | MCP tool handler modules (JS/TS). | | routes | string \| string[] | No | HTTP route handler modules. | | adapters | string \| string[] | No | Agent CLI adapter modules (JS/TS). | | skills | string \| string[] | No | Skill directories containing SKILL.md subfolders. | | rules | string \| string[] | No | Agent rule markdown files. | | automations | string \| string[] | No | Automation definitions. | | hooks | string \| string[] | No | Server lifecycle hook handler modules. | | mcp | string \| string[] | No | External MCP server configuration (JSON). | | themes | string \| string[] | No | Theme JSON files. | | sounds | string \| string[] | No | Sound pack audio files (mp3/wav/ogg/m4a/aac/aiff). | | comms | string \| string[] | No | Comms templates directory. |

| Field | Type | Required | Description | |---|---|---|---| | ui | object | No | UI extensions: views, panels, commands, chat renderers, components. | | settings | object | No | Settings schema and defaults rendered in the plugin settings page. | | detect | object | No | Project auto-detection: file patterns that suggest enabling this plugin. | | data | object | No | Data directory scopes the plugin persists into (global/workspace/project). | | provides | object | No | Structured provider declarations (sync_provider, auth_provider, data_provider) — each is { id, name, entry, config_schema }; auth_provider contributes a pluggable identity/permission backend (see core-identity provider-registry). | | triggers | object | No | Declares the plugin as an event trigger source: module (exports verify/normalize, plus optional respond for posting session outcomes back to the provider), a non-empty events[] of { type, label, filters, firehose? } (firehose = fires at high volume; the editor shows a cost warning), optional setupSkill, setupInstructions (markdown checklist of provider-side setup, rendered in the auto-generated onboarding), and requiredSettings. | | lifecycle | object | No | Server lifecycle hook handlers keyed by event name. | | client_lifecycle | object | No | Client (renderer) lifecycle hook handlers keyed by event name. | | soundDefaults | Record<string, string> | No | Sound packs: notification event → sound slug mapping. | | dependencies | string[] | No | Plugin ids this plugin requires. | | bundledOptIn | boolean | No | Bundled copy is marketplace-only until explicitly installed. | | core | boolean | No | Core platform plugin — boot-synced, cannot be disabled. | | npm | object | No | npm install behavior — set { “scripts”: true } to allow lifecycle scripts (disclosed at install). |

| Field | Type | Required | Description | |---|---|---|---| | loginCommand | string | No | Command that (re)authenticates the plugin’s CLI. | | setupCommand | string | No | First-time configuration command. | | diagnoseCommand | string | No | Health-check / repair command. | | installCommand | string | No | Command that installs the CLI itself. | | installUrl | string | No | Docs or download URL for installing the CLI. | | cli | object | No | How to probe whether the CLI is installed (bin, versionArgs). | | app | object | No | Desktop-app provider config (name, downloadUrl, healthUrl). | | setupSequence | object[] | No | Ordered getting-started steps shown after install. | | onboarding | object | No | Declarative onboarding steps (fields, verify, links, markdown instructions). Trigger-source plugins also get platform-generated copy-URL and await-event steps appended automatically. |

The ui field is an object that declares frontend components and behaviors.

Array of view definitions that add new pages to the dashboard.

{
"ui": {
"views": [
{
"id": "my-view",
"label": "My View",
"icon": "layers",
"route": "my-view",
"component": "./ui/MyView.svelte",
"detailPanel": "./ui/MyDetailPanel.svelte"
}
]
}
}

| Field | Type | Description | |---|---|---| | id | string | Unique view identifier. | | label | string | Display name in navigation. | | icon | string | Icon name. | | route | string | URL route segment (e.g., my-view/my-view). | | component | string | Path to the main Svelte component. | | detailPanel | string | Optional path to a detail panel component. |

Array of navigation entries added to the sidebar.

{
"ui": {
"nav": [
{
"route": "my-view",
"label": "My View",
"icon": "layers",
"shortcut": "Mod+5",
"order": 50,
"surface": "sidebar.nav.my-view"
}
]
}
}

Array of command palette entries.

{
"ui": {
"commands": [
{
"id": "nav-my-view",
"label": "Go to My View",
"icon": "layers",
"section": "Navigation",
"type": "navigate",
"route": "my-view",
"shortcut": "Mod+5",
"keywords": ["custom", "view"]
}
]
}
}

Panels added to the workspace detail area (alongside file viewer, preview, etc.).

Panels added to the task detail view.

Custom renderers for specific tool call results in the chat feed.

{
"ui": {
"chatRenderers": [
{
"kind": "goal_create",
"component": "./ui/GoalCreateRenderer.svelte"
}
]
}
}

Register custom entity types for mention resolution and search.

{
"ui": {
"entityTypes": [
{
"type": "goal",
"storeKey": "allGoals",
"nameKey": "title"
}
]
}
}

SSE event channels that the plugin’s store should listen to.

Frontend stores are discovered by convention, not declared: any ui/*-store.ts module in a bundled plugin is auto-registered, its load<Name>() export is called on mount, and SSE events matching the plugin id (or declared via ui.sseEvents) re-invoke it.

Map of named components that other parts of the UI can reference.

Plugin configuration with defaults and a schema for the settings UI.

{
"settings": {
"defaults": {
"api_key": "",
"enabled_features": ["basic"]
},
"schema": [
{
"key": "api_key",
"type": "string",
"label": "API Key",
"description": "Your service API key.",
"section": "Authentication"
},
{
"key": "enabled_features",
"type": "multi-select",
"label": "Features",
"options": ["basic", "advanced", "experimental"],
"section": "Features"
}
]
}
}

Auto-detection rules that enable the plugin when a project matches.

{
"detect": {
"files": ["package.json", "tsconfig.json"],
"strategy": "all"
}
}

| Field | Type | Default | Description | |---|---|---|---| | files | string[] | — | File patterns to check in the project root. | | strategy | "any" \| "all" | "any" | Whether any file match suffices or all must be present. |

Server-side lifecycle event handlers. Keys are event names, values define the handler.

{
"lifecycle": {
"session.complete": {
"handler": "./hooks/on-session-complete.ts",
"priority": 10,
"type": "action"
}
}
}

Client-side lifecycle event handlers. Same structure as lifecycle but handlers run in the browser.

{
"client_lifecycle": {
"session.complete": {
"handler": "./hooks/client-on-complete.ts",
"priority": 10
}
}
}

Declares the plugin as an event trigger source for event-mode automations. See Building a Trigger Plugin for the full contract.

{
"triggers": {
"module": "./triggers/index.js",
"setupSkill": "connecting-my-provider",
"requiredSettings": ["signing_secret"],
"events": [
{ "type": "issue.created", "label": "Issue created", "filters": ["project"] }
]
}
}

| Field | Required | Description | |---|---|---| | module | Yes | Path to the file exporting verify(rawBody, headers, connection) and normalize(payload, headers, connection). Without it the whole block is dropped (with a warning). | | events | Yes | Non-empty array of { type, label, description?, filters? }. type (non-empty string) is matched against automations’ event_type; label is shown in the automation editor. A zero-event source is skipped by the trigger catalog — the validator warns about it. | | setupSkill | No | Skill id that walks the user through connecting the provider. Should correspond to a skill this plugin ships — plugin_validate warns when skills/<name>/SKILL.md is missing. | | requiredSettings | No | Settings keys (from settings.schema) that must be non-empty for the source to show as “Connected”. Defaults to every password-type setting. |

These two fields solve different problems — don’t mix them up:

  • onboarding is declarative plugin setup: a subtitle plus steps of kind link (open an external console), field (save a settings value, optionally secret), and verify (confirm required credentials are present), rendered in the plugin’s settings page. Use it for integrations that need credentials — trigger sources, API-backed tools.
  • setupSequence is adapter/CLI onboarding only: ordered terminal-action steps (install / auth / setup / diagnose, falling back to installCommand / loginCommand / setupCommand / diagnoseCommand) shown after installing a provider CLI plugin. Use it when the plugin wraps a CLI that must be installed and authenticated.
{
"onboarding": {
"subtitle": "Connect your workspace so agents pick up events.",
"steps": [
{ "kind": "link", "title": "Create an app", "url": "https://example.com/apps", "actionLabel": "Open console" },
{ "kind": "field", "title": "Add your Signing Secret", "field": { "key": "signing_secret", "secret": true }, "actionLabel": "Save" },
{ "kind": "verify", "title": "Verify setup", "actionLabel": "Verify" }
]
}
}