Loading...
Loading...
Use when working with CUE kind definitions, schemas, or versioning in grafana-app-sdk projects (app platform apps). This skill should be used when the user asks to "define a kind", "add a CUE kind", "write a kind schema", "create a CUE schema", "model a resource", "add a new resource type", "edit kinds/", "what is a kind in grafana-app-sdk", "add a version to a kind", or asks about CUE kind structure, versioning, schema fields, validation constraints, or the codegen configuration section. Provides guidance on authoring CUE kind definitions for grafana-app-sdk projects.
npx skill4agent add grafana/skills cue-kind-definitiongrafana-app-sdk project kind add <KindName> --overwrite.cueAlways usewhen re-running to regenerate scaffolding without losing manual additions.--overwrite
grafana-app-sdk project kind addkinds/package kindskinds/
├── manifest.cue # App manifest + version list declarations
├── mykind.cue # Common (cross-version) kind metadata
└── mykind_v1alpha1.cue # v1alpha1 schema + codegen configkinds/
├── manifest.cue
├── mykind.cue
├── mykind_v1alpha1.cue
└── mykind_v1.cueFor larger, more complex kind definitions users may choose to organise kinds into per-kind and per-version subdirectories, each with their own package. The default CLI output uses the flat layout above.
// kinds/mykind.cue
package kinds
myKind: {
kind: "MyKind" // Required: the kind name (PascalCase)
// other cross-version fields (scope, pluralName, validation, mutation, conversion, etc.)
// See references/kind-layout.md for the full field reference
}&// kinds/mykind_v1alpha1.cue
package kinds
myKindv1alpha1: myKind & {
// Version-specific schema
schema: {
// spec: desired state — set by users/clients, never by the operator
spec: {
title: string
description: string | *"" // optional with default
count: int & >=0
enabled: bool | *true
}
// status: observed state — written only by the operator/reconciler,
// never by users. Mirrors Kubernetes spec/status conventions.
status: {
lastObservedGeneration: int | *0
state: string | *""
message: string | *""
}
}
// Code generation config
codegen: {
ts: { enabled: true } // generate TypeScript types
go: { enabled: true } // generate Go types and client
}
}package kinds// kinds/manifest.cue
package kinds
App: {
appName: "my-app"
versions: {
"v1alpha1": {
schema: myKindv1alpha1
}
}
}specspecspecspecstatusstatusstatusstatusstatus: {
// Generation of the spec that was last successfully reconciled.
// Set to metadata.generation after a successful reconcile loop.
lastObservedGeneration: int | *0
// Human-readable summary of current state
state: string | *"" // e.g. "Ready", "Provisioning", "Error"
message: string | *"" // detail, especially on error
// References to objects created by the reconciler.
// e.g. the name of a ConfigMap or Deployment the reconciler provisioned.
provisionedConfigMap: string | *""
provisionedServiceAccount: string | *""
}statusspeclastObservedGenerationobservedGenerationconditions"Ready""Degraded"specstatus##schema#DefinitionSpecschema: {
#Threshold: {
value: float & >=0
severity: "info" | "warning" | "critical"
message: string | *""
}
#ResourceRef: {
name: string & != ""
namespace: string | *"default"
}
spec: {
title: string & != ""
alertThreshold: #Threshold
thresholds: [...#Threshold] // list of a defined type
targetRef?: #ResourceRef // optional
}
}#schema#[...#MyType]{[string]: string}[...string]// Basic types
myString: string
myInt: int
myFloat: float
myBool: bool
myBytes: bytes
// Optional with default
name: string | *"default-value"
// Constraints (using & to intersect)
port: int & >=1 & <=65535
label: string & =~"^[a-z][a-z0-9-]*$" // regex constraint
// Enums (disjunctions)
status: "pending" | "active" | "archived"
// Maps (always fine inline)
labels: {[string]: string}
attrs: {[string]: _}
// Lists of scalars (fine inline)
tags: [...string]
// Optional field
description?: stringapp.goMyKind: {
kind: "MyKind"
schema: { ... }
routes: {
"/actions/process": {
"POST": {
name: "processMyKind" // unique within version; must start with a k8s verb
request: {
body: {
reason: string
}
}
response: {
jobId: string
status: string
}
}
}
}
}versions: {
"v1alpha1": {
routes: {
namespaced: {
"/summary": {
"GET": {
name: "getNamespacedSummary"
response: { count: int }
}
}
}
cluster: {
"/health": {
"GET": {
name: "getHealth"
response: { status: string }
}
}
}
}
}
}grafana-app-sdk generateValidateManifestschema.speckindv1v2statusspeccodegen: {
ts: { enabled: true | false } // TypeScript types
go: { enabled: true | false } // Go types + client
}gotstrue.cuegrafana-app-sdk generatepkg/generated/