Skip to content
Development
Agent

plugin

**Scope**: Plugin scaffolding, CUE schema authoring, React component patterns, archive packaging, and percli plugin commands. Does not cover dashboard consumption of plugins. **Version range**: Perses v0.45+ (Module Federation plugin architecture) **Generated**: 2026-05-09 —

From plugin
vexjoy-agent
443198 skills198 agents12 commands83 hooks

Claude Code

$ npx -y skills add notque/vexjoy-agent --agent claude-code

Agent definition

plugin.md

Perses Plugin Development Reference

> **Scope**: Plugin scaffolding, CUE schema authoring, React component patterns, archive packaging, and percli plugin commands. Does not cover dashboard consumption of plugins. > **Version range**: Perses v0.45+ (Module Federation plugin architecture) > **Generated**: 2026-05-09 — verify against https://github.com/perses/perses/tree/main/docs/plugins

---

Overview

Perses plugins are independently deployable modules that extend the platform with new panel types, datasources, query types, or variable resolvers. Each plugin has three layers: a CUE schema (defines the spec shape), a Go backend (optional — only for datasource/query plugins), and a React/TypeScript frontend component. The most common failure mode is a mismatch between the CUE schema field names and the TypeScript prop names — the backend validates schema but the frontend silently ignores unknown fields.

---

Pattern Table

| Plugin Type | Has Backend | Frontend Component | CUE Schema Required | |------------|-------------|-------------------|---------------------| | Panel | No | Yes — renders data | Yes | | Datasource | Yes — handles HTTP proxying | Yes — editor UI | Yes | | Query | Yes — transforms raw data | Yes — query editor | Yes | | Variable | Yes (optional) | Yes — variable editor | Yes | | Explore | No | Yes — explore view | Yes |

---

Plugin Scaffolding: percli

Generate a new plugin

# Scaffold a panel plugin
percli plugin generate --type panel --name my-chart --output ./plugins/my-chart

# Scaffold a datasource plugin
percli plugin generate --type datasource --name my-datasource --output ./plugins/my-datasource

# Build plugin archive for distribution
percli plugin build --dir ./plugins/my-chart --output ./dist/my-chart.tar.gz

Plugin directory structure (panel example)

plugins/my-chart/
├── plugin.json          # Plugin manifest — name, version, type
├── cue/
│   └── schemas/
│       └── my-chart.cue # CUE schema for panel spec
├── src/
│   ├── index.tsx        # Plugin entry point — exports PanelPlugin
│   ├── MyChart.tsx      # React component
│   └── types.ts         # TypeScript types matching CUE schema
├── package.json
└── webpack.config.js    # Module Federation config

---

CUE Schema Authoring

Minimal panel spec schema

// cue/schemas/my-chart.cue
package schemas

// MyChartSpec defines the configuration for the MyChart panel.
#MyChartSpec: {
    // query is required — references a query variable or inline query
    query: string

    // thresholds are optional visual thresholds
    thresholds?: [...{
        value: number
        color: string
    }]

    // legend controls display; defaults to true
    showLegend?: bool | *true
}

**Why**: Field names in CUE must exactly match the JSON keys sent by the frontend. A field named `showLegend` in CUE but `show_legend` in TypeScript will validate but never populate — the JSON key mismatch is silent.

---

CUE schema validation

# Validate a dashboard JSON against Perses CUE schemas
cue vet -d '#Dashboard' ./schemas/ dashboard.json

# Validate a plugin spec specifically
cue vet -d '#MyChartSpec' ./plugins/my-chart/cue/schemas/ spec.json

# Export CUE schema as JSON Schema for editor tooling
cue export --out json ./plugins/my-chart/cue/schemas/

---

React/TypeScript Frontend Patterns

Plugin entry point (index.tsx)

import { PanelPlugin } from '@perses-dev/plugin-system';
import { MyChart } from './MyChart';
import { MyChartEditor } from './MyChartEditor';
import type { MyChartSpec } from './types';

export const MyChartPanel: PanelPlugin<MyChartSpec> = {
    PanelComponent: MyChart,
    spec: {
        // Default spec used when panel is first added
        initSpec: (): MyChartSpec => ({
            query: '',
            showLegend: true,
        }),
    },
    editor: {
        EditorComponent: MyChartEditor,
    },
};

**Why**: The `initSpec` function must return a valid default that matches the CUE schema. A missing required field in `initSpec` causes the panel editor to open with a validation error before the user touches anything.

---

Accessing query data in a panel component

import { useDataQueries } from '@perses-dev/plugin-system';
import type { TimeSeriesData } from '@perses-dev/core';

export function MyChart({ spec }: PanelProps<MyChartSpec>) {
    const { queryResults, isFetching, error } = useDataQueries('TimeSeriesQuery');

    if (isFetching) return <LoadingOverlay />;
    if (error) return <ErrorAlert error={error} />;

    const data = queryResults[0]?.data as TimeSeriesData | undefined;
    if (!data) return <NoDataOverlay />;

    return <canvas>{/* render data.series */}</canvas>;
}

**Why**: Always handle all three states (`isFetching`, `error`, `!data`). A panel that only handles the happy path shows a blank panel during loading and crashes on query errors, degrading the whole dashboard view.

---

Plugin manifest (plugin.json)

{
    "name": "my-chart",
    "displayName": "My Chart",
    "version": "0.1.0",
    "pluginType": "Panel",
    "components": [
        {
            "kind": "MyChart",
            "display": {
                "name": "My Chart",
                "description": "A custom chart panel"
            }
        }
    ]
}

**Why**: The `kind` field in `plugin.json` must match the `kind` string used in dashboard JSON panel specs. A mismatch causes the panel to render as "Unknown Panel Type" with no useful error.

---

Pattern Catalog: Detection and Fixes

CUE/TypeScript field name mismatch

**Detection**:

# Extract CUE field names
grep -rn '^\s*\w\+?:' --include="*.cue" | sed 's/:.*//' | tr -d ' '

# Compare against TypeScript interface fields
grep -rn '^\s*\w\+\?:' --include="*.ts" | sed 's/:.*//' | tr -d ' '

**Signal**:

// CUE schema:
#Spec: { showLegend?: bool }
// TypeScript type:
interface Spec { show_legend
Read more
@notque
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.

44363 skills198 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
443
Star history of notque/vexjoy-agent on GitHub, a chart by star-history.com

Other agents on vexjoy-agent.

modules

modules

Agent

**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes…

@notque@notqueInstall Agent
testing

testing

Agent

**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**:…

@notque@notqueInstall Agent
communication-patterns

communication-patterns

Agent

**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what…

@notque@notqueInstall Agent

More agents from other plugins.

a11y-architect
Auto-invoked

a11y-architect

Agent

Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI…

ecc12d293k
@affaan-m@affaan-mInstall Agent
analyze-pass-impact

analyze-pass-impact

Agent

Analyzes how a specific topic affects a group of compiler passes. Used by the /plan-update skill to parallelize research across…

react1d252k
@facebook@facebookInstall Agent
orchestrator

orchestrator

Agent

- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as…

codex1d135k
@openai@openaiInstall Agent
cavecrew-builder

cavecrew-builder

Agent

Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical renames, comment removal, format-preserving tweaks. Hard…

caveman2d119k
@juliusbrussee@juliusbrusseeInstall Agent

Questions about plugin.

Which coding agents can use plugin?
plugin installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.