Create, modify, validate, publish, and visually review Grafana dashboards. Use when building dashboards, editing panels/variables/links, finding dashboard examples, using gcx, or taking Playwright screenshots of Grafana dashboards.
72
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Build Grafana dashboards as diagnostic tools, not metric inventories. Use gcx for API/resource work and Python Playwright for UI screenshots.
There are two independent auth layers:
A gcx context can be online but still fail writes with 403. A browser profile can be logged out even when gcx works.
Classify API failures:
gcx config check fails, token expired, login requiredBefore saving/updating:
gcx config current-context
gcx config check
gcx config list-contextsTry an explicitly appropriate context if available. Report the context used.
context → symptom → culprit/entity → subsystem path → resources/efficiency.gcx.Local repo examples are optional and only allowed when project instructions permit broad scans:
find . -iname '*dashboard*' -o -iname '*grafana*' | head -100
rg -n 'gridPos|templating|panels|dashboard|grafana-foundation-sdk' .Live Grafana examples are often better for datasource variables and folder conventions:
gcx dashboards search '<keyword>' -o wide
gcx dashboards get <uid> -o jsonFallback when gcx dashboards resource API/RBAC fails:
gcx api '/api/search?query=<keyword>' -o json
gcx api /api/dashboards/uid/<uid> -o jsonExtract useful patterns:
jq -r '.. | objects | select(.expr?) | .expr' dashboard.json | sort -u
jq '.dashboard.templating.list[]? | {name,type,query,current}' dashboard.json
jq '.dashboard.panels[]? | {id,title,type,gridPos}' dashboard.jsonIf multiple Prometheus/Loki/Tempo datasources exist, infer from existing dashboards in the same folder/team. If still ambiguous, ask one concise datasource question.
Examples:
gcx metrics query 'up' -o json
gcx datasources prometheus query -d <prom_uid> 'count by (__name__) ({__name__=~".*query.*"})' --since 5m -o json
gcx datasources loki query -d <loki_uid> '{namespace="example"} | logfmt' --since 1h -o raw
gcx traces labels -d <tempo_uid> -o jsonCheck metric existence, labels, units, histogram buckets, status/route/op labels, and parsed log fields.
Rows should tell a story. Keep only the triage row open unless the dashboard is explicitly a drilldown.
Common row flow:
Triage + context
User outcome
Tenant/entity evidence
Frontend/gateway scheduling
Worker/backend execution
Storage/cache path
Resource pressure
Efficiency / before-after tuningEach row should have a decision-gate description.
Row JSON example:
{
"id": 10,
"type": "row",
"title": "Query-frontend → queriers: scheduling",
"description": "Move here when latency rises with queueing or throttles. Check batch weight, connected clients, and frontend cache health.",
"collapsed": true,
"gridPos": {"x": 0, "y": 12, "w": 24, "h": 1},
"panels": []
}Panel conventions:
topk() for high-cardinality tenants/podsFetch:
gcx api /api/dashboards/uid/<uid> -o json > /tmp/dashboard.jsonPush payload shape:
{"dashboard": {...}, "folderUid": "<folderUid>", "message": "Explain change", "overwrite": true}Push:
gcx api /api/dashboards/db -d @/tmp/payload.json -o jsonNo dry-run exists for this endpoint. Fetch back and verify:
gcx api /api/dashboards/uid/<uid> -o json \
| jq '{uid:.dashboard.uid,title:.dashboard.title,version:.dashboard.version,folder:.meta.folderUid,panels:(.dashboard.panels|length),vars:[.dashboard.templating.list[]?.name]}'For resource-managed dashboards prefer:
gcx resources pull dashboards/<uid> -p ./resources
gcx resources validate -p ./resources
gcx resources push -p ./resources --dry-run
gcx resources push -p ./resourcesUse absolute dashboard paths for internal links to avoid app-relative redirects:
/d/<uid>/<slug>?${__url_time_range}&${varname:queryparam}&var-tenant=${__field.labels.tenant}For trace links, provide both exact trace and log-correlation fallback:
{cluster=~"$cluster", namespace=~"$namespace"} |= "$traceID"Long table-row URLs can be brittle. Provide a manual fallback in panel descriptions/prompts.
Install once per machine:
python3 -m venv ~/.cache/grafana-dashboard-screenshot/venv
~/.cache/grafana-dashboard-screenshot/venv/bin/python -m pip install --upgrade pip
~/.cache/grafana-dashboard-screenshot/venv/bin/python -m pip install -r /path/to/skill/requirements.txt
~/.cache/grafana-dashboard-screenshot/venv/bin/python -m playwright install chromiumHelper:
scripts/grafana_dashboard_screenshot.pyList profiles before declaring browser auth missing:
~/.cache/grafana-dashboard-screenshot/venv/bin/python /path/to/skill/scripts/grafana_dashboard_screenshot.py profiles
ls -1 ~/.cache/grafana-dashboard-screenshot/ 2>/dev/null || trueIf a host-matching profile exists, retry capture with --profile-name or --profile-dir.
Start a non-blocking headed login browser:
~/.cache/grafana-dashboard-screenshot/venv/bin/python /path/to/skill/scripts/grafana_dashboard_screenshot.py login-start \
--url 'https://grafana.example.com' \
--profile-name grafana-exampleTell the user exactly:
Log in in the opened browser, then say continue.When the user says continue:
~/.cache/grafana-dashboard-screenshot/venv/bin/python /path/to/skill/scripts/grafana_dashboard_screenshot.py login-finish \
--url 'https://grafana.example.com' \
--profile-name grafana-exampleBlocking human mode also exists: login.
~/.cache/grafana-dashboard-screenshot/venv/bin/python /path/to/skill/scripts/grafana_dashboard_screenshot.py capture \
--url 'https://grafana.example.com/d/<uid>/<slug>?from=now-1h&to=now' \
--profile-name grafana-example \
--output './screenshots/dashboard.png' \
--viewport 1800x1400 \
--wait-ms 8000Useful options:
--profile-dir <path>
--selector 'body'
--full-page / --no-full-page
--headed
--wait-for-text '<dashboard title>'
--allow-login-pageFor layout review, use a wide viewport. If the left nav wastes space, use a larger viewport, collapse nav in the profile, or use kiosk/embedded/solo-style URL options when appropriate.
Review checklist:
Include:
144f0eb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.