home-ops-debug
Diagnoses issues in the home-ops Kubernetes cluster using the Flux MCP and Grafana MCP tools. Follows a structured triage workflow to identify root causes efficiently.
Cluster constants
| Property |
Value |
| Flux namespace |
flux-system |
| App namespaces |
cert-manager, database, default, flux-system, kube-system, media, monitoring, network, security, storage, system-upgrade |
| Prometheus datasource |
Discover UID via list_datasources (type: prometheus) |
| Loki datasource |
Discover UID via list_datasources (type: loki) |
Tool mapping
| What to check |
MCP tool |
| Flux Kustomization / HelmRelease status |
flux: get_kubernetes_resources |
| Pod status, events, services |
flux: get_kubernetes_resources |
| Pod logs |
flux: get_kubernetes_logs |
| Pod CPU/memory usage |
flux: get_kubernetes_metrics |
| Force reconciliation |
flux: reconcile_flux_kustomization / reconcile_flux_helmrelease |
| Prometheus metrics |
grafana: query_prometheus |
| Application logs (Loki) |
grafana: query_loki_logs |
| Log error patterns |
grafana: find_error_pattern_logs |
| Firing alerts |
grafana: list_alert_rules |
| Dashboard visuals |
grafana: get_panel_image |
Workflow
Step 1 — Identify the target
Determine what the user wants to debug:
- Specific app — e.g., "radarr is broken" → app=
radarr, namespace=media
- Namespace-wide — e.g., "media apps are down" → scan all apps in namespace
- Cluster-wide — e.g., "what's broken" → scan all namespaces
- Specific symptom — e.g., "reconciliation stuck" → focus on Flux resources
Use the namespace mapping from the app skill:
default — homepage
network — adguard-home, cloudflare-dns, cloudflare-tunnel, envoy-gateway, k8s-gateway, unifi-dns
monitoring — alloy, gatus, grafana, kube-prometheus-stack, loki, ntfy, ntfy-alertmanager, smartctl-exporter, unpoller
database — cloudnativepg, redis
media — bazarr, flaresolverr, jellyfin, prowlarr, qbittorrent, radarr, recyclarr, seerr, sonarr
security — authentik
storage — volsync
Step 2 — Flux GitOps layer
Check Flux resources top-down. Run these in parallel when possible:
Kustomization status — check if the app's Kustomization is ready:
flux: get_kubernetes_resources
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
namespace: <namespace> # the app's namespace (set by Kustomize transformer)
name: <app> # optional, omit for namespace-wide scan
HelmRelease status — check if the HelmRelease is reconciled:
flux: get_kubernetes_resources
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
namespace: <namespace>
name: <app>
OCIRepository status — check if the chart source is available:
flux: get_kubernetes_resources
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
namespace: <namespace>
name: <app>
What to look for:
Ready: False with a message explaining why
Suspended: true — reconciliation paused
- Dependency failures — a
dependsOn target not ready
- Source fetch errors — OCI registry unreachable or tag not found
- Validation errors — invalid YAML or Helm values
If Flux resources look healthy, the issue is at the Kubernetes or application layer — proceed to Step 3.
If Flux is stuck, try reconciling:
flux: reconcile_flux_kustomization
name: <app>
namespace: <namespace>
with_source: true
Step 3 — Kubernetes resource layer
Check the workload resources. Run these in parallel:
Pods — are they running?
flux: get_kubernetes_resources
apiVersion: v1
kind: Pod
namespace: <namespace>
selector: app.kubernetes.io/name=<app>
Events — recent warnings or errors:
flux: get_kubernetes_resources
apiVersion: v1
kind: Event
namespace: <namespace>
Filter events mentioning the app name in the results.
PVCs — storage bound?
flux: get_kubernetes_resources
apiVersion: v1
kind: PersistentVolumeClaim
namespace: <namespace>
name: <app>
What to look for:
- Pod status:
CrashLoopBackOff, ImagePullBackOff, Pending, OOMKilled
- Events:
FailedScheduling (resource constraints), FailedMount (PVC issues), Unhealthy (probe failures)
- PVC:
Pending (no storage available)
Step 4 — Application logs
Fetch logs from the problematic pod. Use the Flux MCP for direct pod logs:
flux: get_kubernetes_logs
pod_name: <pod-name> # from Step 3 pod listing
container_name: app # most apps use "app" as container name
pod_namespace: <namespace>
limit: 100
If logs are also shipped to Loki, query for broader patterns:
grafana: query_loki_logs
datasourceUid: <loki-uid>
logql: '{namespace="<namespace>", app_kubernetes_io_name="<app>"} |= "error" or |= "fatal"'
limit: 50
For pattern analysis over time:
grafana: find_error_pattern_logs
name: "<app> error investigation"
labels: {"namespace": "<namespace>", "app_kubernetes_io_name": "<app>"}
Step 5 — Metrics and alerts (if relevant)
Check resource utilization and alert state:
Pod resource usage:
flux: get_kubernetes_metrics
pod_namespace: <namespace>
pod_selector: app.kubernetes.io/name=<app>
Firing alerts:
grafana: list_alert_rules
Filter for rules in firing or pending state.
Custom PromQL (when investigating specific symptoms):
grafana: query_prometheus
datasourceUid: <prometheus-uid>
expr: <query>
startTime: now-1h
queryType: instant
Useful queries:
- Restart count:
kube_pod_container_status_restarts_total{namespace="<ns>", pod=~"<app>.*"}
- OOM kills:
kube_pod_container_status_last_terminated_reason{namespace="<ns>", reason="OOMKilled"}
- CPU throttling:
rate(container_cpu_cfs_throttled_seconds_total{namespace="<ns>", pod=~"<app>.*"}[5m])
- Memory usage:
container_memory_working_set_bytes{namespace="<ns>", pod=~"<app>.*", container!=""}
Step 6 — Summarize and recommend
Present findings in this structure:
## Diagnosis: <app>
**Status:** <one-line summary>
**Root cause:** <what's actually wrong>
**Evidence:**
- <finding 1>
- <finding 2>
**Recommended fix:**
1. <action>
2. <action>
Common remediation patterns:
- Flux validation error → fix the manifest in the repo, commit, and push
- Image pull failure → check image tag/digest, registry availability
- CrashLoopBackOff → check logs for startup errors, config issues, missing secrets
- OOMKilled → increase memory limits in HelmRelease values
- PVC Pending → check StorageClass, node capacity
- Probe failure → check if port/path is correct, app startup time vs probe thresholds
- Dependency not ready → debug the dependency first (recursive)
- SOPS decryption failure → check age key is deployed, secret format is valid
Important notes
- Always discover datasource UIDs dynamically using
grafana: list_datasources — never hardcode them.
- Flux Kustomization namespace is the app's namespace (set by the Kustomize namespace transformer), not
flux-system.
- HelmRelease namespace follows the same pattern — it lives in the app's namespace.
- When checking multiple apps, run tool calls in parallel to speed up diagnosis.
- Do NOT take remediation actions (reconcile, delete, apply) without user confirmation — diagnosis only unless asked to fix.
- Pod container names: most apps use
app, but check the actual container name from the pod spec if app doesn't work.
Source: MarkNygaard/home-ops — distributed by TomeVault.
1---2name: marknygaard-home-ops-home-ops-debug3description: home-ops-debug4---56# home-ops-debug78Diagnoses issues in the home-ops Kubernetes cluster using the Flux MCP and Grafana MCP tools. Follows a structured triage workflow to identify root causes efficiently.910## Cluster constants1112| Property | Value |13|----------|-------|14| Flux namespace | `flux-system` |15| App namespaces | `cert-manager`, `database`, `default`, `flux-system`, `kube-system`, `media`, `monitoring`, `network`, `security`, `storage`, `system-upgrade` |16| Prometheus datasource | Discover UID via `list_datasources` (type: `prometheus`) |17| Loki datasource | Discover UID via `list_datasources` (type: `loki`) |1819## Tool mapping2021| What to check | MCP tool |22|---------------|----------|23| Flux Kustomization / HelmRelease status | `flux: get_kubernetes_resources` |24| Pod status, events, services | `flux: get_kubernetes_resources` |25| Pod logs | `flux: get_kubernetes_logs` |26| Pod CPU/memory usage | `flux: get_kubernetes_metrics` |27| Force reconciliation | `flux: reconcile_flux_kustomization` / `reconcile_flux_helmrelease` |28| Prometheus metrics | `grafana: query_prometheus` |29| Application logs (Loki) | `grafana: query_loki_logs` |30| Log error patterns | `grafana: find_error_pattern_logs` |31| Firing alerts | `grafana: list_alert_rules` |32| Dashboard visuals | `grafana: get_panel_image` |3334## Workflow3536### Step 1 — Identify the target3738Determine what the user wants to debug:39- **Specific app** — e.g., "radarr is broken" → app=`radarr`, namespace=`media`40- **Namespace-wide** — e.g., "media apps are down" → scan all apps in namespace41- **Cluster-wide** — e.g., "what's broken" → scan all namespaces42- **Specific symptom** — e.g., "reconciliation stuck" → focus on Flux resources4344Use the namespace mapping from the app skill:45- `default` — homepage46- `network` — adguard-home, cloudflare-dns, cloudflare-tunnel, envoy-gateway, k8s-gateway, unifi-dns47- `monitoring` — alloy, gatus, grafana, kube-prometheus-stack, loki, ntfy, ntfy-alertmanager, smartctl-exporter, unpoller48- `database` — cloudnativepg, redis49- `media` — bazarr, flaresolverr, jellyfin, prowlarr, qbittorrent, radarr, recyclarr, seerr, sonarr50- `security` — authentik51- `storage` — volsync5253### Step 2 — Flux GitOps layer5455Check Flux resources top-down. Run these in parallel when possible:56571. **Kustomization status** — check if the app's Kustomization is ready:58 ```59 flux: get_kubernetes_resources60 apiVersion: kustomize.toolkit.fluxcd.io/v161 kind: Kustomization62 namespace: <namespace> # the app's namespace (set by Kustomize transformer)63 name: <app> # optional, omit for namespace-wide scan64 ```65662. **HelmRelease status** — check if the HelmRelease is reconciled:67 ```68 flux: get_kubernetes_resources69 apiVersion: helm.toolkit.fluxcd.io/v270 kind: HelmRelease71 namespace: <namespace>72 name: <app>73 ```74753. **OCIRepository status** — check if the chart source is available:76 ```77 flux: get_kubernetes_resources78 apiVersion: source.toolkit.fluxcd.io/v179 kind: OCIRepository80 namespace: <namespace>81 name: <app>82 ```8384**What to look for:**85- `Ready: False` with a message explaining why86- `Suspended: true` — reconciliation paused87- Dependency failures — a `dependsOn` target not ready88- Source fetch errors — OCI registry unreachable or tag not found89- Validation errors — invalid YAML or Helm values9091**If Flux resources look healthy**, the issue is at the Kubernetes or application layer — proceed to Step 3.9293**If Flux is stuck**, try reconciling:94```95flux: reconcile_flux_kustomization96 name: <app>97 namespace: <namespace>98 with_source: true99```100101### Step 3 — Kubernetes resource layer102103Check the workload resources. Run these in parallel:1041051. **Pods** — are they running?106 ```107 flux: get_kubernetes_resources108 apiVersion: v1109 kind: Pod110 namespace: <namespace>111 selector: app.kubernetes.io/name=<app>112 ```1131142. **Events** — recent warnings or errors:115 ```116 flux: get_kubernetes_resources117 apiVersion: v1118 kind: Event119 namespace: <namespace>120 ```121 Filter events mentioning the app name in the results.1221233. **PVCs** — storage bound?124 ```125 flux: get_kubernetes_resources126 apiVersion: v1127 kind: PersistentVolumeClaim128 namespace: <namespace>129 name: <app>130 ```131132**What to look for:**133- Pod status: `CrashLoopBackOff`, `ImagePullBackOff`, `Pending`, `OOMKilled`134- Events: `FailedScheduling` (resource constraints), `FailedMount` (PVC issues), `Unhealthy` (probe failures)135- PVC: `Pending` (no storage available)136137### Step 4 — Application logs138139Fetch logs from the problematic pod. Use the Flux MCP for direct pod logs:140141```142flux: get_kubernetes_logs143 pod_name: <pod-name> # from Step 3 pod listing144 container_name: app # most apps use "app" as container name145 pod_namespace: <namespace>146 limit: 100147```148149If logs are also shipped to Loki, query for broader patterns:150151```152grafana: query_loki_logs153 datasourceUid: <loki-uid>154 logql: '{namespace="<namespace>", app_kubernetes_io_name="<app>"} |= "error" or |= "fatal"'155 limit: 50156```157158For pattern analysis over time:159```160grafana: find_error_pattern_logs161 name: "<app> error investigation"162 labels: {"namespace": "<namespace>", "app_kubernetes_io_name": "<app>"}163```164165### Step 5 — Metrics and alerts (if relevant)166167Check resource utilization and alert state:1681691. **Pod resource usage:**170 ```171 flux: get_kubernetes_metrics172 pod_namespace: <namespace>173 pod_selector: app.kubernetes.io/name=<app>174 ```1751762. **Firing alerts:**177 ```178 grafana: list_alert_rules179 ```180 Filter for rules in `firing` or `pending` state.1811823. **Custom PromQL** (when investigating specific symptoms):183 ```184 grafana: query_prometheus185 datasourceUid: <prometheus-uid>186 expr: <query>187 startTime: now-1h188 queryType: instant189 ```190191 Useful queries:192 - Restart count: `kube_pod_container_status_restarts_total{namespace="<ns>", pod=~"<app>.*"}`193 - OOM kills: `kube_pod_container_status_last_terminated_reason{namespace="<ns>", reason="OOMKilled"}`194 - CPU throttling: `rate(container_cpu_cfs_throttled_seconds_total{namespace="<ns>", pod=~"<app>.*"}[5m])`195 - Memory usage: `container_memory_working_set_bytes{namespace="<ns>", pod=~"<app>.*", container!=""}`196197### Step 6 — Summarize and recommend198199Present findings in this structure:200201```202## Diagnosis: <app>203204**Status:** <one-line summary>205206**Root cause:** <what's actually wrong>207208**Evidence:**209- <finding 1>210- <finding 2>211212**Recommended fix:**2131. <action>2142. <action>215```216217Common remediation patterns:218- **Flux validation error** → fix the manifest in the repo, commit, and push219- **Image pull failure** → check image tag/digest, registry availability220- **CrashLoopBackOff** → check logs for startup errors, config issues, missing secrets221- **OOMKilled** → increase memory limits in HelmRelease values222- **PVC Pending** → check StorageClass, node capacity223- **Probe failure** → check if port/path is correct, app startup time vs probe thresholds224- **Dependency not ready** → debug the dependency first (recursive)225- **SOPS decryption failure** → check age key is deployed, secret format is valid226227## Important notes228229- Always discover datasource UIDs dynamically using `grafana: list_datasources` — never hardcode them.230- Flux Kustomization namespace is the **app's namespace** (set by the Kustomize namespace transformer), not `flux-system`.231- HelmRelease namespace follows the same pattern — it lives in the app's namespace.232- When checking multiple apps, run tool calls in parallel to speed up diagnosis.233- Do NOT take remediation actions (reconcile, delete, apply) without user confirmation — diagnosis only unless asked to fix.234- Pod container names: most apps use `app`, but check the actual container name from the pod spec if `app` doesn't work.235236---237> Source: [MarkNygaard/home-ops](https://github.com/MarkNygaard/home-ops) — distributed by [TomeVault](https://tomevault.io).238<!-- tomevault:4.0:skill_md:2026-05-22 -->