npx skills add ...
npx skills add grafana/skills --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 filters, finalizer management), use `Watcher` for event-style handling, reconcile `UnmanagedKinds` (resources your app doesn't own), and register the whole thing in `app.go`. Use when writing a reconciler, implementing the reconcile loop, adding async business logic, handling create/update/delete events, processing resource state changes, scheduling periodic resyncs with `RequeueAfter`, picking between Watcher and Reconciler, or wiring a controller into `app.go` — even when the user says "process this resource", "handle X events", or "write a controller" without saying "reconciler".
npx skills add grafana/skills --skill reconciler-logic
Reconcilers are the async business-logic layer of a grafana-app-sdk app. The SDK enqueues a reconcile event when a resource is created, updated, or deleted; the reconciler observes the current state and drives the system toward the desired state.
If the operator starts but no reconcile events fire when you create a resource:
BasicReconcileOptions.Namespace matches the resource's namespaceBasicReconcileOptions.LabelFilters / FieldSelectors — most "no events" issues are filter mismatches (kubectl get <resource> -o yaml to see labels)operator.TypedReconciler handles type assertion and provides a strongly-typed ReconcileFunc:
ReconcileAction values: ReconcileActionCreated, ReconcileActionUpdated, ReconcileActionDeleted, ReconcileActionResynced.
To requeue after a delay (e.g. polling an external system):
resource.UpdateObjectAlways use resource.UpdateObject for status writes — it fetches the latest version before applying your update function, avoiding 409 Conflict errors when multiple reconcile events race:
Do not use client.Update for status — it sends the full object and races with spec changes made by users.
Check LastObservedGeneration at the top of the reconcile function to avoid re-processing unchanged resources:
ReconcileOptionsControl informer behavior via BasicReconcileOptions on the AppManagedKind entry:
UsePlain: false (the default) wraps your reconciler in OpinionatedReconciler, which manages finalizers automatically so the SDK can guarantee clean deletion.
references/watchers.md — Watcher alternative (event-style Add/Update/Delete callbacks) + decision matrix for watcher vs reconcilerreferences/unmanaged-kinds.md — UnmanagedKinds for reconciling resources your app doesn't own, with UseOpinionated: false guidance and common failure modesreferences/registration.md — full app.go wiring (client setup, multi-version registration, ValidateManifest) + common failure modes