Cleanup
Scan a Kubernetes cluster for idle resources — pods, PVCs, ConfigMaps, and namespaces.
annave cleanup scan connects to your Kubernetes cluster and lists resources that are idle, failed, or unused. It is read-only — it never deletes or modifies anything.
Usage
bash
annave cleanup scan [flags]Flags
| Flag | Short | Default | Description |
|---|---|---|---|
| --namespace | -n | — | Limit scan to a specific namespace. Omit to scan all namespaces. |
| --context | — | kubeconfig context to use | |
| --kubeconfig | — | Path to kubeconfig file | |
| --dry-run | true | Preview only — always true, the flag is for output labelling | |
| --format | plain | Output format: plain, json, table |
Kubeconfig resolution order: --kubeconfig flag → $KUBECONFIG environment variable → ~/.kube/config.
What it finds
| Resource | Condition flagged |
|---|---|
| Pod | Status `Succeeded` (completed job pod left behind) |
| Pod | Status `Failed` |
| Pod | Status `Running` with a container in `CrashLoopBackOff` |
| Pod | Status `Pending` for longer than 10 minutes |
| PVC | Phase `Lost` |
| PVC | Phase `Pending` for longer than 1 hour |
| PVC | Phase `Bound` but not mounted by any running pod for over 24 hours |
| ConfigMap | No owner references and older than 30 days |
| Namespace | No pods, Deployments, StatefulSets, or Services |
Examples
Scan all namespaces
bash
annave cleanup scanScan a specific namespace
bash
annave cleanup scan --namespace stagingNon-default kubeconfig context
bash
annave cleanup scan --context production-clusterJSON output for scripting
bash
annave cleanup scan --format json | jq '[.resources[] | select(.reason == "CrashLoopBackOff")]'Plain output
text
Cleanup scan [DRY RUN] — 2026-05-16 10:42:07
context docker-desktop
namespace all namespaces
findings 5 idle resource(s)
Pod (3):
production/worker-job-4x9mt Completed finished 3d ago
staging/api-6b8f9d-abcde CrashLoopBackOff 14 restarts
staging/migration-job-1a2b3 Failed exit code 1
PVC (2):
production/data-postgres-0 BoundUnmounted unmounted 48h
staging/logs-collector-pvc Pending pending 2h15mJSON output shape
json
{
"context": "docker-desktop",
"namespace": "",
"dry_run": true,
"scanned_at": "2026-05-16T10:42:07Z",
"resources": [
{
"resource": {
"kind": "Pod",
"name": "worker-job-4x9mt",
"namespace": "production",
"age_hours": 72
},
"reason": "Completed",
"detail": "finished 3d ago"
}
]
}Required permissions
The kubeconfig user needs list and get on the following resources:
- pods (all namespaces)
- persistentvolumeclaims (all namespaces)
- configmaps (all namespaces)
- namespaces
- deployments (for empty namespace detection)
- statefulsets (for empty namespace detection)
- services (for empty namespace detection)
What to watch
- The scan is always read-only. The
--dry-runflag exists only to label the output clearly — it does not change behaviour. - For large clusters, the default 30-second context deadline may be too short. Increase
cleanup.timeout_secondsinlimits.yamland rebuild. - Bound-but-unmounted PVC detection compares the PVC list against all pods in the namespace. If pod listing is slow or returns partial results, some PVCs may be incorrectly flagged. Verify before deleting.
- Empty namespace detection does not consider Custom Resource Definitions. A namespace with only CRD instances will be reported as empty.