/datasources-provisioning
Generate a copy-paste Grafana data source provisioning file (YAML or Terraform) for any plugin from its standardized settings schema on the plugins CDN. Use when the user wants to provision or configure a data source as code — e.g. "provision infinity", "datasource yaml for
$ npx -y skills add grafana/skills --skill datasources-provisioning --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/datasources-provisioning
Context preview
The summary Claude sees to decide when to auto-load this skill.
Generate a copy-paste Grafana data source provisioning file (YAML or Terraform) for any plugin from its standardized settings schema on the plugins CDN. Use when the user wants to provision or configure a data source as code — e.g. "provision infinity", "datasource yaml for
SKILL.md
datasources-provisioning.SKILL.mdname: datasources-provisioning
license: Apache-2.0
description: Generate a copy-paste Grafana data source provisioning file (YAML or Terraform) for any plugin from its standardized settings schema on the plugins CDN. Use when the user wants to provision or configure a data source as code — e.g. "provision infinity", "datasource yaml for clickhouse", "terraform for the github datasource" — even when they only name the plugin and not the word "provisioning".
Workflow
1. Ask the starting point: from scratch, or from an existing data source?
**Ask this before anything else** (skip only if the user already made it clear):
- **From scratch** — the user names a plugin type to provision → continue with step 2.
- **From an existing data source** in a running instance → jump to [Convert an existing data source](#convert-an-existing-data-source), then return to step 6.
2. Resolve the full plugin id
Provisioning needs the canonical plugin id (`<org>-<name>-datasource`), not the short name a user might say.
- Already canonical (contains `-datasource` or `-app`)? Use as-is: `yesoreyeram-infinity-datasource`.
- Short name only (e.g. `infinity`, `clickhouse`)? Search the catalog API with `filter=<keyword>`:
curl -s "https://grafana.com/api/plugins?filter=infinity" \
| jq -r '.items[] | "\(.slug)\t\(.name)"'
# → yesoreyeram-infinity-datasource InfinityMultiple matches → show the candidates and ask which one.
The snippets below use Infinity (`yesoreyeram-infinity-datasource`) as the worked example — substitute the id resolved here (and the version from step 3) in every command and output.
3. Resolve the latest version
curl -s "https://grafana.com/api/plugins/yesoreyeram-infinity-datasource" | jq -r '.version'
Never hardcode a version — the CDN path is version-pinned and a stale version 404s.
4. Fetch the settings schema (primary structured source)
https://plugins-cdn.grafana.net/<PLUGIN_ID>/<VERSION>/public/plugins/<PLUGIN_ID>/schema/dsconfig.json
ID=yesoreyeram-infinity-datasource
VER=$(curl -s "https://grafana.com/api/plugins/$ID" | jq -r '.version')
curl -sf "https://plugins-cdn.grafana.net/$ID/$VER/public/plugins/$ID/schema/dsconfig.json"
This file conforms to the **dsconfig** schema spec — the source of truth for how to interpret it. Don't re-derive field semantics from memory (`valueType` alone spans `string`, `number`, `boolean`, `array`, `object`, `map`, `any`); consult the spec when a field isn't a plain scalar:
- Prose spec: https://raw.githubusercontent.com/grafana/dsconfig/refs/heads/main/dsconfig/schema.md
- Meta-schema (defines the format of every `dsconfig.json`): https://raw.githubusercontent.com/grafana/dsconfig/refs/heads/main/dsconfig/schema.json
What you need from each field to provision: `key` (the provisioning key), `valueType`, `target` (`root` | `jsonData` | `secureJsonData`), and `validations` (honor `allowedValues` for selectors like `auth_method`). Orientation example (`schemaVersion: "v1"`):
{
"pluginType": "yesoreyeram-infinity-datasource",
"fields": [
{
"key": "auth_method",
"valueType": "string",
"target": "jsonData",
"validations": [
{
"type": "allowedValues",
"values": [
"none",
"basicAuth",
"apiKey",
"bearerToken",
"oauth2",
"aws",
"azureBlob"
]
}
]
}
]
}Select only the fields relevant to what the user asked for (chosen auth method + connection), not all of them. Each field's `description` tells you which auth method it belongs to.
For ready-made example configs, fetch `v0alpha1.json`:
https://plugins-cdn.grafana.net/<PLUGIN_ID>/<VERSION>/public/plugins/<PLUGIN_ID>/schema/v0alpha1.json
ID=yesoreyeram-infinity-datasource
VER=$(curl -s "https://grafana.com/api/plugins/$ID" | jq -r '.version')
curl -sf "https://plugins-cdn.grafana.net/$ID/$VER/public/plugins/$ID/schema/v0alpha1.json"
Worked examples live under `settingsExamples.examples`, an object keyed by scenario (e.g. `apiKey`, `oauth2ClientCredentials`). Each entry has a `summary`/`description` (the scenario) and a `value` holding the `jsonData`/`secureJsonData` payload to lift straight into the file:
# list scenarios, then pull one payload
... | jq -r '.settingsExamples.examples | keys[]'
... | jq '.settingsExamples.examples.apiKey.value'
5. Fallback when no schema is published
If `schema/dsconfig.json` 404s (older plugins):
- Last resort: the generic structure in **grafana-oss** skill (§ Data source provisioning) can also tell the user the field names are best-effort, not plugin-authoritative.
> NOTE: **grafana-oss** skill is available in `grafana-core` plugin and also available as a standalone skill from the https://github.com/grafana/skills repository
6. Map each field by its `target`
| `target` | YAML | Terraform (`grafana_data_source`) | | ---------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | `root` | top-level key on the datasource (`url`, `basicAuth`, `basicAuthUser`) | top-level argument (`url`) / inside `json_data_encoded` | | `jsonData` | under `jsonData:` | key inside `json_data_encoded = jsonencode({ … })` | | `secureJsonData` | under `secureJsonData:` as `${ENV_VAR}` | key inside `secure_json_data_encoded = jsonencode({ … })` via a `sensitive` variable |
Use each field's `valueType` for the scalar (`string` quoted in YAML, `boolean`→`true`/`false`, `number` bare)
Read more
name: datasources-provisioning license: Apache-2.0 description: Generate a copy-paste Grafana data source provisioning file (YAML or Terraform) for any plugin from its standardized settings schema on the plugins CDN. Use when the user wants to provision or configure a data source as code — e.g. "provision infinity", "datasource yaml for clickhouse", "terraform for the github datasource" — even when they only name the plugin and not the word "provisioning".
Workflow
1. Ask the starting point: from scratch, or from an existing data source?
**Ask this before anything else** (skip only if the user already made it clear):
- **From scratch** — the user names a plugin type to provision → continue with step 2.
- **From an existing data source** in a running instance → jump to [Convert an existing data source](#convert-an-existing-data-source), then return to step 6.
2. Resolve the full plugin id
Provisioning needs the canonical plugin id (`<org>-<name>-datasource`), not the short name a user might say.
- Already canonical (contains `-datasource` or `-app`)? Use as-is: `yesoreyeram-infinity-datasource`.
- Short name only (e.g. `infinity`, `clickhouse`)? Search the catalog API with `filter=<keyword>`:
curl -s "https://grafana.com/api/plugins?filter=infinity" \
| jq -r '.items[] | "\(.slug)\t\(.name)"'
# → yesoreyeram-infinity-datasource InfinityMultiple matches → show the candidates and ask which one.
The snippets below use Infinity (`yesoreyeram-infinity-datasource`) as the worked example — substitute the id resolved here (and the version from step 3) in every command and output.
3. Resolve the latest version
curl -s "https://grafana.com/api/plugins/yesoreyeram-infinity-datasource" | jq -r '.version'
Never hardcode a version — the CDN path is version-pinned and a stale version 404s.
4. Fetch the settings schema (primary structured source)
https://plugins-cdn.grafana.net/<PLUGIN_ID>/<VERSION>/public/plugins/<PLUGIN_ID>/schema/dsconfig.json
ID=yesoreyeram-infinity-datasource VER=$(curl -s "https://grafana.com/api/plugins/$ID" | jq -r '.version') curl -sf "https://plugins-cdn.grafana.net/$ID/$VER/public/plugins/$ID/schema/dsconfig.json"
This file conforms to the **dsconfig** schema spec — the source of truth for how to interpret it. Don't re-derive field semantics from memory (`valueType` alone spans `string`, `number`, `boolean`, `array`, `object`, `map`, `any`); consult the spec when a field isn't a plain scalar:
- Prose spec: https://raw.githubusercontent.com/grafana/dsconfig/refs/heads/main/dsconfig/schema.md
- Meta-schema (defines the format of every `dsconfig.json`): https://raw.githubusercontent.com/grafana/dsconfig/refs/heads/main/dsconfig/schema.json
What you need from each field to provision: `key` (the provisioning key), `valueType`, `target` (`root` | `jsonData` | `secureJsonData`), and `validations` (honor `allowedValues` for selectors like `auth_method`). Orientation example (`schemaVersion: "v1"`):
{
"pluginType": "yesoreyeram-infinity-datasource",
"fields": [
{
"key": "auth_method",
"valueType": "string",
"target": "jsonData",
"validations": [
{
"type": "allowedValues",
"values": [
"none",
"basicAuth",
"apiKey",
"bearerToken",
"oauth2",
"aws",
"azureBlob"
]
}
]
}
]
}Select only the fields relevant to what the user asked for (chosen auth method + connection), not all of them. Each field's `description` tells you which auth method it belongs to.
For ready-made example configs, fetch `v0alpha1.json`:
https://plugins-cdn.grafana.net/<PLUGIN_ID>/<VERSION>/public/plugins/<PLUGIN_ID>/schema/v0alpha1.json
ID=yesoreyeram-infinity-datasource VER=$(curl -s "https://grafana.com/api/plugins/$ID" | jq -r '.version') curl -sf "https://plugins-cdn.grafana.net/$ID/$VER/public/plugins/$ID/schema/v0alpha1.json"
Worked examples live under `settingsExamples.examples`, an object keyed by scenario (e.g. `apiKey`, `oauth2ClientCredentials`). Each entry has a `summary`/`description` (the scenario) and a `value` holding the `jsonData`/`secureJsonData` payload to lift straight into the file:
# list scenarios, then pull one payload ... | jq -r '.settingsExamples.examples | keys[]' ... | jq '.settingsExamples.examples.apiKey.value'
5. Fallback when no schema is published
If `schema/dsconfig.json` 404s (older plugins):
- Last resort: the generic structure in **grafana-oss** skill (§ Data source provisioning) can also tell the user the field names are best-effort, not plugin-authoritative.
> NOTE: **grafana-oss** skill is available in `grafana-core` plugin and also available as a standalone skill from the https://github.com/grafana/skills repository
6. Map each field by its `target`
| `target` | YAML | Terraform (`grafana_data_source`) | | ---------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | `root` | top-level key on the datasource (`url`, `basicAuth`, `basicAuthUser`) | top-level argument (`url`) / inside `json_data_encoded` | | `jsonData` | under `jsonData:` | key inside `json_data_encoded = jsonencode({ … })` | | `secureJsonData` | under `secureJsonData:` as `${ENV_VAR}` | key inside `secure_json_data_encoded = jsonencode({ … })` via a `sensitive` variable |
Use each field's `valueType` for the scalar (`string` quoted in YAML, `boolean`→`true`/`false`, `number` bare)
Public skills for working with Grafana, Prometheus, Loki, Tempo, Pyroscope, k6, and the broader LGTM observability stack. Compatible with Claude Code, Cursor, Codex, and any tool supporting the Agent Skills open standard.
Repo: grafana/skills
Other skills on grafana-skills.
- /admission-control
Use when the user asks to "write a validator", "add validation", "implement admission control", "write a mutating webhook", "add a mutation handler", "validate incoming resources", "implement admission logic", "add admission webhooks", "write ingress validation", or asks how to
Open skill - /app-sdk-concepts
Use when starting any grafana-app-sdk work — scaffolding a Grafana app, initializing a Grafana App Platform app, picking a deployment mode (standalone operator / grafana/apps / frontend-only), wiring app-specific config, or onboarding to the SDK. Covers `grafana-app-sdk` CLI
Open skill - /cue-kind-definition
Author CUE kind definitions for grafana-app-sdk apps - schemas, versioning, field constraints, named type definitions, custom routes, and codegen configuration. Scaffolds kinds via `grafana-app-sdk project kind add`, writes spec/status schemas with type constraints (regex, enum,
Open skill - /reconciler-logic
Implement reconcilers and watchers for grafana-app-sdk apps — write `TypedReconciler[*MyKind]` reconcile functions, apply generation-based skip patterns, do conflict-safe status updates via `resource.UpdateObject`, configure `BasicReconcileOptions` (namespace, label/field
Open skill - /adaptive-metrics
Cut Grafana Cloud Metrics cost by shrinking active-series count with Adaptive Metrics aggregation rules — auto-recommendations from query history, custom exact/regex rules, label-drop config, unused-metric detection, and Alloy remote_write fallback. Use when investigating a high
Open skill - /admin
Manage Grafana Cloud accounts — organizations, stacks, RBAC roles and assignments, SSO/SAML/OAuth/GitHub auth, service accounts for CI/CD, user invites, team membership, and API-driven provisioning. Creates stacks via the Cloud API, mints service-account tokens, applies role
Open skill

