perses-variable-manage
Perses Variable Management
Create and manage variables with chains and interpolation.
Overview
This skill manages the full lifecycle of Perses variables: creation, configuration, chaining with dependencies, and interpolation across all scopes (global, project, dashboard). Variable chains enable cascading filters where dependent variables only show values filtered by their parent selections — for example, a pod variable that only displays pods matching the selected cluster and namespace.
Instructions
Phase 1: IDENTIFY
Goal: Determine variable type, scope, and dependencies.
Variable types:
- TextVariable: Static text input — user types a value. Use for free-form filters like custom regex or label values not available via query.
- ListVariable: Dynamic dropdown populated by a plugin. Use for most filter/selector use cases.
Variable plugins (for ListVariable):
| Plugin Kind | Source | Use Case |
|---|---|---|
| PrometheusLabelValuesVariable | Label values query | Filter by namespace, pod, job |
| PrometheusPromQLVariable | PromQL query results | Dynamic values from expressions |
| StaticListVariable | Hardcoded list | Fixed options (env, region) |
| DatasourceVariable | Available datasources | Switch between datasource instances |
Variable scopes:
| Scope | Resource Kind | Use Case |
|---|---|---|
| Global | GlobalVariable | Shared filters across all projects and dashboards |
| Project | Variable (in project) | Shared filters across dashboards within a project |
| Dashboard | variables[] in dashboard spec | Dashboard-specific filters |
Interpolation formats (${var:format}):
| Format | Output Example | Use Case |
|---|---|---|
| csv | a,b,c |
Multi-value in most contexts |
| json | ["a","b","c"] |
JSON-compatible contexts |
| regex | a|b|c |
Prometheus label matchers with =~ |
| pipe | a|b|c |
Pipe-delimited lists |
| glob | {a,b,c} |
Glob-style matching |
| lucene | ("a" OR "b" OR "c") |
Loki/Elasticsearch queries |
| values | a+b+c |
URL query parameter encoding |
| singlevariablevalue | Single value | Extracts one value from multi-select |
| doublequote | "a","b","c" |
Quoted CSV |
| singlequote | 'a','b','c' |
Single-quoted CSV |
| raw | a (first only) |
Single value extraction |
Key constraint on variable chains: Variables must be ordered so dependencies come first because Perses evaluates variables in array order. A variable referencing $cluster must appear after the cluster variable definition. This is a strict sequencing requirement — if the parent variable appears after the child, the child will resolve $cluster as empty on first load, returning unfiltered results.
Gate: Variable type, plugin, scope, and dependencies identified. Proceed to Phase 2.
Phase 2: CREATE
Goal: Create the variable resource(s).
Single variable (global scope):
percli apply -f - <<EOF
kind: GlobalVariable
metadata:
name: namespace
spec:
kind: ListVariable
spec:
name: namespace
display:
name: Namespace
hidden: false
allowAllValue: true
allowMultiple: true
plugin:
kind: PrometheusLabelValuesVariable
spec:
labelName: namespace
datasource:
kind: PrometheusDatasource
name: prometheus
EOF
Via MCP (project scope):
perses_create_project_variable(
project="my-project",
name="namespace",
kind="ListVariable",
plugin_kind="PrometheusLabelValuesVariable",
plugin_spec={"labelName": "namespace", "datasource": {"kind": "PrometheusDatasource", "name": "prometheus"}},
allow_multiple=true,
allow_all_value=true
)
Variable chain (dashboard scope — cluster -> namespace -> pod):
When building chains, order variables with dependencies first. Each subsequent variable uses matchers that reference the previous variables using the exact syntax shown below. Always include the datasource field — Perses will not infer it and the variable will fail to resolve if omitted. Use explicit interpolation formats in consuming queries (regex for Prometheus =~ matchers, csv for other contexts) to ensure multi-value substitution works correctly.
variables:
- kind: ListVariable
spec:
name: cluster
display:
name: Cluster
allowAllValue: false
allowMultiple: false
plugin:
kind: PrometheusLabelValuesVariable
spec:
labelName: cluster
datasource:
kind: PrometheusDatasource
name: prometheus
- kind: ListVariable
spec:
name: namespace
display:
name: Namespace
allowAllValue: true
allowMultiple: true
plugin:
kind: PrometheusLabelValuesVariable
spec:
labelName: namespace
datasource:
kind: PrometheusDatasource
name: prometheus
matchers:
- "cluster=\"$cluster\""
- kind: ListVariable
spec:
name: pod
display:
name: Pod
allowAllValue: true
allowMultiple: true
plugin:
kind: PrometheusLabelValuesVariable
spec:
labelName: pod
datasource:
kind: PrometheusDatasource
name: prometheus
matchers:
- "cluster=\"$cluster\""
- "namespace=\"$namespace\""
Default behaviors (applied unless overridden):
- Default to ListVariable with PrometheusLabelValuesVariable plugin for query-driven filtering
- Create variables at dashboard scope unless otherwise specified
- Enable
allowMultipleandallowAllValueby default for filter variables (allows users to select all or no specific values)
Gate: Variables created without errors. Proceed to Phase 3.
Phase 3: VERIFY
Goal: Confirm variables exist and chains resolve correctly.
# List variables in project
percli get variable --project <project>
# List global variables
percli get globalvariable
# Describe specific variable
percli describe variable <name> --project <project>
Or via MCP:
perses_list_variables(project="<project>")
perses_list_global_variables()
Verify chain behavior by checking that dependent variables correctly filter when parent values change (requires UI or API query testing).
Gate: Variables listed and chain dependencies confirmed. Task complete.
Error Handling
| Cause | Symptom | Solution |
|---|---|---|
| Variable chain break: dependent variable defined before its parent in the array | Child variable shows all values instead of filtering by parent selection; Perses evaluates variables in array order, so the parent has no value yet when the child resolves | Reorder the variables array so parents appear before children — cluster before namespace before pod. Each variable can only reference variables that appear earlier in the array |
Wrong interpolation format: using ${var:csv} where ${var:regex} is needed |
Prometheus query with =~ matcher fails with parse error or matches nothing — label=~"a,b,c" is not valid regex, must be label=~"a|b|c" |
Use ${var:regex} for any Prometheus =~ or !~ label matchers. Reserve ${var:csv} for contexts that accept comma-separated lists |
| PrometheusLabelValuesVariable returns empty dropdown | Variable renders with no selectable options despite metrics existing in Prometheus | Check: (1) labelName matches exact Prometheus label name (case-sensitive), (2) matchers filters are not too restrictive or referencing nonexistent parent variables, (3) datasource name matches a configured PrometheusDatasource, (4) Prometheus is reachable from Perses server |
MCP perses_create_project_variable fails |
Error returned from MCP tool call — variable not created | Check: (1) variable name does not already exist in the project (names must be unique per scope), (2) the target project exists (create it first with perses_create_project), (3) plugin kind is spelled correctly (e.g., PrometheusLabelValuesVariable not PrometheusLabelValues) |
| Matcher syntax error in child variable | Child variable returns empty results or Perses logs show query parse errors | Matchers must be exact PromQL label matcher syntax: "label=\"$var\"" with escaped inner quotes. Missing escapes or wrong quote nesting breaks the matcher silently |
Blockers
Stop and resolve before proceeding past each phase gate if any of these conditions exist:
Phase 1 Blockers:
- Variable dependency chain is circular (A -> B -> A) — restructure the chain
- Requested label does not exist in the target Prometheus — verify with
curl -s http://<prometheus>/api/v1/labels - No datasource of the required type is configured in the target project or globally
Phase 2 Blockers:
percli applyor MCP tool returns an error — fix before proceeding- Variable name conflicts with an existing variable at the same scope
- Matchers reference a parent variable that does not exist or is misspelled
Phase 3 Blockers:
- Variable list command does not show the created variable — creation failed silently
- Variable chain produces unfiltered results when parent is selected — dependency order or matcher syntax is wrong
- Variable dropdown is empty — plugin configuration, datasource, or label name is incorrect
Anti-Rationalization Guards
These shortcuts seem reasonable but cause real failures:
- "The variable order doesn't matter, they all resolve eventually": Perses evaluates variables strictly in array order, not by dependency graph. A child variable that appears before its parent will resolve against an empty parent value on first load, silently producing wrong results.
- "I'll just use
$varwithout a format — Perses will figure it out": Bare$varuses the default format which may not match the query context. For Prometheus=~matchers this silently produces wrong results. Always specify the interpolation format explicitly when the variable is multi-select. - "The variable works in the UI so the interpolation must be correct": It may work with a single selection but break with multiple selections. Always test with multiple values selected to verify the interpolation format produces valid query syntax.
- "I'll create the variable and fix the chain order later": Variables that appear to work in isolation will return wrong results when chaining is broken, and the bug is subtle — dashboards show data, just unfiltered data. Get the dependency order right before creating any variables.
Required Patterns
Ensure all configurations follow these requirements:
- Always order child variables after their parents in the variables array — this silently breaks filtering
- Always use
${var:regex}for Prometheus=~or!~matchers — use${var:regex}instead - Always use PrometheusLabelValuesVariable or PrometheusPromQLVariable for dynamic label values — use PrometheusLabelValuesVariable or PrometheusPromQLVariable instead
- Always verify all consuming queries use an appropriate multi-value interpolation format before enabling
allowMultiple: truethat all consuming queries use an appropriate multi-value interpolation format - Always include the
datasourcefield in Prometheus variable plugins — Perses will not infer it and the variable will fail to resolve
References
| Resource | URL | Use For |
|---|---|---|
| Perses Variable Documentation | https://perses.dev/docs/user-guides/variables/ | Variable types, scopes, and configuration |
| Perses Variable Spec (Go types) | https://github.com/perses/perses/tree/main/pkg/model/api/v1/variable | Authoritative field definitions for variable specs |
| Perses Plugin List | https://github.com/perses/plugins | Available variable plugins and their spec schemas |
| Perses MCP Server | https://github.com/perses/perses-mcp-server | MCP tool reference for variable CRUD operations |
| Interpolation Formats Source | https://github.com/perses/perses/tree/main/internal/api/variable | Implementation of all interpolation format handlers |
| percli CLI Reference | https://perses.dev/docs/user-guides/percli/ | CLI commands for variable management |
More from notque/claude-code-toolkit
generate-claudemd
Generate project-specific CLAUDE.md from repo analysis.
12fish-shell-config
Fish shell configuration and PATH management.
12pptx-generator
PPTX presentation generation with visual QA: slides, pitch decks.
12codebase-overview
Systematic codebase exploration and architecture mapping.
10image-to-video
FFmpeg-based video creation from image and audio.
9data-analysis
Decision-first data analysis with statistical rigor gates.
9