promql
Skill2 starsChanged 4 months agoMITView on GitHub
You MUST consult this skill when writing or debugging PromQL queries for Prometheus — dashboards, alerting rules, recording rules, or ad-hoc metric exploration. Also trigger on rate vs irate decisions, histogram quantiles, predict_linear for capacity planning, absent() for uptime alerts, or vector matching errors. NOT for Prometheus server deployment (see homelab-monitoring), Loki log queries (see logql), or Grafana datasource configuration.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- grafana/skillstheir own version, first seen Oct 27, 2026
- Egoushka/agent-skillstheir own version, first seen Sep 26, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- grafana/skills★ 302same name
- Egoushka/agent-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository67 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agent-architectureSkill
- agent-evaluationSkill
- agent-memorySkill
- agent-post-trainingSkill
- agent-self-evolutionSkill
- agent-tool-designSkill
- api-designSkill
- application-architectureSkill
- brainstormSkill
- code-reviewerSkill
- coding-agent-designSkill
- concurrency-designSkill
- context-engineeringSkill
- dockerSkill
- game-audioSkill
- game-designSkill
- game-narrativeSkill
- game-patternsSkill
- game-performanceSkill
- game-renderingSkill
- game-visualsSkill
- git-commitSkill
- git-prSkill
- godot-shaderSkill
- godotSkill
- gpu-rendering-architectureSkill
- grafanaSkill
- helmSkill
- homelab-monitoringSkill
- k3sSkill
- k8s-networkingSkill
- k8s-operationsSkill
- k8s-storageSkill
- k8s-workloadsSkill
- knowledge-baseSkill
- level-designSkill
- llm-inference-servingSkill
- loggingSkill
- logqlSkill
- love2d-fennelSkill
- love2dSkill
- ml-platform-architectureSkill
- ml-post-trainingSkill
- multi-agent-collaborationSkill
- nix-dendriticSkill
- nix-packagingSkill
- nixSkill
- odin-designSkill
- odin-gamedevSkill
- orchestratorSkill
- physical-ai-systemsSkill
- plannerSkill
- prd-to-storiesSkill
- prd-writingSkill
- pr-reviewerSkill
- python-designSkill
- rag-designSkill
- ray-data-pipelinesSkill
- ray-kubernetes-infrastructureSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 42
Add bool modifier for 0/1 output instead of filtering: up == bool 1
- Distinctive: line 48
When combining two metrics, Prometheus matches on all shared labels by default.
- Very specific: line 79
Range window rule: use >= 4× scrape interval.
- Distinctive: line 103
If you aggregate across jobs/instances and want per-job quantiles:
- Very specific: line 112
Run an instant query over a range — useful for max_over_time of a derived metric:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
PromQL
PromQL is Prometheus's functional query language. This skill covers homelab usage with node-exporter, cAdvisor/Docker metrics, and app-specific exporters (Plex, Sonarr, Radarr, Prowlarr, Home Assistant, AdGuard Home).
Data Types
| Type | Description | When you have it |
| Instant vector | One sample per series at current time | Bare metric name or {} selector |
| Range vector | Multiple samples over a window | Metric with [5m] appended |
| Scalar | Single number | scalar(), arithmetic on instant vectors |
| String | Unused in practice | — |
Range vectors can only be passed to functions (rate, avg_over_time, etc.) — they can't be graphed directly.
Selectors
node_cpu_seconds_total{mode="idle", instance="homelab:9100"} # exact match
container_memory_usage_bytes{name=~"sonarr|radarr"} # regex match
up{job="plex"}[5m] # range vector
up offset 1h # 1h agoLabel matchers:
=exact,!=not equal=~regex (RE2, fully anchored —sonarrmatches onlysonarr, use.*sonarr.*for substring)!~negated regex
Operators
Arithmetic: +, -, *, /, %, ^
Comparison: ==, !=, >, <, >=, <=
- Add
boolmodifier for 0/1 output instead of filtering:up == bool 1
Logical: and, or, unless
Vector Matching
When combining two metrics, Prometheus matches on all shared labels by default. Mismatches cause empty results or errors.
a / on(job, instance) b # match only on these labels
a / ignoring(status_code) b # match on all labels except these
a / on(job) group_left() b # many-to-one: left side has more series
a / on(job) group_right() b # one-to-many: right side has more seriesDiagnose mismatches: count by (instance) (metric_a) vs count by (instance) (metric_b) — labels must align.
Aggregation
sum by (instance) (rate(node_cpu_seconds_total[5m])) # keep instance, drop rest
avg without (cpu) (rate(node_cpu_seconds_total[5m])) # drop cpu, keep rest
topk(5, rate(container_cpu_usage_seconds_total[5m])) # top 5 containers by CPUOperators: sum, avg, min, max, count, topk, bottomk, stddev, stdvar, quantile, group.
Rate Functions — Decision Table
| Function | Input | Use When |
rate(v[d]) | Counter range | Default for counters (_total) — handles resets, good for alerting |
irate(v[d]) | Counter range | High-resolution spikes — not for alerting (too volatile) |
increase(v[d]) | Counter range | Total increase over window (e.g., requests in last hour) |
delta(v[d]) | Gauge range | Change in a gauge over window |
deriv(v[d]) | Gauge range | Rate of change for gauges (linear regression) |
Range window rule: use >= 4× scrape interval. With 15s scrape: use [60s] minimum, [5m] is typical.
Aggregation Over Time
For smoothing or summarizing a metric over a window without rate:
avg_over_time(node_load1[30m]) # 30-min average of load
max_over_time(container_memory_usage_bytes{name="plex"}[1h])Functions: avg_over_time, min_over_time, max_over_time, sum_over_time, count_over_time, quantile_over_time, last_over_time.
Histograms
Classic histograms (most exporters): preserve the le label when aggregating.
# 95th percentile request latency
histogram_quantile(0.95,
sum by (le) (rate(http_request_duration_seconds_bucket[5m]))
)If you aggregate across jobs/instances and want per-job quantiles:
histogram_quantile(0.95,
sum by (le, job) (rate(http_request_duration_seconds_bucket[5m]))
)Subqueries
Run an instant query over a range — useful for max_over_time of a derived metric:
max_over_time(rate(container_cpu_usage_seconds_total[5m])[1h:1m])
# reads as: "max of the 5m rate, sampled every 1m, over the past 1h"Label Functions
label_replace(metric, "dst_label", "$1", "src_label", "(.*)")
label_join(metric, "dst_label", "/", "src1", "src2")Prediction (Homelab Killer Feature)
predict_linear fits a linear regression and extrapolates forward:
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0- First arg: range vector — the window determines regression accuracy. Use 6h–24h for disk (slow trends). Too short = noisy; too long = misses recent changes.
- Second arg: seconds to project ahead (
24*3600= 24 hours) - Result
< 0means "disk will be full within 24h"
Existence / Uptime Checks
absent(up{job="sonarr"}) # fires when sonarr disappears from scrape
absent_over_time(up{job="plex"}[5m]) # fires when plex has been down 5+ minutesabsent returns a 1-element vector when the selector matches nothing. Use in alerting rules to detect services that stopped reporting.
Important caveats:
absent(up{job="sonarr"})only fires when the entire job disappears. With multiple instances, it won't fire if one instance is down but others are up. For per-instance alerting, useup{job="sonarr"} == 0withfor: 5minstead.absent_over_timedetects missing scrape data (exporter unreachable), notup == 0(service down but exporter running). For "service down", useup{job="plex"} == 0.
Common Mistakes
| Mistake | Fix |
rate(node_memory_MemAvailable_bytes[5m]) | Memory is a gauge — use it directly: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes |
sum(http_requests_total) without rate | Wrap in rate() first: sum(rate(http_requests_total[5m])) |
sum(rate(http_request_duration_seconds_bucket[5m])) | Missing by (le) — histogram quantile needs le label |
rate(metric[15s]) with 15s scrape interval | Range must be >= 4× scrape: use [60s] minimum |
irate() in alerting rules | Use rate() — irate is too volatile for reliable alerts |
Regex {name="sonarr"} matching nothing | RE2 is fully anchored; use {name=~".*sonarr.*"} for substring or exact {name="sonarr"} |
Recording Rules Naming
Convention: level:metric:operations
groups:
- name: homelab.rules
rules:
- record: instance:node_cpu:rate5m
expr: 1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))Homelab Examples
CPU usage % per node:
1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))Memory pressure:
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)Disk filling prediction (alert when full within 24h):
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0Container down alert (single instance — exporter unreachable):
absent(up{job="sonarr", instance="homelab:8989"})Container down alert (service down, exporter still running):
up{job="sonarr"} == 0Error rate % (returns no result — not 0% — when there is no traffic):
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (job) (rate(http_requests_total[5m])) * 100Top 5 containers by memory:
topk(5, container_memory_usage_bytes{name!=""})Alerting rule example:
groups:
- name: homelab.alerts
rules:
- alert: DiskFillingSoon
expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0
for: 15m
labels:
severity: warning
annotations:
summary: "Disk on {{ $labels.instance }} fills within 24h"Note: keep for: much shorter than the prediction horizon. for: 1h with a 24h prediction means the alert only fires after the condition has been true for 1 hour — by then you may have less than 23h of lead time.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

