Skip to content

operator

**Scope**: Kubernetes CRDs (v1alpha2), Helm chart deployment, RBAC, cert-manager TLS, monitoring, and multi-instance management. Does not cover dashboard content or plugin development. **Version range**: Perses Operator v0.4+ (CRD v1alpha2); Helm chart `perses-dev/perses`

From plugin
vexjoy-agent
413198 skills198 agents10 commands86 hooks
Install
$ npx -y skills add notque/vexjoy-agent --agent claude-code

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

**Scope**: Kubernetes CRDs (v1alpha2), Helm chart deployment, RBAC, cert-manager TLS, monitoring, and multi-instance management. Does not cover dashboard content or plugin development. **Version range**: Perses Operator v0.4+ (CRD v1alpha2); Helm chart `perses-dev/perses`

Agent definition

operator.md

Perses Operator Reference

> **Scope**: Kubernetes CRDs (v1alpha2), Helm chart deployment, RBAC, cert-manager TLS, monitoring, and multi-instance management. Does not cover dashboard content or plugin development. > **Version range**: Perses Operator v0.4+ (CRD v1alpha2); Helm chart `perses-dev/perses` > **Generated**: 2026-05-09 — verify against https://github.com/perses/perses-operator

---

Overview

The Perses Operator manages Perses server instances and their associated resources (dashboards, datasources, variables) as Kubernetes CRDs. The operator reconciles `PersesDashboard`, `PersesProject`, `PersesGlobalDatasource`, and `PersesGlobalVariable` objects against the Perses API. The most common failure mode is deploying a `PersesDashboard` before the `PersesProject` it references exists — the operator queues retries silently.

---

Pattern Table

| CRD Kind | Scope | Purpose | Requires | |----------|-------|---------|---------| | `Perses` | Namespaced | Manages a Perses server instance | cert-manager (if TLS) | | `PersesProject` | Namespaced | Creates a project in the Perses API | `Perses` instance | | `PersesDashboard` | Namespaced | Syncs a dashboard to a project | `PersesProject` | | `PersesGlobalDatasource` | Namespaced | Registers a global datasource | `Perses` instance | | `PersesGlobalVariable` | Namespaced | Registers a global variable | `Perses` instance | | `PersesDatasource` | Namespaced | Project-scoped datasource | `PersesProject` |

---

CRD Examples

Perses instance (server deployment)

apiVersion: perses.dev/v1alpha2
kind: Perses
metadata:
  name: perses
  namespace: monitoring
spec:
  # Use StatefulSet when using filesystem storage (default)
  # Use Deployment when using database/etcd storage
  containerPort: 8080
  config:
    database:
      # file-based storage — use PVC for persistence
      file:
        folder: /etc/perses/storage
        extension: json
  security:
    # Enable auth — requires OIDC or native user config
    enableAuth: false
  # TLS via cert-manager
  # tls:
  #   enabled: true
  #   caSecretName: perses-ca

**Why**: `file` storage requires a PVC; without one, pod restarts lose all dashboards. For production use either a PVC or configure etcd.

---

PersesProject

apiVersion: perses.dev/v1alpha2
kind: PersesProject
metadata:
  name: my-team
  namespace: monitoring
spec:
  # instanceRef points to the Perses CR in the same namespace
  instanceRef:
    name: perses

---

PersesDashboard

apiVersion: perses.dev/v1alpha2
kind: PersesDashboard
metadata:
  name: cluster-overview
  namespace: monitoring
spec:
  instanceRef:
    name: perses
  # project must match an existing PersesProject .metadata.name
  project: my-team
  # dashboard is the full Perses dashboard spec (same as percli export output)
  dashboard:
    display:
      name: "Cluster Overview"
    duration: "1h"
    refreshInterval: "30s"
    variables: []
    panels: {}
    layouts: []

**Why**: `spec.project` is the Perses project name (from `PersesProject.metadata.name`), not the Kubernetes namespace. Confusing these is the most common misconfiguration.

---

PersesGlobalDatasource

apiVersion: perses.dev/v1alpha2
kind: PersesGlobalDatasource
metadata:
  name: prometheus
  namespace: monitoring
spec:
  instanceRef:
    name: perses
  datasource:
    display:
      name: "Prometheus"
    default: true
    plugin:
      kind: PrometheusDatasource
      spec:
        # directUrl proxies through the Perses backend
        directUrl: "http://prometheus.monitoring.svc:9090"

---

Helm Chart Deployment

Add the Perses Helm repo

helm repo add perses-dev https://perses-dev.github.io/helm-charts
helm repo update
helm search repo perses-dev/perses --versions | head -5

Minimal values.yaml

# values.yaml
perses:
  config:
    database:
      file:
        folder: /etc/perses/storage
        extension: json
  persistence:
    enabled: true
    size: 5Gi

# Expose via Ingress
ingress:
  enabled: true
  className: nginx
  hosts:
    - host: perses.example.com
      paths:
        - path: /
          pathType: Prefix

# ServiceMonitor for Prometheus scraping
serviceMonitor:
  enabled: true
  interval: 30s
helm upgrade --install perses perses-dev/perses \
  --namespace monitoring \
  --create-namespace \
  --values values.yaml

---

Operator installation

# Install the CRDs and operator
helm upgrade --install perses-operator perses-dev/perses-operator \
  --namespace perses-operator \
  --create-namespace

# Verify operator is running
kubectl get pods -n perses-operator
kubectl get crds | grep perses.dev

---

Pattern Catalog: Detection and Fixes

PersesDashboard deployed before PersesProject

**Detection**:

kubectl get persesdashboard -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}: project={.spec.project}{"\n"}{end}'
kubectl get persesproject -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'
# Compare: every .spec.project in dashboards must have a matching PersesProject .metadata.name

**Signal**:

kubectl get persesdashboard cluster-overview -n monitoring
# STATUS: Pending (retrying)

**Why it matters**: The operator queues the dashboard sync for retry but doesn't surface a clear error. The dashboard never appears in Perses UI and the operator log shows `project "my-team" not found` at debug level only.

**Preferred action**: Apply `PersesProject` in the same manifest before `PersesDashboard`. Use Helm hooks or Argo CD sync waves to enforce ordering.

---

Using `Deployment` with file-based storage

**Detection**:

kubectl get perses -A -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.config.database}{"\n"}{end}'
kubectl get perses -A -o yaml | grep -A3 'database:' | grep -v StatefulSet

**Signal**:

spec:
  config:
    database:
      file:
        fol
Read more
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. AI agents skip steps. "Looks correct" replaces running tests. "Trivial change" replaces verification.

Get the whole plugin, auto-invoked