Source profileQuality 94/100Review permissions

tenequm/skills/skills/grafana-foundation-sdk/SKILL.md

grafana-foundation-sdk

Build Grafana dashboards as code with the grafana-foundation-sdk typed builders (TypeScript or Go). Use when creating, modifying, or generating Grafana dashboard JSON programmatically, converting hand-written dashboard JSON to typed code, building monitoring dashboards, or working with Prometheus/Loki queries in dashboards.

Source repository stars
35
Declared platforms
0
Static risk flags
3
Last source update
2026-08-24
Source checked
2026-08-25

Decision brief

What it does: where it fits

The grafana-foundation-sdk provides strongly typed builder libraries for defining Grafana dashboards as code. Instead of writing raw JSON (which is error-prone and hard to review in diffs), you compose dashboards using chained builder calls that produce valid Grafana JSON.

Best for

  • Creating new Grafana dashboards from scratch
  • Converting existing hand-written dashboard JSON to typed code
  • Adding panels, variables, or queries to dashboards

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/tenequm/skills --skill "skills/grafana-foundation-sdk"
Safe inspection promptEditorial

Inspect the Agent Skill "grafana-foundation-sdk" from https://github.com/tenequm/skills/blob/9b9fb5a29c103ed207dc255d753939e4e2ed29f5/skills/grafana-foundation-sdk/SKILL.md at commit 9b9fb5a29c103ed207dc255d753939e4e2ed29f5. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    Quick Start - TypeScript

    Review the “Quick Start - TypeScript” section in the pinned source before continuing.

    Review and apply the “Quick Start - TypeScript” source section.
  2. 02

    When to use this skill

    Creating new Grafana dashboards from scratch

    Creating new Grafana dashboards from scratchConverting existing hand-written dashboard JSON to typed codeAdding panels, variables, or queries to dashboards
  3. 03

    Installation

    The SDK is published as concrete v0.0.x tags (latest: v0.0.16). Pin explicitly - it is pre-1.0 and the API churns between releases (see Known Gotchas).

    The SDK is published as concrete v0.0.x tags (latest: v0.0.16). Pin explicitly - it is pre-1.0 and the API churns between releases (see Known Gotchas).TypeScript: bash npm install '@grafana/[email protected]'
  4. 04

    or

    const dashboard = new DashboardBuilder('My Service Overview') .uid('my-service-overview') .tags(['my-service']) .editable() .refresh('30s') .time({ from: 'now-24h', to: 'now' }) .timezone('browser') .withVariable( new QueryVariableBuilder('service') .label('Service') .query('lab…

    SDK is v0.0.x (public preview) - Used by Grafana Labs in production but the API can change between releases. Pin your version explicitly. Best suited for Grafana = 12, works with = 10.instant() and range() are mutually exclusive in Prometheus - Calling .instant() sets instant=true AND range=false. Calling .range() does the opposite. Use .rangeAndInstant() if you need both.Loki range()/instant() are deprecated - Use .queryType('range') or .queryType('instant') instead. Similarly, .resolution() is deprecated in favor of .step().
  5. 05

    Core Architecture

    Everything follows the builder pattern: create a builder, chain configuration methods, call .build() (TS) or .Build() (Go) to produce the final object. The output is standard Grafana dashboard JSON - compatible with Grafana's API, file-based provisioning, and Kubernetes ConfigMa…

    Everything follows the builder pattern: create a builder, chain configuration methods, call .build() (TS) or .Build() (Go) to produce the final object. The output is standard Grafana dashboard JSON - compatible with Gra…Each panel type, query type, and variable type lives in its own package. You import only what you need:

Permission review

Static risk signals and limitations

Runs scripts

medium · line 22

The documentation asks the agent to run terminal commands or scripts.

npm install '@grafana/grafana-foundation-sdk@~0.0.16'

Runs scripts

medium · line 24

The documentation asks the agent to run terminal commands or scripts.

pnpm add '@grafana/grafana-foundation-sdk@~0.0.16'

Writes files

medium · line 282

The documentation asks the agent to create, modify, or delete local files.

fs.writeFileSync('dashboard.json', JSON.stringify(dashboard, null, 2));

Reads files

low · line 296

The documentation asks the agent to read local files, directories, or repositories.

These are sharp edges discovered from real usage and open issues on the SDK repo:

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score94/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars35SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
tenequm/skills
Skill path
skills/grafana-foundation-sdk/SKILL.md
Commit
9b9fb5a29c103ed207dc255d753939e4e2ed29f5
License
MIT
Collected
2026-08-25
Default branch
main
View the original SKILL.md

Grafana Foundation SDK

The grafana-foundation-sdk provides strongly typed builder libraries for defining Grafana dashboards as code. Instead of writing raw JSON (which is error-prone and hard to review in diffs), you compose dashboards using chained builder calls that produce valid Grafana JSON.

The SDK is auto-generated from Grafana's internal CUE schemas via the cog tool. It supports Go, TypeScript, Python, PHP, and Java. This skill focuses on TypeScript (primary) and Go (secondary) since those are the most common choices for infrastructure teams.

When to use this skill

  • Creating new Grafana dashboards from scratch
  • Converting existing hand-written dashboard JSON to typed code
  • Adding panels, variables, or queries to dashboards
  • Building reusable dashboard components (helper functions for common panel patterns)
  • Generating dashboards dynamically based on service lists or configs

Installation

The SDK is published as concrete v0.0.x tags (latest: v0.0.16). Pin explicitly - it is pre-1.0 and the API churns between releases (see Known Gotchas).

TypeScript:

npm install '@grafana/grafana-foundation-sdk@~0.0.16'
# or
pnpm add '@grafana/grafana-foundation-sdk@~0.0.16'

Go:

go get github.com/grafana/grafana-foundation-sdk/[email protected]

Core Architecture

Everything follows the builder pattern: create a builder, chain configuration methods, call .build() (TS) or .Build() (Go) to produce the final object. The output is standard Grafana dashboard JSON - compatible with Grafana's API, file-based provisioning, and Kubernetes ConfigMaps.

Each panel type, query type, and variable type lives in its own package. You import only what you need:

// Each concern has its own import
import { DashboardBuilder, RowBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
import { PanelBuilder as TimeseriesBuilder } from '@grafana/grafana-foundation-sdk/timeseries';
import { PanelBuilder as StatBuilder } from '@grafana/grafana-foundation-sdk/stat';
import { DataqueryBuilder as PromQueryBuilder } from '@grafana/grafana-foundation-sdk/prometheus';
import { DataqueryBuilder as LokiQueryBuilder } from '@grafana/grafana-foundation-sdk/loki';

Quick Start - TypeScript

import { DashboardBuilder, RowBuilder, QueryVariableBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
import { PanelBuilder as StatBuilder } from '@grafana/grafana-foundation-sdk/stat';
import { PanelBuilder as TimeseriesBuilder } from '@grafana/grafana-foundation-sdk/timeseries';
import { DataqueryBuilder } from '@grafana/grafana-foundation-sdk/prometheus';
import * as common from '@grafana/grafana-foundation-sdk/common';

const dashboard = new DashboardBuilder('My Service Overview')
  .uid('my-service-overview')
  .tags(['my-service'])
  .editable()
  .refresh('30s')
  .time({ from: 'now-24h', to: 'now' })
  .timezone('browser')
  .withVariable(
    new QueryVariableBuilder('service')
      .label('Service')
      .query('label_values(up{namespace="default"}, job)')
      .datasource({ type: 'prometheus', uid: 'prometheus' })
      .refresh(1)
      .includeAll(true)
      .allValue('.*')
      .sort(1)
  )
  .withRow(new RowBuilder('Overview'))
  .withPanel(
    new StatBuilder()
      .title('Request Rate')
      .datasource({ type: 'prometheus', uid: 'prometheus' })
      .withTarget(
        new DataqueryBuilder()
          .expr('sum(rate(http_requests_total{job=~"$service"}[5m]))')
          .legendFormat('req/s')
      )
      .unit('reqps')
      .decimals(1)
      .height(4)
      .span(6)
      .colorMode(common.BigValueColorMode.Background)
      .graphMode(common.BigValueGraphMode.Area)
      .reduceOptions(
        new common.ReduceDataOptionsBuilder().calcs(['lastNotNull'])
      )
  )
  .withPanel(
    new TimeseriesBuilder()
      .title('Request Rate Over Time')
      .datasource({ type: 'prometheus', uid: 'prometheus' })
      .withTarget(
        new DataqueryBuilder()
          .expr('sum by (job)(rate(http_requests_total{job=~"$service"}[5m]))')
          .legendFormat('{{job}}')
      )
      .unit('reqps')
      .fillOpacity(15)
      .height(8)
      .span(12)
  );

// Output the dashboard JSON
console.log(JSON.stringify(dashboard.build(), null, 2));

Key Patterns

1. Helper functions for repeated panel configurations

The biggest win from using the SDK is creating reusable helpers that encode your team's conventions:

function promDs() {
  return { type: 'prometheus', uid: 'prometheus' } as const;
}

function lokiDs() {
  return { type: 'loki', uid: 'loki' } as const;
}

function promQuery(expr: string, legend?: string) {
  const q = new DataqueryBuilder().expr(expr);
  if (legend) q.legendFormat(legend);
  return q;
}

function statPanel(title: string, expr: string, opts?: { unit?: string; decimals?: number; color?: string }) {
  const panel = new StatBuilder()
    .title(title)
    .datasource(promDs())
    .withTarget(promQuery(expr))
    .height(4)
    .span(4)
    .colorMode(common.BigValueColorMode.Background)
    .graphMode(common.BigValueGraphMode.Area)
    .reduceOptions(new common.ReduceDataOptionsBuilder().calcs(['lastNotNull']));

  if (opts?.unit) panel.unit(opts.unit);
  if (opts?.decimals !== undefined) panel.decimals(opts.decimals);
  // Thresholds can be set via .thresholds() if needed

  return panel;
}

2. Template variables

// Query variable - populated from Prometheus labels
new QueryVariableBuilder('service')
  .label('Service')
  .query('label_values(http_server_duration_count{namespace="myapp"}, job)')
  .datasource({ type: 'prometheus', uid: 'prometheus' })
  .refresh(2)  // 1=on dashboard load, 2=on time range change
  .includeAll(true)
  .allValue('.*')
  .sort(1)  // 1=alphabetical asc

// Custom variable - static key:value pairs
new CustomVariableBuilder('level')
  .label('Log Level')
  .query('All : .+, Error : error|fatal, Warning : warn, Info : info, Debug : debug')
  .current({ text: 'All', value: '.+' })

Reference variables in queries with standard Grafana syntax: $service, $__range, $__rate_interval, $__auto.

3. Panel sizing

Panels use height(h) (grid rows) and span(w) (out of 24 columns):

  • Full width: .span(24)
  • Half width: .span(12)
  • Third width: .span(8)
  • Quarter width: .span(6)
  • Typical stat panel: .height(4).span(4)
  • Typical timeseries: .height(8).span(12)

4. Thresholds

import { ThresholdsConfigBuilder } from '@grafana/grafana-foundation-sdk/dashboard';

// First step must have no value (it's the base)
new StatBuilder()
  .thresholds(
    new ThresholdsConfigBuilder()
      .mode(common.ThresholdsMode.Absolute)
      .steps([
        { value: null as any, color: 'green' },
        { value: 80, color: 'yellow' },
        { value: 95, color: 'red' },
      ])
  )

5. Field overrides

new TimeseriesBuilder()
  .overrideByName('Revenue', [
    { id: 'color', value: { fixedColor: 'green', mode: 'fixed' } },
  ])
  .overrideByRegexp('.*5..', [
    { id: 'color', value: { fixedColor: 'red', mode: 'fixed' } },
  ])

6. Rows (including collapsed)

// Regular row
.withRow(new RowBuilder('Traffic'))

// Collapsed row with nested panels
.withRow(
  new RowBuilder('Business Details')
    .collapsed()
    .withPanel(/* ... */)
    .withPanel(/* ... */)
)

7. Loki log and metric queries

import { DataqueryBuilder as LokiQueryBuilder } from '@grafana/grafana-foundation-sdk/loki';

// Log query
new LokiQueryBuilder()
  .expr('{namespace="myapp", app=~"$service", level=~"$level"}')
  .refId('A')

// Metric query from logs
new LokiQueryBuilder()
  .expr('sum by (buyer_wallet)(count_over_time({namespace="myapp"} | event="request" [$__range]))')
  .legendFormat('{{buyer_wallet}}')
  .refId('A')

8. Transformations

Transformations are applied as raw objects since the SDK doesn't have typed builders for all transformation types:

new TableBuilder()
  .withTransformation({
    id: 'reduce',
    options: {
      reducers: ['lastNotNull'],
      mode: 'seriesToRows',
      includeTimeField: false,
      labelsToFields: true,
    },
  })
  .withTransformation({
    id: 'organize',
    options: {
      excludeByName: { Field: true },
      renameByName: { buyer_wallet: 'Buyer Wallet', 'Last not null': 'Requests' },
    },
  })
  .withTransformation({
    id: 'sortBy',
    options: { sort: [{ field: 'Requests', desc: true }] },
  })

Generating Output

The .build() call returns a plain object matching Grafana's dashboard JSON schema. Serialize it however you need:

// Standard JSON file (for provisioning or ConfigMaps)
const fs = require('fs');
const dashboard = builder.build();
fs.writeFileSync('dashboard.json', JSON.stringify(dashboard, null, 2));

// Kubernetes resource manifest (for Grafana's k8s API)
const manifest = {
  apiVersion: 'dashboard.grafana.app/v1beta1',
  kind: 'Dashboard',
  metadata: { name: dashboard.uid },
  spec: dashboard,
};
console.log(JSON.stringify(manifest, null, 2));

Known Gotchas

These are sharp edges discovered from real usage and open issues on the SDK repo:

  1. SDK is v0.0.x (public preview) - Used by Grafana Labs in production but the API can change between releases. Pin your version explicitly. Best suited for Grafana >= 12, works with >= 10.

  2. instant() and range() are mutually exclusive in Prometheus - Calling .instant() sets instant=true AND range=false. Calling .range() does the opposite. Use .rangeAndInstant() if you need both.

  3. Loki range()/instant() are deprecated - Use .queryType('range') or .queryType('instant') instead. Similarly, .resolution() is deprecated in favor of .step().

  4. First threshold step must have value: null - This is the base/default color. Omitting it produces invalid JSON.

  5. Panel IDs are auto-assigned - You don't set id on panels. Grafana assigns them at import time. Similarly, gridPos.x/y are computed from height() and span().

  6. Transformations are plain objects - The SDK has no typed builders for transformations. Pass them as raw { id, options } objects via .withTransformation().

  7. CustomVariable quirk - When provisioning via Grafana's API, CustomVariableBuilder requires the .query() field with comma-separated key:value pairs (e.g., 'All : .+, Error : error') for options to persist, even when .values() is also used.

  8. Go: cog.ToPtr() is essential - Many struct fields are pointer types. Use cog.ToPtr[T](value) for nullable fields (thresholds, datasource refs). TypeScript doesn't have this issue.

  9. Go: Build() returns error - Always check it. TypeScript's .build() returns the object directly with compile-time type safety instead.

  10. No typed query builders for plugin datasources - Only core datasources (Prometheus, Loki, Tempo, Elasticsearch, CloudWatch, etc.) have builders. For third-party plugins, define custom query types by implementing the Builder<Dataquery> interface.

  11. Dashboard schema v1 vs v2 - This skill targets the v1 dashboard (@grafana/grafana-foundation-sdk/dashboard, k8s apiVersion dashboard.grafana.app/v1beta1). A newer schema v2 ships as dashboardv2beta1 (k8s apiVersion dashboard.grafana.app/v2beta1) with its own builders. v2beta1 is still stabilizing and has known sharp edges (e.g. transforms, annotation positioning, SQL expressions in Go) - prefer v1 unless you specifically need v2 layouts. Most query/panel builders are shared; some expose a QueryV2Builder/VisualizationV2Builder variant for v2.

  12. Builders are only type-checked if wired into a tsconfig - The SDK gives compile-time safety only when the generator file is actually type-checked. A generator sitting under a non-package directory (e.g. a Helm chart dir) that no tsconfig includes is silently unchecked, so type errors surface only at .build() runtime. Also: the SDK's output targets ES2024/bundler module resolution, which an older global tsc chokes on - run the project-local compiler (npx tsc), not a stale global one.

  13. Regenerate JSON after every generator edit - The deployed dashboard is the generated JSON, not the .ts/.go source. Edit the generator, re-run it, and commit the regenerated JSON together; never hand-edit the generated JSON (the next regen silently overwrites it). A repo rule ("never edit the dashboard JSON directly") is worth adding.

Reference Files

For detailed API reference and complete examples, see:

  • references/typescript-api.md - Full TypeScript API with all panel types, query builders, and configuration options
  • references/patterns.md - Common dashboard patterns, recipes, and a complete example converting this project's dashboard to SDK code

Frequently asked questions

What to verify before installation and use

What does the grafana-foundation-sdk source document cover?

The grafana-foundation-sdk provides strongly typed builder libraries for defining Grafana dashboards as code. Instead of writing raw JSON (which is error-prone and hard to review in diffs), you compose dashboards using chained builder calls that produce valid Grafana JSON.

How do I install grafana-foundation-sdk?

The source record exposes this install command: npx skills add https://github.com/tenequm/skills --skill "skills/grafana-foundation-sdk". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged exec-script, write-files, read-files in the source; the page lists the matching lines and excerpts.

Alternatives

Compare before choosing

Computed 10045,511

coreyhaines31/marketingskills

ab-testing

When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

Computed 10029,034

garrytan/gbrain

bulk-ingestion

End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

Computed 10024,921

alirezarezvani/claude-skills

app-store-optimization

App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

Computed 1005,241

dotnet/skills

migrate-vstest-to-mtp

Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing