> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kubex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Cluster Automation Strategies

> Experimental: GPU/KAI-related fields in this resource are subject to breaking changes. When using them, set `spec.experimental.gpuKaiContract: v1alpha1-2026-07`.

`ClusterAutomationStrategy` defines how resizing is allowed to happen for cluster-scoped policy flows.

Use it when a platform team wants one reusable resize behavior that can be referenced by `ClusterProactivePolicy` and `ClusterStaticPolicy` across multiple namespaces.

For the namespaced variant, see [Automation Strategies](https://docs.kubex.ai/docs-kubex/Content/Kubex/automation-engine/automation-strategies.md).

## Reference Rules

* `ClusterProactivePolicy` references a `ClusterAutomationStrategy`.
* `ClusterStaticPolicy` references a `ClusterAutomationStrategy`.
* Helm can generate `ClusterAutomationStrategy` resources from `policy.policies`, but these CRs can also be managed directly with manifests or GitOps.

## Field Reference

`ClusterAutomationStrategy.spec` uses the same field structure and defaults as the namespaced `AutomationStrategy`:

Usage-level `floor` and `ceiling` values apply to all containers by default. Add `containers.<name>` under the same requests or limits block when a multi-container pod needs different bounds for specific containers.

| Field | Default | Description |
| - | - | - |
| `spec.enablement` | `{}` | Parent object for enablement rules. |
| `spec.enablement.overrideScheduler` | `none` | EXPERIMENTAL. Selects GPU mutation mode for GPU actions. Valid values: `none`, `kai`. |
| `spec.enablement.cpu.requests.downsize` | `true` | Allows reducing CPU requests. |
| `spec.enablement.cpu.requests.upsize` | `true` | Allows increasing CPU requests. |
| `spec.enablement.cpu.requests.setFromUnspecified` | `true` | Allows setting CPU requests when currently unset. |
| `spec.enablement.cpu.requests.floor` | none | Minimum CPU request target. |
| `spec.enablement.cpu.requests.ceiling` | none | Maximum CPU request target. |
| `spec.enablement.cpu.requests.containers.<name>.floor` | none | Container-specific CPU request minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.cpu.requests.containers.<name>.ceiling` | none | Container-specific CPU request maximum that overrides the usage-level ceiling for that container only. |
| `spec.enablement.cpu.limits.downsize` | `true` | Allows reducing CPU limits. |
| `spec.enablement.cpu.limits.upsize` | `true` | Allows increasing CPU limits. |
| `spec.enablement.cpu.limits.setFromUnspecified` | `false` | Allows setting CPU limits when currently unset. |
| `spec.enablement.cpu.limits.floor` | none | Minimum CPU limit target. |
| `spec.enablement.cpu.limits.ceiling` | none | Maximum CPU limit target. |
| `spec.enablement.cpu.limits.containers.<name>.floor` | none | Container-specific CPU limit minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.cpu.limits.containers.<name>.ceiling` | none | Container-specific CPU limit maximum that overrides the usage-level ceiling for that container only. |
| `spec.enablement.memory.requests.downsize` | `true` | Allows reducing memory requests. |
| `spec.enablement.memory.requests.upsize` | `true` | Allows increasing memory requests. |
| `spec.enablement.memory.requests.setFromUnspecified` | `true` | Allows setting memory requests when currently unset. |
| `spec.enablement.memory.requests.floor` | none | Minimum memory request target. |
| `spec.enablement.memory.requests.ceiling` | none | Maximum memory request target. |
| `spec.enablement.memory.requests.containers.<name>.floor` | none | Container-specific memory request minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.memory.requests.containers.<name>.ceiling` | none | Container-specific memory request maximum that overrides the usage-level ceiling for that container only. |
| `spec.enablement.memory.limits.downsize` | `true` | Allows reducing memory limits. |
| `spec.enablement.memory.limits.upsize` | `true` | Allows increasing memory limits. |
| `spec.enablement.memory.limits.setFromUnspecified` | `true` | Allows setting memory limits when currently unset. |
| `spec.enablement.memory.limits.floor` | none | Minimum memory limit target. |
| `spec.enablement.memory.limits.ceiling` | none | Maximum memory limit target. |
| `spec.enablement.memory.limits.containers.<name>.floor` | none | Container-specific memory limit minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.memory.limits.containers.<name>.ceiling` | none | Container-specific memory limit maximum that overrides the usage-level ceiling for that container only. |
| `spec.enablement.ephemeralStorage.restartStrategy` | `OnNextRestart` | How storage changes reach running pods. `OnNextRestart` applies them the next time the pod is recreated (for example a rollout, scale-up, or node drain) and never evicts. `Evict` restarts the pod to apply them and requires `podEviction.enabled: true`. |
| `spec.enablement.ephemeralStorage.requests.downsize` | `false` | Allows reducing ephemeral-storage requests. |
| `spec.enablement.ephemeralStorage.requests.upsize` | `false` | Allows increasing ephemeral-storage requests. |
| `spec.enablement.ephemeralStorage.requests.setFromUnspecified` | `false` | Allows setting ephemeral-storage requests when currently unset. |
| `spec.enablement.ephemeralStorage.requests.floor` | none | Minimum ephemeral-storage request target. |
| `spec.enablement.ephemeralStorage.requests.ceiling` | none | Maximum ephemeral-storage request target. |
| `spec.enablement.ephemeralStorage.requests.containers.<name>.floor` | none | Container-specific ephemeral-storage request minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.ephemeralStorage.requests.containers.<name>.ceiling` | none | Container-specific ephemeral-storage request maximum that overrides the usage-level ceiling for that container only. |
| `spec.enablement.ephemeralStorage.limits.downsize` | `false` | Allows reducing ephemeral-storage limits. |
| `spec.enablement.ephemeralStorage.limits.upsize` | `false` | Allows increasing ephemeral-storage limits. |
| `spec.enablement.ephemeralStorage.limits.setFromUnspecified` | `false` | Allows setting ephemeral-storage limits when currently unset. |
| `spec.enablement.ephemeralStorage.limits.floor` | none | Minimum ephemeral-storage limit target. |
| `spec.enablement.ephemeralStorage.limits.ceiling` | none | Maximum ephemeral-storage limit target. |
| `spec.enablement.ephemeralStorage.limits.containers.<name>.floor` | none | Container-specific ephemeral-storage limit minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.ephemeralStorage.limits.containers.<name>.ceiling` | none | Container-specific ephemeral-storage limit maximum that overrides the usage-level ceiling for that container only. |
| `spec.enablement.gpu.requests.downsize` | `false` | EXPERIMENTAL. Allows reducing GPU requests. |
| `spec.enablement.gpu.requests.upsize` | `false` | EXPERIMENTAL. Allows increasing GPU requests. |
| `spec.enablement.gpu.requests.setFromUnspecified` | `false` | EXPERIMENTAL. Allows setting GPU requests when currently unset. |
| `spec.enablement.gpu.requests.floor` | none | EXPERIMENTAL. Minimum GPU request target. |
| `spec.enablement.gpu.requests.ceiling` | none | EXPERIMENTAL. Maximum GPU request target. |
| `spec.enablement.gpu.requests.containers.<name>.floor` | none | EXPERIMENTAL. Container-specific GPU request minimum that overrides the usage-level floor for that container only. |
| `spec.enablement.gpu.requests.containers.<name>.ceiling` | none | EXPERIMENTAL. Container-specific GPU request maximum that overrides the usage-level ceiling for that container only. |
| `spec.inPlaceResize.enabled` | `true` | Enables the in-place resize execution path. |
| `spec.inPlaceResize.containerRestart` | `false` | Allows in-place resize operations that require container restart. |
| `spec.podEviction.enabled` | `true` | Enables eviction-based fallback. |
| `spec.podEviction.retryPodDisruptionBudget` | `true` | Retries eviction when blocked by PDB. |
| `spec.scheduling` | `{}` | Parent object for scheduling-based allow and block windows. |
| `spec.scheduling.inclusionWindows[]` | none | Windows when resizing is allowed. When at least one inclusion window exists, resizing is allowed only inside one of them. |
| `spec.scheduling.inclusionWindows[].name` | none | Optional label used in logs and summaries. |
| `spec.scheduling.inclusionWindows[].timezone` | `UTC` | IANA timezone used for weekday and time evaluation. |
| `spec.scheduling.inclusionWindows[].weekdays[]` | all days | Restricts the window to specific weekdays such as `Monday` or `Mon`. |
| `spec.scheduling.inclusionWindows[].start` | `00:00` | Inclusive local start time in `HH:MM` 24-hour format. If omitted, the window begins at the start of the day. |
| `spec.scheduling.inclusionWindows[].end` | `24:00` | Exclusive local end time in `HH:MM` 24-hour format. If omitted, the window ends at the end of the day. Supports `24:00` to represent the end of the day. |
| `spec.scheduling.exclusionWindows[]` | none | Windows when resizing is blocked. Exclusion windows always take precedence over inclusion windows. |
| `spec.scheduling.exclusionWindows[].name` | none | Optional label used in logs and summaries. |
| `spec.scheduling.exclusionWindows[].timezone` | `UTC` | IANA timezone used for weekday and time evaluation. |
| `spec.scheduling.exclusionWindows[].weekdays[]` | all days | Restricts the window to specific weekdays such as `Friday` or `Fri`. |
| `spec.scheduling.exclusionWindows[].start` | `00:00` | Inclusive local start time in `HH:MM` 24-hour format. If omitted, the window begins at the start of the day. |
| `spec.scheduling.exclusionWindows[].end` | `24:00` | Exclusive local end time in `HH:MM` 24-hour format. If omitted, the window ends at the end of the day. Supports `24:00` to represent the end of the day. |
| `spec.safetyChecks.enablePauseUntilAnnotationCheck` | `true` | Blocks actions when pause annotations are present. |
| `spec.safetyChecks.enableResourceQuotaFilter` | `true` | Filters actions that would violate `ResourceQuota`. |
| `spec.safetyChecks.enableHpaFilter` | `true` | Filters actions for HPA-managed resources. |
| `spec.safetyChecks.enableVpaFilter` | `true` | Filters actions when a VPA is actively managing the resource (has recommendations and updateMode enabled). |
| `spec.safetyChecks.blockResizeOnVpaControlledResources` | `false` | Filters actions for any resource declared in a VPA resourcePolicy, even if the VPA is Off or has no recommendations. This setting is only evaluated after `enableVpaFilter=true` passes, so it is more defensive than `enableVpaFilter`. |
| `spec.safetyChecks.enableLimitRangeFilter` | `true` | Filters actions that violate `LimitRange` container rules. |
| `spec.safetyChecks.enablePodLimitRangeFilter` | `true` | Filters actions that violate pod-level `LimitRange` rules. |
| `spec.safetyChecks.retainGuaranteedQOS` | `false` | Keeps Guaranteed QoS pods at request=limit by treating limits as the source of truth for CPU and memory when enabled. |
| `spec.safetyChecks.minCpuChangePercent` | `5` | Ignores CPU changes below this threshold. |
| `spec.safetyChecks.minMemoryChangePercent` | `5` | Ignores memory changes below this threshold. |
| `spec.safetyChecks.minEphemeralStorageChangePercent` | `10` | Ignores ephemeral-storage changes below this threshold. |
| `spec.safetyChecks.minReadyDuration` | `10s` | Requires pods to be Ready for at least this duration. |
| `spec.safetyChecks.requireOwnerPodsReady` | `false` | Requires all pods in the owner workload to be Ready. |
| `spec.safetyChecks.respectWorkloadMaxUnavailable` | `true` | Prevents actions that exceed workload `maxUnavailable`. In-place resizes that don't restart a container don't count against it. |
| `spec.safetyChecks.resizeRetryInterval` | `30s` | Requeue interval for temporarily blocked actions. |
| `spec.safetyChecks.requireNodeAllocatable` | `true` | Filters request increases that exceed node allocatable capacity. |
| `spec.safetyChecks.nodeCpuHeadroom` | `10%` | CPU headroom reserved before node allocatable checks. |
| `spec.safetyChecks.nodeMemoryHeadroom` | `200Mi` | Memory headroom reserved before node allocatable checks. |

## VPA Filter Behavior

Two complementary VPA filters help avoid conflicts between Kubex automation and Vertical Pod Autoscalers:

### enableVpaFilter (default: true)

Filters actions when a VPA is **actively managing** the resource. This requires all of:

* VPA `updateMode` is not `Off` (i.e., `Auto`, `Recreate`, or `Initial`)
* VPA has an active recommendation with status `RecommendationProvided=True`
* The resource dimension (e.g., `cpu.requests`) appears in the VPA's `containerRecommendations`

**Use case:** Prevent conflicts when VPA is actively recommending and applying changes. This is the default safe behavior that defers to VPA when it's doing work.

### blockResizeOnVpaControlledResources (default: false)

Filters actions for resources **declared** in a VPA `resourcePolicy`, regardless of whether the VPA is active. This check is only evaluated when `enableVpaFilter=true`. It checks only:

* The resource is listed in `resourcePolicy.containerPolicies[].controlledResources`
* The usage type (requests/limits) matches `controlledValues` (defaults to both)

Does **not** check:

* VPA `updateMode` (blocks even when `Off`)
* Recommendation status (blocks even when no recommendations exist)
* Whether VPA is actively applying changes

**Use case:** Reserve resources for future VPA management, or ensure strict non-interference when VPA ownership is declared but the VPA may be temporarily disabled or not yet providing recommendations.

### Comparison

| Scenario | enableVpaFilter | blockResizeOnVpaControlledResources |
| - | - | - |
| VPA in `Auto` mode with active recommendations | Blocks | Blocks |
| VPA in `Off` mode with resourcePolicy declared | Allows | Blocks |
| VPA in `Auto` mode but no recommendations yet | Allows | Blocks |
| VPA in `Initial` mode after first recommendation | Allows | Blocks (if resourcePolicy declared) |
| No matching VPA | Allows | Allows |

**Note:** `blockResizeOnVpaControlledResources` is ignored unless `enableVpaFilter=true` is enabled.

## Scheduling Windows

`spec.scheduling` lets platform teams constrain when cluster-scoped proactive automation is allowed to execute.

* `inclusionWindows` define allowed times. If multiple inclusion windows are defined, they are evaluated with OR logic (automation is allowed if it matches ANY inclusion window). Inclusion windows may overlap.
* `exclusionWindows` define blocked times and always override inclusion windows.
* If neither list is set, scheduling does not restrict automation.
* If any inclusion window is defined, automation is allowed only while the current time matches at least one inclusion window.
* `start` is inclusive and `end` is exclusive.
* If `start` or `end` are omitted, they default to `00:00` and `24:00` respectively, allowing for easy "all day" configuration.
* Windows are evaluated in the window's local IANA timezone specified in the `timezone` field.
* Overnight windows are supported. For example, `22:00` to `06:00` spans midnight. `24:00` is supported for exclusive end times.

When scheduling blocks a proactive resize, the controller keeps the recommendation pending and retries when the next allowed window opens.

## Helm Mapping

The current chart can generate `ClusterAutomationStrategy` resources from `policy.policies`, but it does not render scheduling fields from Helm values.

For scheduling-controlled cluster automation:

* Create or manage the `ClusterAutomationStrategy` manifest directly.
* Reference that strategy name from a Helm-managed or manually managed `ClusterProactivePolicy`.

## Ephemeral Storage

`spec.enablement.ephemeralStorage` uses the same fields as `spec.enablement.memory`, plus `restartStrategy`. Unlike memory, every storage change is off by default. Set `upsize`, `downsize`, or `setFromUnspecified` to `true` for the changes you want. Example that allows storage changes with a floor, keeps limits from shrinking, and sets a per-container ceiling:

```yaml theme={null}
spec:
  enablement:
    ephemeralStorage:
      restartStrategy: OnNextRestart
      requests:
        upsize: true
        downsize: true
        setFromUnspecified: true
        floor: 1Gi
        containers:
          worker:
            ceiling: 20Gi
      limits:
        upsize: true
        setFromUnspecified: true
        floor: 1Gi
        containers:
          worker:
            ceiling: 40Gi
```

By default, storage changes are applied the next time the pod is recreated (for example a rollout, scale-up, or node drain). Set `restartStrategy: Evict` to let Kubex restart the pod to apply them. See [Proactive Policies](https://docs.kubex.ai/docs-kubex/Content/Kubex/automation-engine/proactive-policies.md#ephemeral-storage) for how to turn them on, how they are applied, and how to turn them off.

## Guaranteed QoS Behavior

When `spec.safetyChecks.retainGuaranteedQOS` is enabled:

* The behavior applies only to pods that are currently in the Kubernetes `Guaranteed` QoS class.
* For CPU and memory, desired limits are treated as the source of truth.
* Request values are automatically set to match limit values so `requests == limits` remains true.
* If a limit action exists but no request action exists, the controller can add a matching request action to preserve `Guaranteed` QoS.

When this toggle is disabled (default), requests and limits are handled independently by recommendation and enablement logic, and a pod can move away from `Guaranteed` QoS.

Note: A pod is in the `Guaranteed` QoS class only when ALL containers have `requests == limits` for BOTH CPU and memory. If a container has CPU request=limit but memory request≠limit, the pod is `Burstable`, not `Guaranteed`, and this behavior does not activate.

## Example

```yaml theme={null}
apiVersion: rightsizing.kubex.ai/v1alpha1
kind: ClusterAutomationStrategy
metadata:
  name: platform-conservative
spec:
  enablement:
    cpu:
      requests:
        downsize: true
        upsize: true
        setFromUnspecified: true
        floor: 250m
        ceiling: "8"
      limits:
        downsize: false
        upsize: true
        setFromUnspecified: false
    memory:
      requests:
        downsize: true
        upsize: true
        setFromUnspecified: true
        floor: 512Mi
        ceiling: 16Gi
        containers:
          api:
            floor: 1Gi
          worker:
            ceiling: 8Gi
      limits:
        downsize: false
        upsize: true
        setFromUnspecified: true
  inPlaceResize:
    enabled: true
    containerRestart: false
  podEviction:
    enabled: false
  scheduling:
    inclusionWindows:
      - name: overnight-maintenance
        timezone: America/New_York
        weekdays:
          - Mon
          - Tue
          - Wed
          - Thu
          - Fri
        start: "22:00"
        end: "06:00"
    exclusionWindows:
      - name: monday-freeze
        timezone: America/New_York
        weekdays:
          - Mon
        start: "00:00"
        end: "02:00"
  safetyChecks:
    enableResourceQuotaFilter: true
    enableHpaFilter: true
    enableVpaFilter: true
    minCpuChangePercent: 15
    minMemoryChangePercent: 15
    minReadyDuration: 1m
    respectWorkloadMaxUnavailable: true
    requireNodeAllocatable: true
    nodeCpuHeadroom: 15%
    nodeMemoryHeadroom: 512Mi
```

## Notes

* Prefer cluster strategies when one platform-owned policy model should apply across many namespaces.
* Use namespaced `AutomationStrategy` instead when teams should own and evolve resize behavior independently inside their own namespaces.
* For Helm-managed mappings and limits, see [Policy Configuration](https://docs.kubex.ai/docs-kubex/Content/Kubex/automation-engine/policy-configuration.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.