promql — Claude Code skill: write and debug PromQL queries
Writes and validates PromQL against Prometheus, Mimir and Grafana Cloud Metrics. Useful when a p95 looks wrong or a query drags.
npx skills add grafana/skills --skill promql -a claude-codeWhat promql does
The skill hands your agent a PromQL pattern library: rate versus irate and increase, label matchers and regex, sum / avg / topk / by / without aggregation, histogram_quantile for classic and native histograms, ratios with divide-by-zero guards, absent and changes for staleness, time offsets and predict_linear, recording-rule naming, SLO and burn-rate math. There is also a playbook for hunting the noisy label behind a cardinality spike.
It works in steps. You sketch the expression, the agent checks syntax and whether the metric and labels exist through /api/v1/query and /api/v1/series, then you confirm the magnitude in Grafana Explore against a known ground truth. A slow dashboard query can become a recording rule: the expression gets a name like job:http_request_duration_p95:rate5m, the rule loads, the new metric is verified with the same query, and only then does the panel switch to it.
The window is where most people trip. rate() and increase() need a range vector at least four times the scrape interval; with a 60s scrape that means [5m] minimum. Go shorter and you get "No data", then waste time checking label spelling instead of the window. You also need a Prometheus, Mimir or Grafana Cloud endpoint to query, and on Grafana Cloud every curl carries basic auth.
What it helps with
- compute the 5xx share per service
- fix a p95 that comes out wrong
- build an error-budget alert
- find the label that blew up cardinality
- turn a slow dashboard query into a recording rule
Example prompts for the agent
- calculate the error rate per service over 5 minutes
- why is this query slow and what's filling Mimir
- turn this expression into a recording rule for p95
How to install promql
1Skills CLI (Vercel)
npx skills add grafana/skills --skill promql -a claude-code2Manually: put the files in place
~/.claude/skills/promql/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/promql/
1Skills CLI (Vercel)
npx skills add grafana/skills --skill promql -a codex2Manually: put the files in place
.agents/skills/promql/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add grafana/skills --skill promql -a cursor2Manually: put the files in place
.cursor/skills/promql/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install grafana/skills promql2Manually: put the files in place
.github/skills/promql/SKILL.md1Skills CLI (Vercel)
npx skills add grafana/skills --skill promql -a gemini-cli2Platform CLI
gemini skills install https://github.com/grafana/skills --path skills/grafana-core/promqlManually: put the files in place
.devin/skills/promql/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add grafana/skills --skill promql -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about promql
How do I install promql in Claude?
Run npx skills add grafana/skills --skill promql -a claude-code. The skill lands in ~/.claude/skills/promql/SKILL.md.
What does the promql skill do?
It gives the agent PromQL patterns plus a validation order: syntax, metric existence, magnitude check. It also covers common bugs such as NaN from histogram_quantile.
What do I need before using it?
A Prometheus, Mimir or Grafana Cloud Metrics endpoint to query. On Grafana Cloud, add basic auth with the metrics user and token to each curl.
Source text
SKILL.md · Apache-2.0
---
name: promql
license: Apache-2.0
description: Write, validate, and optimize PromQL for Prometheus / Grafana Mimir / Grafana Cloud Metrics. Covers `rate` vs `irate` vs `increase`, label matchers and regex, `sum / avg / topk / by / without` aggregation, classic + native `histogram_quantile`, ratios with divide-by-zero guards, `absent` / `changes` for staleness, time offsets and `predict_linear`, recording-rule naming, SLO + burn-rate math, and a cardinality-hunting playbook. Use when writing a metric query, fixing wrong p95s, building an error-budget alert, debugging "query is slow", finding the noisy label that blew up cardinality, or migrating a dashboard query to a recording rule — even when the user says "calculate the error rate", "p99 latency", "sum by service", "why is this query slow", or "what's filling Mimir" without naming PromQL.
---
# PromQL Query Patterns
> **Docs**: https://prometheus.io/docs/prometheus/latest/querying/basics/
PromQL returns either an **instant vector**, a **range vector**, or a **scalar**.
**Golden rule:** `rate()` / `increase()` require a range vector ≥ 4× the scrape interval. 60s scrape → use `[5m]` minimum.
## Prerequisites
- A Prometheus / Mimir / Grafana Cloud endpoint to query (`/api/v1/query` or via Grafana Explore)
- The PromQL pattern library in [`references/patterns.md`](references/patterns.md)
## Common Workflows
### 1. Write + validate a query
```bash
# 0. Point at your Prometheus/Mimir. For Grafana Cloud, use the metrics endpoint
# and add basic auth (-u "<metrics_user>:<token>") to each curl below.
PROM=http://localhost:9090 # or https://prometheus-prod-XX.grafana.net/api/prom
# 1. Sketch the query — for "5xx error rate per service":
EXPR='sum(rate(http_requests_total{status_code=~"5.."}[5m])) by (service)'
# 2. Validate syntax + that the metric/labels exist
curl -sG --data-urlencode "query=${EXPR}" \
"$PROM/api/v1/query" | jq '.status, (.data.result|length)'
# Expect: "success" and result count > 0. If 0 — check label spelling and scrape activity:
curl -sG --data-urlencode "match[]=http_requests_total" "$PROM/api/v1/series" | jq '.data | length'
# 3. Sanity-check the magnitude — open Grafana Explore, paste the expr,
# confirm the values look right against a known ground truth (k6 run, log count, etc.)
```
### 2. Common patterns to copy
**Per-status request rate** (aggregate AFTER rate):
```promql
sum(rate(http_requests_total{job="api"}[5m])) by (status_code)
```
**p95 latency** (must keep `le` in the inner aggregation):
```promql
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))
```
**Error rate with divide-by-zero guard:**
```promql
sum(rate(http_requests_total{status_code=~"5.."}[5m]))
/ (sum(rate(http_requests_total[5m])) > 0)
```
Full library (recording rules, SLO burn-rate, offsets, cardinality hunt, native histograms): [`references/patterns.md`](references/patterns.md).
### 3. Convert a slow dashboard query into a recording rule
```yaml
# 1. Pick the slow expression, give it a recording-rule name
groups:
- name: http_request_rates
interval: 1m
rules:
- record: job:http_request_duration_p95:rate5m
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))
```
```bash
# 2. After rules load, verify the new metric exists
curl -sG --data-urlencode "query=job:http_request_duration_p95:rate5m" \
"$PROM/api/v1/query" | jq '.data.result | length' # → > 0
# 3. Verify it matches the original expression for at least one sample window
# (Both queries should produce the same value at the same timestamp.)
# 4. Replace the dashboard panel expression with the recording-rule metric.
```
## Common bugs
- `histogram_quantile` returns NaN → forgot `by (le)` in the inner aggregation
- "No data" → check the metric exists (`/api/v1/series`) and the window ≥ 4× scrape interval
- Wrong rate magnitude → counter was aggregated before `rate()` (always `rate()` first)
- Query timeout → series count too high; use `topk(...)` + a recording rule + drop high-cardinality labels (see [`references/patterns.md`](references/patterns.md))
## Resources
- [PromQL basics](https://prometheus.io/docs/prometheus/latest/querying/basics/)
- [Operators](https://prometheus.io/docs/prometheus/latest/querying/operators/)
- [Functions](https://prometheus.io/docs/prometheus/latest/querying/functions/)
- [Grafana Mimir](https://grafana.com/docs/mimir/latest/)
© grafana · Apache-2.0 · grafana/skills