build-grafana-dashboards

Create production-ready Grafana dashboards with reusable panels, template variables, annotations, and provisioning for version-controlled dashboard deployment. Use when creating visual representations of Prometheus, Loki, or other data source metrics, building operational dashboards for SRE teams, migrating from manual dashboard creation to version-controlled provisioning, or establishing executive-level SLO compliance reporting.

9 stars

Best use case

build-grafana-dashboards is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Create production-ready Grafana dashboards with reusable panels, template variables, annotations, and provisioning for version-controlled dashboard deployment. Use when creating visual representations of Prometheus, Loki, or other data source metrics, building operational dashboards for SRE teams, migrating from manual dashboard creation to version-controlled provisioning, or establishing executive-level SLO compliance reporting.

Teams using build-grafana-dashboards should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/build-grafana-dashboards/SKILL.md --create-dirs "https://raw.githubusercontent.com/pjt222/agent-almanac/main/i18n/caveman-lite/skills/build-grafana-dashboards/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/build-grafana-dashboards/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How build-grafana-dashboards Compares

Feature / Agentbuild-grafana-dashboardsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Create production-ready Grafana dashboards with reusable panels, template variables, annotations, and provisioning for version-controlled dashboard deployment. Use when creating visual representations of Prometheus, Loki, or other data source metrics, building operational dashboards for SRE teams, migrating from manual dashboard creation to version-controlled provisioning, or establishing executive-level SLO compliance reporting.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Build Grafana Dashboards

Design and deploy Grafana dashboards with best practices for maintainability, reusability, and version control.

## When to Use

- Creating visual representations of Prometheus, Loki, or other data source metrics
- Building operational dashboards for SRE teams and incident responders
- Establishing executive-level reporting dashboards for SLO compliance
- Migrating dashboards from manual creation to version-controlled provisioning
- Standardizing dashboard layouts across teams with template variables
- Creating drill-down experiences from high-level overviews to detailed metrics

## Inputs

- **Required**: Data source configuration (Prometheus, Loki, Tempo, etc.)
- **Required**: Metrics or logs to visualize with their query patterns
- **Optional**: Template variables for multi-service or multi-environment views
- **Optional**: Existing dashboard JSON for migration or modification
- **Optional**: Annotation queries for event correlation (deployments, incidents)

## Procedure

> See [Extended Examples](references/EXAMPLES.md) for complete configuration files and templates.


### Step 1: Design Dashboard Structure

Plan dashboard layout and organization before building panels.

Create a dashboard specification document:

```markdown
# Service Overview Dashboard

## Purpose
Real-time operational view for on-call engineers monitoring the API service.

## Rows
1. High-Level Metrics (collapsed by default)
   - Request rate, error rate, latency (RED metrics)
   - Service uptime, instance count
2. Detailed Metrics (expanded by default)
   - Per-endpoint latency breakdown
   - Error rate by status code
   - Database connection pool status
3. Resource Utilization
   - CPU, memory, disk usage per instance
   - Network I/O rates
4. Logs (collapsed by default)
   - Recent errors from Loki
   - Alert firing history

## Variables
- `environment`: production, staging, development
- `instance`: all instances or specific instance selection
- `interval`: aggregation window (5m, 15m, 1h)

## Annotations
- Deployment events from CI/CD system
- Alert firing/resolving events
```

Key design principles:
- **Most important metrics first**: Critical metrics at the top, details below
- **Consistent time ranges**: Synchronize time across all panels
- **Drill-down paths**: Link from high-level to detailed dashboards
- **Responsive layout**: Use rows and panel widths that work on various screens

**Got:** Clear dashboard structure documented, stakeholders aligned on metrics and layout priorities.

**If fail:**
- Conduct dashboard design review with end users (SREs, developers)
- Benchmark against industry standards (USE method, RED method, Four Golden Signals)
- Review existing dashboards in team for consistency patterns

### Step 2: Create Dashboard with Template Variables

Build the dashboard foundation with reusable variables for filtering.

Create dashboard JSON structure (or use UI, then export):

```json
{
  "dashboard": {
    "title": "API Service Overview",
    "uid": "api-service-overview",
    "version": 1,
    "timezone": "browser",
    "editable": true,
    "graphTooltip": 1,
    "time": {
      "from": "now-6h",
      "to": "now"
    },
    "refresh": "30s",
    "templating": {
      "list": [
        {
          "name": "environment",
          "type": "query",
          "datasource": "Prometheus",
          "query": "label_values(up{job=\"api-service\"}, environment)",
          "multi": false,
          "includeAll": false,
          "refresh": 1,
          "sort": 1,
          "current": {
            "selected": false,
            "text": "production",
            "value": "production"
          }
        },
        {
          "name": "instance",
          "type": "query",
          "datasource": "Prometheus",
          "query": "label_values(up{job=\"api-service\",environment=\"$environment\"}, instance)",
          "multi": true,
          "includeAll": true,
          "refresh": 1,
          "allValue": ".*",
          "current": {
            "selected": true,
            "text": "All",
            "value": "$__all"
          }
        },
        {
          "name": "interval",
          "type": "interval",
          "options": [
            {"text": "1m", "value": "1m"},
            {"text": "5m", "value": "5m"},
            {"text": "15m", "value": "15m"},
            {"text": "1h", "value": "1h"}
          ],
          "current": {
            "text": "5m",
            "value": "5m"
          },
          "auto": false
        }
      ]
    },
    "annotations": {
      "list": [
        {
          "name": "Deployments",
          "datasource": "Prometheus",
          "enable": true,
          "expr": "changes(app_version{job=\"api-service\",environment=\"$environment\"}[5m]) > 0",
          "step": "60s",
          "iconColor": "rgba(0, 211, 255, 1)",
          "tagKeys": "version"
        }
      ]
    }
  }
}
```

Variable types and use cases:
- **Query variables**: Dynamic lists from data source (`label_values()`, `query_result()`)
- **Interval variables**: Aggregation windows for queries
- **Custom variables**: Static lists for non-metric selections
- **Constant variables**: Shared values across panels (data source names, thresholds)
- **Text box variables**: Free-form input for filtering

**Got:** Variables populate correctly from data source, cascading filters work (environment filters instances), default selections appropriate.

**If fail:**
- Test variable queries independently in Prometheus UI
- Check for circular dependencies (variable A depends on B depends on A)
- Verify regex patterns in `allValue` field for multi-select variables
- Review variable refresh settings (on dashboard load vs on time range change)

### Step 3: Build Visualization Panels

Create panels for each metric with appropriate visualization types.

**Time series panel** (request rate):

```json
{
  "type": "timeseries",
  "title": "Request Rate",
  "gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
  "targets": [
    {
      "expr": "sum(rate(http_requests_total{job=\"api-service\",environment=\"$environment\",instance=~\"$instance\"}[$interval])) by (method)",
      "legendFormat": "{{method}}",
      "refId": "A"
    }
  ],
  "fieldConfig": {
    "defaults": {
      "unit": "reqps",
      "color": {
        "mode": "palette-classic"
      },
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "smooth",
        "fillOpacity": 10,
        "spanNulls": true
      },
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {"value": null, "color": "green"},
          {"value": 1000, "color": "yellow"},
          {"value": 5000, "color": "red"}
        ]
      }
    }
  },
  "options": {
    "tooltip": {
      "mode": "multi",
      "sort": "desc"
    },
    "legend": {
      "displayMode": "table",
      "placement": "right",
      "calcs": ["mean", "max", "last"]
    }
  }
}
```

**Stat panel** (error rate):

```json
{
  "type": "stat",
  "title": "Error Rate",
  "gridPos": {"h": 4, "w": 6, "x": 12, "y": 0},
  "targets": [
    {
# ... (see EXAMPLES.md for complete configuration)
```

**Heatmap panel** (latency distribution):

```json
{
  "type": "heatmap",
  "title": "Request Duration Heatmap",
  "gridPos": {"h": 8, "w": 12, "x": 0, "y": 8},
  "targets": [
    {
# ... (see EXAMPLES.md for complete configuration)
```

Panel selection guide:
- **Time series**: Trends over time (rates, counts, durations)
- **Stat**: Single current value with threshold coloring
- **Gauge**: Percentage values (CPU, memory, disk usage)
- **Bar gauge**: Comparing multiple values at a point in time
- **Heatmap**: Distribution of values over time (latency percentiles)
- **Table**: Detailed breakdown of multiple metrics
- **Logs**: Raw log lines from Loki with filtering

**Got:** Panels render correctly with data, visualizations match intended metric types, legends descriptive, thresholds highlight problems.

**If fail:**
- Test queries in Explore view with same time range and variables
- Check for metric name typos or incorrect label filters
- Verify aggregation functions match metric type (rate for counters, avg for gauges)
- Review unit configurations (bytes, seconds, requests per second)
- Enable "Show query inspector" to debug empty results

### Step 4: Configure Rows and Layout

Organize panels into collapsible rows for logical grouping.

```json
{
  "panels": [
    {
      "type": "row",
      "title": "High-Level Metrics",
      "collapsed": false,
# ... (see EXAMPLES.md for complete configuration)
```

Layout best practices:
- Grid is 24 units wide, each panel specifies `w` (width) and `h` (height)
- Use rows to group related panels, collapse less critical sections by default
- Place most critical metrics in first visible area (y=0-8)
- Maintain consistent panel heights within rows (typically 4, 8, or 12 units)
- Use full width (24) for time series, half width (12) for comparisons

**Got:** Dashboard layout organized logically, rows collapse/expand correctly, panels align visually without gaps.

**If fail:**
- Validate gridPos coordinates don't overlap
- Check that row panels array contains panels (not null)
- Verify y-coordinates increment logically down the page
- Use Grafana UI "Edit JSON" to inspect grid positions

### Step 5: Add Links and Drill-Downs

Create navigation paths between related dashboards.

Dashboard-level links in JSON:

```json
{
  "links": [
    {
      "title": "Service Details",
      "type": "link",
      "icon": "external link",
# ... (see EXAMPLES.md for complete configuration)
```

Panel-level data links:

```json
{
  "fieldConfig": {
    "defaults": {
      "links": [
        {
          "title": "View Logs for ${__field.labels.instance}",
# ... (see EXAMPLES.md for complete configuration)
```

Link variables:
- `$service`, `$environment`: Dashboard template variables
- `${__field.labels.instance}`: Label value from clicked data point
- `${__from}`, `${__to}`: Current dashboard time range
- `$__url_time_range`: Encoded time range for URL

**Got:** Clicking panel elements or dashboard links navigates to related views with context preserved (time range, variables).

**If fail:**
- URL encode special characters in query parameters
- Test links with various variable selections (All vs specific value)
- Verify target dashboard UIDs exist and are accessible
- Check that `includeVars` and `keepTime` flags work as expected

### Step 6: Set Up Dashboard Provisioning

Version control dashboards as code for reproducible deployments.

Create provisioning directory structure:

```bash
mkdir -p /etc/grafana/provisioning/{dashboards,datasources}
```

Datasource provisioning (`/etc/grafana/provisioning/datasources/prometheus.yml`):

```yaml
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
# ... (see EXAMPLES.md for complete configuration)
```

Dashboard provisioning (`/etc/grafana/provisioning/dashboards/default.yml`):

```yaml
apiVersion: 1

providers:
  - name: 'default'
    orgId: 1
    folder: 'Services'
    type: file
    disableDeletion: false
    updateIntervalSeconds: 30
    allowUiUpdates: true
    options:
      path: /var/lib/grafana/dashboards
      foldersFromFilesStructure: true
```

Store dashboard JSON files in `/var/lib/grafana/dashboards/`:

```bash
/var/lib/grafana/dashboards/
├── api-service/
│   ├── overview.json
│   └── details.json
├── database/
│   └── postgres.json
└── infrastructure/
    ├── nodes.json
    └── kubernetes.json
```

Using Docker Compose:

```yaml
version: '3.8'
services:
  grafana:
    image: grafana/grafana:10.2.0
    ports:
      - "3000:3000"
    volumes:
      - ./grafana/provisioning:/etc/grafana/provisioning
      - ./grafana/dashboards:/var/lib/grafana/dashboards
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
```

**Got:** Dashboards automatically loaded on Grafana startup, changes to JSON files reflected after update interval, version control tracks dashboard changes.

**If fail:**
- Check Grafana logs: `docker logs grafana | grep -i provisioning`
- Verify JSON syntax: `python -m json.tool dashboard.json`
- Ensure file permissions allow Grafana to read: `chmod 644 *.json`
- Test with `allowUiUpdates: false` to prevent UI modifications
- Validate provisioning config: `curl http://localhost:3000/api/admin/provisioning/dashboards/reload -X POST -H "Authorization: Bearer $GRAFANA_API_KEY"`

## Validation

- [ ] Dashboard loads without errors in Grafana UI
- [ ] All template variables populate with expected values
- [ ] Variable cascading works (selecting environment filters instances)
- [ ] Panels display data for configured time ranges
- [ ] Panel queries use variables correctly (no hardcoded values)
- [ ] Thresholds highlight problem states appropriately
- [ ] Legend formatting descriptive and not cluttered
- [ ] Annotations appear for relevant events
- [ ] Links navigate to correct dashboards with context preserved
- [ ] Dashboard provisioned from JSON file (version controlled)
- [ ] Responsive layout works on different screen sizes
- [ ] Tooltip and hover interactions provide useful context

## Pitfalls

- **Variable not updating panels**: Ensure queries use `$variable` syntax, not hardcoded values. Check variable refresh settings.
- **Empty panels with correct query**: Verify time range includes data points. Check scrape interval vs aggregation window (5m rate needs >5m of data).
- **Legend too verbose**: Use `legendFormat` to show only relevant labels, not full metric name. Example: `{{method}} - {{status}}` instead of default.
- **Inconsistent time ranges**: Set dashboard time sync so all panels share the same time window. Use "Sync cursor" for correlated investigation.
- **Performance issues**: Avoid queries returning high cardinality series (>1000). Use recording rules or pre-aggregation. Limit time ranges for expensive queries.
- **Dashboard drift**: Without provisioning, manual UI changes create version control conflicts. Use `allowUiUpdates: false` in production.
- **Missing data links**: Data links require exact label names. Use `${__field.labels.labelname}` carefully, verify label exists in query result.
- **Annotation overload**: Too many annotations clutter the view. Filter annotations by importance or use separate annotation tracks.

## Related Skills

- `setup-prometheus-monitoring` - Configure Prometheus data sources that feed Grafana dashboards
- `configure-log-aggregation` - Set up Loki for log panel queries and log-based annotations
- `define-slo-sli-sla` - Visualize SLO compliance and error budgets with Grafana stat and gauge panels
- `instrument-distributed-tracing` - Add trace ID links from metrics panels to Tempo trace views

Related Skills

optimize-docker-build-cache

9
from pjt222/agent-almanac

Optimize Docker build times using layer caching, multi-stage builds, BuildKit features, and dependency-first copy patterns. Applicable to R, Node.js, and Python projects. Use when Docker builds are slow due to repeated package installations, when rebuilds reinstall all dependencies on every code change, when image sizes are unnecessarily large, or when CI/CD pipeline builds are a bottleneck.

build-tcg-deck

9
from pjt222/agent-almanac

Build a competitive or casual trading card game deck. Covers archetype selection, mana/energy curve analysis, win condition identification, meta-game positioning, and sideboard construction for Pokemon TCG, Magic: The Gathering, Flesh and Blood, and other TCGs. Use when building a new deck for a tournament format or casual play, adapting an existing deck to a changed meta-game, evaluating whether a new set warrants a deck change, or converting a deck concept into a tournament-ready list.

build-shiny-module

9
from pjt222/agent-almanac

Build reusable Shiny modules with proper namespace isolation using NS(). Covers module UI/server pairs, reactive return values, inter-module communication, and nested module composition. Use when extracting a reusable component from a growing Shiny app, building a UI widget used in multiple places, encapsulating complex reactive logic behind a clean interface, or composing larger applications from smaller, testable units.

build-sequential-circuit

9
from pjt222/agent-almanac

Build sequential (stateful) logic circuits including latches, flip-flops, registers, counters, and finite state machines. Covers SR latch, D and JK flip-flops, binary/BCD/ring counters, and Mealy/Moore FSM design with clock signal and timing analysis. Use when a circuit must remember past inputs, count events, or implement a state-dependent control sequence.

build-pkgdown-site

9
from pjt222/agent-almanac

Build and deploy a pkgdown documentation site for an R package to GitHub Pages. Covers _pkgdown.yml configuration, theming, article organization, reference index customization, and deployment methods. Use when creating a documentation site for a new or existing package, customizing layout or navigation, fixing 404 errors on a deployed site, or migrating between branch-based and GitHub Actions deployment methods.

build-parameterized-report

9
from pjt222/agent-almanac

Create parameterized Quarto or R Markdown reports that can be rendered with different inputs to generate multiple variations. Covers parameter definitions, programmatic rendering, and batch generation. Use when generating the same report for different departments, regions, or time periods; creating client-specific reports from a single template; building dashboards that filter to specific subsets; or automating recurring reports with varying inputs.

build-feature-store

9
from pjt222/agent-almanac

Build a feature store using Feast for centralized feature management, configure offline and online stores for batch and real-time serving, define feature views with transformations, and implement point-in-time correct joins for ML pipelines. Use when managing features for multiple ML models, ensuring training-serving consistency, serving low-latency features for real-time inference, reusing feature definitions across projects, or building a feature catalog for discovery and governance.

build-custom-mcp-server

9
from pjt222/agent-almanac

Build a custom MCP (Model Context Protocol) server that exposes domain-specific tools to AI assistants. Covers server implementation in Node.js or R, tool definitions, transport configuration, and testing with Claude Code. Use when you need to expose custom functionality beyond what mcptools provides, when building specialized domain-specific AI integrations, or when wrapping existing APIs or services as MCP tools.

build-consensus

9
from pjt222/agent-almanac

Achieve distributed agreement without central authority using bee democracy, threshold voting, and quorum sensing. Covers proposal generation, advocacy dynamics, commitment thresholds, deadlock resolution, and consensus quality assessment. Use when a group must decide between options without a designated leader, when centralized decision-making is a bottleneck, when stakeholders have different perspectives to integrate, or when designing automated systems that must reach consensus such as distributed databases or multi-agent AI.

build-coherence

9
from pjt222/agent-almanac

AI multi-path reasoning coherence using bee democracy — independent evaluation of competing approaches, waggle dance as reasoning-out-loud, quorum sensing for confidence thresholds, and deadlock resolution. Use when forage-solutions has identified multiple valid approaches and a selection must be made, when oscillating between options without committing, when justifying an architecture or tool choice with structured reasoning, or before an irreversible action where the cost of the wrong choice is high.

build-cli-plugin

9
from pjt222/agent-almanac

Build a plugin or adapter for a CLI tool using the abstract base class pattern. Covers defining the contract (static fields, required methods), choosing an installation strategy (symlink, copy, append-to-file), implementing detection, install/uninstall with idempotency, listing, auditing, and registering the plugin. Use when adding support for a new framework to a CLI installer, building a plugin system for any multi-target tool, or extending an existing adapter architecture.

build-ci-cd-pipeline

9
from pjt222/agent-almanac

Design and implement multi-stage CI/CD pipelines using GitHub Actions with matrix builds, dependency caching, artifact management, and secret handling. Create workflows that span linting, testing, building, and deployment stages with parallel execution and conditional logic. Use when setting up automated testing and deployment for a new project, migrating from Jenkins or CircleCI to GitHub Actions, implementing matrix builds across platforms, adding build caching, or creating multi-stage pipelines with security scanning and quality gates.