Skip to content

Resource labels

Everything kube-agents installs into a cluster carries the Kubernetes recommended labels, so the project’s whole footprint is selectable in one query:

Terminal window
kubectl get all,configmap,pvc,serviceaccount,secret -A \
-l app.kubernetes.io/part-of=kube-agents

Every install path sets name, instance, part-of, and managed-by:

Source name instance part-of managed-by
PlatformAgent controller output (per CR) platform-agent <namespace>-<agent name> kube-agents platformagent-controller
Operator install (k8s-operator/config/) kube-agents-operator kube-agents-operator kube-agents kustomize
Helm chart (charts/kube-agents/) kube-agents, kube-agents-operator, or litellm <release name> kube-agents Helm
LiteLLM integration litellm litellm kube-agents kustomize
GitHub token minter github-token-minter github-token-minter kube-agents kustomize
Inference replay inference-replay inference-replay kube-agents kustomize
Hindsight memory store hindsight hindsight kube-agents kustomize

component is set by one source only, Hindsight, and everywhere else by nothing: the object’s own name already says what it is, and a second key that has to stay consistent with the first is a key that eventually disagrees with it. Hindsight is the exception because it is one integration with two unrelated workloads — an API server and its Postgres database — so name alone cannot tell them apart. Its objects carry app.kubernetes.io/component: api or postgresql, and those values are load-bearing rather than decorative: the Deployment and StatefulSet selectors, the NetworkPolicy that lets only the API reach port 5432, and the PodMonitoring that must scrape the API and not the database are all built from them. Do not add component anywhere else on the strength of this.

version is set only by the Helm chart, which fills it from Chart.AppVersion — a chart release is pinned to exactly one application release, so there is a correct value to write. See Release versioning. No other path sets it. The controller writes objects whose version is whatever image the CR asked for, and an image reference may carry a digest, whose @ and : are not legal in a label value; the kustomizations have no build identity to report at all. A version label that is present on some of the footprint and absent from the rest is worse than one that is consistently absent, so select on image references, not on this label, when you need to know what is actually running.

instance carries the namespace for controller-created objects because the controller also writes cluster-scoped ClusterRoles and ClusterRoleBindings, where a bare CR name is ambiguous between two agents of the same name in different namespaces. Nothing bounds a PlatformAgent name to a length that fits a label value, so the joined value is truncated to 63 characters. The singleton installs use instance == name; there is only one per cluster.

managed-by names the thing that writes the object, so you can tell an object the operator reconciles from one a human applied with kustomize or one Helm rendered.

Objects the Platform Agent authors at runtime through its skills are user workloads, not project infrastructure, and do not get these labels. Those carry the kubeagents.x-k8s.io/requested-by annotation instead — see User attribution for why per-requester identity belongs in an annotation rather than a label.

CRDs installed by the Helm chart are also unlabelled. Helm applies everything in a chart’s crds/ directory verbatim and never renders it as a template, and those files are byte-for-byte copies of k8s-operator/config/crd/bases/ enforced by make chart-check, so there is nowhere to put the labels. Installing the CRDs through k8s-operator/config/crd/ instead does label them — that kustomization sets the four keys itself.

Three constraints shape how the labels are applied, and all three matter when upgrading an existing install:

  • Selectors are never touched. Deployment and StatefulSet spec.selector is immutable, so adding a label there would make the API server reject the update on every existing install. The controller keeps app: <name>-gateway as the sole selector key, and every kustomization sets includeSelectors: false. Do not “tidy” this by adding the recommended labels to a selector.
  • Pod templates do get the labels, which changes the pod template hash and therefore causes one rollout of the agent Deployment the first time you upgrade to a version that includes them. This is expected and happens once. The same applies to an existing Hindsight install, where it restarts both the API and the Postgres pod — the database lives on data-hindsight-postgresql-0, which the restart does not touch, so no memories are lost, but memory is briefly unavailable while Postgres and the API’s models reload.
  • volumeClaimTemplates are never touched either, and this one is a trap rather than a choice. Kustomize’s includeTemplates: true does not label only pod templates: on a StatefulSet it also labels spec.volumeClaimTemplates[].metadata, which is among the fields the API server refuses to update after creation. The object is then rejected whole, with updates to statefulset spec for fields other than 'replicas' ... are forbidden. A fresh install accepts it and only upgrades break, so it is invisible until someone has one. The Hindsight kustomization — the only one here with a StatefulSet — therefore sets includeTemplates: false and patches the two pod templates directly instead.

PersistentVolumeClaims are created once and never updated by the controller, so claims that existed before the upgrade stay unlabelled until they are recreated. They will not appear in the -l app.kubernetes.io/part-of=kube-agents query above. The constraint above means Hindsight’s claim stays unlabelled permanently, not just until recreation.

Claims backed by a volumeClaimTemplates entry are permanently unlabelled for the same reason wherever they come from, not only under Kustomize: buildRWOVolumeClaimTemplates sets a name and nothing else on the template’s metadata, so an agent declaring RWO spec.deployment.storages gets claims the part-of query cannot reach either. Claims the controller creates directly — <agent>-data, system-metadata, and non-RWO custom storage — go through withCommonLabels and are labelled.

Everything one PlatformAgent owns, including its cluster-scoped RBAC:

Terminal window
AGENT_INSTANCE=kubeagents-system-platform-agent
kubectl get all,configmap,pvc,serviceaccount,secret -A -l "app.kubernetes.io/instance=$AGENT_INSTANCE"
kubectl get clusterrole,clusterrolebinding -l "app.kubernetes.io/instance=$AGENT_INSTANCE"

Only what the operator reconciles, excluding anything applied by hand:

Terminal window
kubectl get all -A -l app.kubernetes.io/managed-by=platformagent-controller

Just the integrations:

Terminal window
kubectl get all -A \
-l 'app.kubernetes.io/part-of=kube-agents,app.kubernetes.io/name in (litellm,github-token-minter,inference-replay,hindsight)'

Cluster-scoped RBAC the project owns — the objects most easily orphaned, since a namespaced PlatformAgent cannot own a cluster-scoped resource through an owner reference:

Terminal window
kubectl get clusterrole,clusterrolebinding -l app.kubernetes.io/part-of=kube-agents
  • User attribution — annotations that connect an object to the human who asked for it.
  • Security & IAM — what the agent is and is not permitted to do.