grafana
Skill2 starsChanged 4 months agoMITView on GitHub
You MUST consult this skill when authoring Grafana dashboards, configuring panels or template variables, wiring datasources, or setting up alerting rules and contact points. Also trigger on GrafanaDashboard/GrafanaDatasource CRDs (Grafana Operator), file-based provisioning for Docker Compose, Discord/email alert routing, and drilldown dashboard design. NOT for PromQL query syntax (see promql), LogQL syntax (see logql), or deploying the monitoring stack (see homelab-monitoring).
- Reads credentials
8 other projects use a version of this.
Adopted by
Most recently taken up by
- chenwei791129/agent-skillstheir own version, first seen Oct 19, 2026
- G1Joshi/Agent-Skillstheir own version, first seen Oct 13, 2026
- NVIDIA/AI-Factory-Operations-Agenttheir own version, first seen Oct 13, 2026
- rkhozinov/claude-skillstheir own version, first seen Jul 29, 2026
- magnus919/agent-skillstheir own version, first seen Jul 21, 2026
- addxai/enterprise-harness-engineeringtheir own version, first seen Apr 17, 2026
Other versions8 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 8
- magnus919/agent-skills★ 172same name
- addxai/enterprise-harness-engineering★ 44same name
- NVIDIA/AI-Factory-Operations-Agent★ 37same name
- G1Joshi/Agent-Skills★ 15same name
- koderover/devops-skills★ 7same name
- ffsshhttiikk/opencode-agents-skills★ 2same name
- chenwei791129/agent-skills★ 0same name
- rkhozinov/claude-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
- 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
- promqlSkill
- 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
6 rules. 0 are common, 2 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 7 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 22
Every dashboard is a JSON object.
- Very specific: line 120
When $service changes, Grafana re-queries the $instance options automatically.
- Very specific: line 155
Use $__rate_interval instead of a hardcoded window in rate() — it adapts to zoom level.
- Distinctive: line 254
Import from grafana.com instead of inline JSON:
- Very specific: line 280
Place dashboard JSON files alongside provider.yaml.
- Very specific: line 386
Every panel in a dashboard should use the same variables.
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Grafana
Homelab-focused Grafana skill covering dashboard authoring, template variables, IaC provisioning (Grafana Operator CRDs and file-based), and alerting.
Two IaC paths:
- k3s: Grafana Operator CRDs (
GrafanaDashboard,GrafanaDatasource) — GitOps-friendly - Compose: File-based provisioning — JSON dashboards + YAML provider configs mounted into the container
See references/crd-examples.md for full YAML examples of both paths.
Dashboard JSON Model
Every dashboard is a JSON object. Key top-level fields:
{
"title": "Homelab Overview",
"uid": "homelab-overview",
"schemaVersion": 38,
"time": { "from": "now-6h", "to": "now" },
"refresh": "30s",
"templating": { "list": [] },
"annotations": { "list": [] },
"panels": []
}uid: stable identifier — used in dashboard links and provisioning; keep it short and slug-likeschemaVersion: use 38+ (current stable)refresh: omit or set""to disable auto-refresh;"30s"is a good homelab default
Panel Structure
{
"type": "timeseries",
"title": "Request Rate",
"gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 },
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
"targets": [
{
"expr": "rate(http_requests_total{job=\"$service\"}[$__rate_interval])",
"legendFormat": "{{method}} {{status}}"
}
],
"options": {},
"fieldConfig": {
"defaults": { "unit": "reqps" },
"overrides": []
}
}gridPos: 24-column grid;w: 24= full width,w: 12= halfdatasource.uid: use${DS_PROMETHEUS}or${DS_LOKI}so the dashboard is portable across instancestargets[].expr: parameterize with variables like$service,$container
Panel Type Decision Table
| Type | Use When |
timeseries | Values over time — CPU, memory, request rate, error rate |
stat | Single current value — uptime status, current temp, active streams |
gauge | Value within a bounded range — disk %, memory %, queue fill |
table | Multi-column data — per-service breakdown, top-N lists |
logs | Raw log lines from Loki |
barchart | Categorical comparison — requests per service, errors by type |
row | Collapsible section header — group panels by concern |
Template Variables
Variables appear as dropdowns at the top of the dashboard. Every panel query that uses $variable syntax updates when the variable changes.
Variable JSON (inside templating.list)
Query variable — values come from a datasource query:
{
"name": "service",
"type": "query",
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
"query": {
"query": "label_values(up, job)",
"refId": "StandardVariableQuery"
},
"refresh": 2,
"sort": 1,
"multi": false,
"includeAll": true,
"allValue": ".*",
"label": "Service"
}Chained variable — $instance options depend on $service:
{
"name": "instance",
"type": "query",
"query": {
"query": "label_values(up{job=\"$service\"}, instance)"
},
"refresh": 2
}When $service changes, Grafana re-queries the $instance options automatically.
Container variable for Loki:
{
"name": "container",
"type": "query",
"datasource": { "type": "loki", "uid": "${DS_LOKI}" },
"query": { "label": "container", "stream": "{}" },
"refresh": 2
}Note: Loki variables use
{"label": "...", "stream": "..."}— notlabel_values()which is Prometheus-only.
Using Variables in Queries
# Prometheus — filter by variable
rate(container_cpu_usage_seconds_total{container="$container"}[$__rate_interval])
# Loki — filter log stream
{container="$container"} |= "error"Built-in Variables
| Variable | Value |
$__interval | Calculated step interval for the current time range |
$__rate_interval | Safe interval for rate() — always ≥ 4× scrape interval |
$__range | Duration of the selected time range (e.g., 6h) |
$__from / $__to | Time range as epoch milliseconds |
Use $__rate_interval instead of a hardcoded window in rate() — it adapts to zoom level.
Datasource Configuration
k3s Path — Grafana Operator CRDs
The Grafana Operator manages a Grafana custom resource (CR) in your cluster. Every GrafanaDatasource and GrafanaDashboard CRD must have an instanceSelector that matches the labels on that Grafana CR. The homelab standard is dashboards: grafana.
If datasources or dashboards don't appear: Verify the Grafana CR has the matching label:
kubectl get grafana -n monitoring --show-labels. The operator silently skips CRDs whoseinstanceSelectordoesn't match — no error is emitted to the resource status.
# Prometheus datasource
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDatasource
metadata:
name: prometheus
namespace: monitoring
spec:
instanceSelector:
matchLabels:
dashboards: grafana
datasource:
name: Prometheus
type: prometheus
url: http://kube-prometheus-stack-prometheus.monitoring.svc:9090
access: proxy
isDefault: true
jsonData:
timeInterval: "30s"# Loki datasource
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDatasource
metadata:
name: loki
namespace: monitoring
spec:
instanceSelector:
matchLabels:
dashboards: grafana
datasource:
name: Loki
type: loki
url: http://loki.monitoring.svc:3100
access: proxyCompose Path — File Provisioning
# /etc/grafana/provisioning/datasources/datasources.yaml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
access: proxy
isDefault: true
- name: Loki
type: loki
url: http://loki:3100
access: proxyMount this file into the Grafana container:
volumes:
- ./provisioning/datasources:/etc/grafana/provisioning/datasources:roDashboard Provisioning
k3s — GrafanaDashboard CRD
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDashboard
metadata:
name: homelab-overview
namespace: monitoring
spec:
instanceSelector:
matchLabels:
dashboards: grafana
json: |
{
"title": "Homelab Overview",
"uid": "homelab-overview",
"schemaVersion": 38,
"panels": []
}Import from grafana.com instead of inline JSON:
spec:
instanceSelector:
matchLabels:
dashboards: grafana
grafanaCom:
id: 1860 # Node Exporter Full
revision: 37Compose — File Provisioning
# /etc/grafana/provisioning/dashboards/provider.yaml
apiVersion: 1
providers:
- name: default
folder: Homelab
type: file
disableDeletion: false
updateIntervalSeconds: 30
options:
path: /etc/grafana/provisioning/dashboardsPlace dashboard JSON files alongside provider.yaml. Grafana polls the directory every updateIntervalSeconds.
Alerting
Alert Rule Structure
Grafana-managed alert rules live in evaluation groups. Each rule has:
- Query/expression: PromQL or LogQL that returns a value
- Condition: threshold that triggers the alert (e.g.,
IS ABOVE 0) forduration: how long the condition must hold before firing- Labels: used for routing (e.g.,
severity: critical,team: homelab) - Annotations:
summaryanddescription— support{{ $labels.job }}templating
Example — container down alert (conceptual — see references/crd-examples.md for full CRD syntax):
# Grafana UI: Alerting → Alert rules → New alert rule
expr: up{job="sonarr"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.job }} is down"
description: "{{ $labels.job }} on {{ $labels.instance }} has been unreachable for 2 minutes"Contact Points
Discord webhook (most common homelab destination):
Get the webhook URL from Discord: Server Settings → Integrations → Webhooks → New Webhook (or via channel settings: Edit Channel → Integrations → Webhooks). Copy the URL — it looks like https://discord.com/api/webhooks/<id>/<token>.
Treat the webhook URL as a secret — do not commit it to version control. For the CRD path, store it in a Kubernetes Secret and reference it via
secureSettingsin the contact point config.
# Grafana UI: Alerting → Contact points → New contact point
# Type: Discord
# Webhook URL: https://discord.com/api/webhooks/<id>/<token>
# Message (optional custom template):
# {{ range .Alerts }}
# **{{ .Labels.alertname }}** — {{ .Annotations.summary }}
# {{ end }}Email:
Configure SMTP via environment variables (do not edit grafana.ini directly in containers — changes are lost on restart):
- Compose: set
GF_SMTP_ENABLED=true,GF_SMTP_HOST,GF_SMTP_USER,GF_SMTP_PASSWORD,GF_SMTP_FROM_ADDRESSenv vars (seereferences/crd-examples.mdCompose snippet) - k3s: set the same
GF_SMTP_*env vars in the Grafana CR'sdeployment.spec.template.spec.containers[].env
Then create an Email contact point in the UI. Store GF_SMTP_PASSWORD in a Secret, not in plain config.
Generic webhook:
# Type: Webhook
# URL: https://your-endpoint/alert
# HTTP Method: POST
# Sends Grafana's default JSON payload with alert state, labels, annotationsNotification Policies
The routing tree determines which contact point receives which alert:
Default policy → discord-webhook
└── severity=critical → discord-webhook + email
└── team=homelab → discord-webhookConfigure at Alerting → Notification policies. The default policy catches everything not matched by a child policy.
Critical first step: Before any alert can notify, set the default policy's contact point. Go to Alerting → Notification policies, click
...on the default policy → Edit, and set Contact point to your Discord webhook. Without this, fired alerts go nowhere — the built-in default routes to email which requires SMTP.
Dashboard Design Patterns
Overview → Drilldown
Top-level dashboard shows aggregate health across all services. Use a $service variable and a stat panel per service showing up status. Link each stat panel to a per-service detail dashboard passing $service as a URL parameter.
{
"type": "stat",
"title": "$service status",
"links": [
{
"title": "Drilldown",
"url": "/d/service-detail?var-service=${service}"
}
]
}Row Organization
Group panels by concern using row panels:
- System Health — CPU, memory, disk for the host
- Services — per-service up/down, request rates
- Logs — Loki log panels filtered by
$service
Collapse rows by default (collapsed: true) to keep the dashboard scannable.
Consistent Variable Usage
Every panel in a dashboard should use the same variables. If $container is defined, every Prometheus query should include {container="$container"} and every Loki query should include {container="$container"}. Panels that don't respect the variable create confusing mismatches when the user switches the dropdown.
References
references/crd-examples.md— Full GrafanaDashboard and GrafanaDatasource YAML, GrafanaAlertRuleGroup CRD, homelab service health dashboard JSON
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.

