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:
kubectl get all,configmap,pvc,serviceaccount,secret -A \ -l app.kubernetes.io/part-of=kube-agentsThe label contract
Section titled “The label contract”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.
What is not labelled
Section titled “What is not labelled”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.
Upgrade notes
Section titled “Upgrade notes”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.selectoris immutable, so adding a label there would make the API server reject the update on every existing install. The controller keepsapp: <name>-gatewayas the sole selector key, and every kustomization setsincludeSelectors: 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. volumeClaimTemplatesare never touched either, and this one is a trap rather than a choice. Kustomize’sincludeTemplates: truedoes not label only pod templates: on a StatefulSet it also labelsspec.volumeClaimTemplates[].metadata, which is among the fields the API server refuses to update after creation. The object is then rejected whole, withupdates 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 setsincludeTemplates: falseand 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.
Query recipes
Section titled “Query recipes”Everything one PlatformAgent owns, including its cluster-scoped RBAC:
AGENT_INSTANCE=kubeagents-system-platform-agentkubectl 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:
kubectl get all -A -l app.kubernetes.io/managed-by=platformagent-controllerJust the integrations:
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:
kubectl get clusterrole,clusterrolebinding -l app.kubernetes.io/part-of=kube-agentsWhere to go next
Section titled “Where to go next”- 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.