# ModelCache

Source: /reference/modelcaches/

Stage model weights on cluster storage before serving.

Apply instances as `apiVersion: modelplane.ai/v1alpha1`, `kind: ModelCache`.

[Concept guide: Cache Model Weights](/models/model-cache/index.md)

## Example

```yaml
apiVersion: modelplane.ai/v1alpha1
kind: ModelCache
metadata:
  name: qwen-72b
  namespace: ml-team
spec:
  source: HuggingFace
  huggingFace:
    repo: Qwen/Qwen2.5-72B-Instruct
    sizeGiB: 150
    authSecret:
      name: hf-token
      key: HF_TOKEN
```

## Definition

The CompositeResourceDefinition this reference is generated from, with the complete OpenAPI schema, validation rules, and defaults:

```yaml
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
  name: modelcaches.modelplane.ai
spec:
  group: modelplane.ai
  names:
    categories: [crossplane, modelplane, models]
    kind: ModelCache
    plural: modelcaches
    shortNames: [mc]
  scope: Namespaced
  versions:
  - name: v1alpha1
    served: true
    referenceable: true
    additionalPrinterColumns:
    - name: REPO
      type: string
      jsonPath: .spec.huggingFace.repo
    - name: STAGED
      type: string
      jsonPath: .status.summary.ready
    schema:
      openAPIV3Schema:
        type: object
        required: [spec]
        properties:
          spec:
            type: object
            required: [source]
            x-kubernetes-validations:
            - rule: "self.source != 'HuggingFace' || has(self.huggingFace)"
              message: spec.huggingFace is required when spec.source is HuggingFace.
            properties:
              source:
                type: string
                enum: [HuggingFace]
                description: >-
                  Which kind of artifact source to stage from. The
                  matching source object (e.g. spec.huggingFace) must
                  be set.
              huggingFace:
                type: object
                description: >-
                  HuggingFace source. Required when source is
                  HuggingFace. The cache downloads once, so repo,
                  revision, include and exclude can't change after
                  the ModelCache is created.
                required: [repo, sizeGiB]
                # The cache downloads once, so a changed source would
                # report Ready without the files it names. A field that
                # is absent compares as empty, so adding or removing one
                # is a change too.
                x-kubernetes-validations:
                - rule: "self.repo == oldSelf.repo"
                  message: Create a new ModelCache to change spec.huggingFace.repo.
                - rule: >-
                    (has(self.revision) ? self.revision : '') ==
                    (has(oldSelf.revision) ? oldSelf.revision : '')
                  message: Create a new ModelCache to change spec.huggingFace.revision.
                - rule: >-
                    (has(self.include) ? self.include : []) ==
                    (has(oldSelf.include) ? oldSelf.include : [])
                  message: Create a new ModelCache to change spec.huggingFace.include.
                - rule: >-
                    (has(self.exclude) ? self.exclude : []) ==
                    (has(oldSelf.exclude) ? oldSelf.exclude : [])
                  message: Create a new ModelCache to change spec.huggingFace.exclude.
                properties:
                  repo:
                    type: string
                    description: HuggingFace repository ID.
                    minLength: 1
                  revision:
                    type: string
                    description: >-
                      Branch, tag, or commit SHA. Defaults to the
                      repo's default branch.
                  authSecret:
                    type: object
                    description: >-
                      Optional Secret holding an HF token for gated or
                      private repos. Names a Secret in the ModelCache's
                      own namespace; Modelplane propagates it to each
                      matched cluster for the hydration Job to read.
                    required: [name]
                    properties:
                      name:
                        type: string
                        minLength: 1
                      key:
                        type: string
                        default: HF_TOKEN
                  include:
                    type: array
                    description: >-
                      Glob patterns of the files to download, such as
                      "*.safetensors". Each is passed to hf download as
                      --include. Downloads every file in the repository
                      when unset.
                    maxItems: 32
                    items:
                      type: string
                      minLength: 1
                  exclude:
                    type: array
                    description: >-
                      Glob patterns of the files not to download, such as
                      "original/*". Each is passed to hf download as
                      --exclude.
                    maxItems: 32
                    items:
                      type: string
                      minLength: 1
                  sizeGiB:
                    type: integer
                    description: >-
                      Capacity to allocate for the staged artifact on
                      each matched cluster.
                    minimum: 1
                    maximum: 100000
              clusterSelector:
                type: object
                description: >-
                  Label selector to pick the InferenceClusters that
                  stage this artifact. If omitted, the cache replicates
                  to every cluster.
                properties:
                  matchLabels:
                    type: object
                    additionalProperties:
                      type: string
          status:
            type: object
            properties:
              conditions:
                type: array
                items:
                  type: object
              summary:
                type: object
                description: Per-cluster ready / total counts.
                properties:
                  ready:
                    type: string
                    description: e.g. "2/3"
              clusters:
                type: array
                description: Per-cluster staging status.
                items:
                  type: object
                  required: [name]
                  properties:
                    name:
                      type: string
                    phase:
                      type: string
                      enum: [Pending, Hydrating, Ready, Failed]
                    message:
                      type: string
                      description: >-
                        Why the model isn't readable on this cluster yet,
                        while phase isn't Ready.
                    mount:
                      type: object
                      description: >-
                        How an engine pod reads the model on this cluster.
                        Set only while phase is Ready. A ModelReplica adds
                        these to each of its engine pods.
                      properties:
                        volumes:
                          type: array
                          description: >-
                            Pod volumes, each a subset of a Kubernetes
                            Volume.
                          maxItems: 8
                          items:
                            type: object
                            required: [name]
                            properties:
                              name:
                                type: string
                              persistentVolumeClaim:
                                type: object
                                required: [claimName]
                                properties:
                                  claimName:
                                    type: string
                        volumeMounts:
                          type: array
                          description: >-
                            Container volume mounts, each a subset of a
                            Kubernetes VolumeMount.
                          maxItems: 8
                          items:
                            type: object
                            required: [name, mountPath]
                            properties:
                              name:
                                type: string
                              mountPath:
                                type: string
                              readOnly:
                                type: boolean
                        env:
                          type: array
                          description: >-
                            Container environment variables. A variable the
                            engine sets itself takes precedence.
                          maxItems: 8
                          items:
                            type: object
                            required: [name, value]
                            properties:
                              name:
                                type: string
                              value:
                                type: string
```
