Kubernetes Concepts
Every exported resource declaration becomes a Kubernetes manifest document in the generated YAML. The serializer:
- Resolves the correct
apiVersionandkindfrom the resource type - Converts the export name to a kebab-case
metadata.name - Nests user properties under
spec(or at the top level for specless types like ConfigMap) - Merges default labels and annotations from
defaultLabels()/defaultAnnotations()
Resource structure
Section titled “Resource structure”Every Kubernetes resource has four standard fields:
| Field | Source | Example |
|---|---|---|
apiVersion | Resolved from resource type | apps/v1 |
kind | Resolved from resource type | Deployment |
metadata | From metadata property | { name: "my-app", labels: {...} } |
spec | From spec property or remaining props | Resource-specific configuration |
API groups
Section titled “API groups”K8s resources are organized by API group:
| Group | apiVersion | Resources |
|---|---|---|
| Core | v1 | Pod, Service, ConfigMap, Secret, Namespace, ServiceAccount |
| Apps | apps/v1 | Deployment, StatefulSet, DaemonSet, ReplicaSet |
| Batch | batch/v1 | Job, CronJob |
| Networking | networking.k8s.io/v1 | Ingress, NetworkPolicy |
| RBAC | rbac.authorization.k8s.io/v1 | Role, ClusterRole, RoleBinding, ClusterRoleBinding |
| Autoscaling | autoscaling/v2 | HorizontalPodAutoscaler |
| Policy | policy/v1 | PodDisruptionBudget |
Property types
Section titled “Property types”Nested objects like containers, probes, and volumes are expressed as property types:
import { Deployment, Container, Probe, ResourceRequirements } from "@intentius/chant-lexicon-k8s";
export const app = new Deployment({ metadata: { name: "my-app" }, spec: { replicas: 2, selector: { matchLabels: { app: "my-app" } }, template: { metadata: { labels: { app: "my-app" } }, spec: { containers: [ new Container({ name: "app", image: "my-app:1.0", resources: new ResourceRequirements({ limits: { cpu: "500m", memory: "256Mi" }, requests: { cpu: "100m", memory: "128Mi" }, }), livenessProbe: new Probe({ httpGet: { path: "/healthz", port: 8080 }, initialDelaySeconds: 10, }), }), ], }, }, },});Those property types are classes. Every other object a resource holds, such as DeploymentSpec, ServiceSpec or JobSpec, is an interface in the generated declarations, and you write it as an object literal. In @intentius/chant-lexicon-k8s/types, both check the keys and value types you pass, so spec: { replicas: "three" } is a type error there.
Specless types
Section titled “Specless types”Some K8s resources (ConfigMap, Secret, Namespace, ServiceAccount) don’t have a spec field. Their data goes directly on the manifest:
import { ConfigMap, Secret } from "@intentius/chant-lexicon-k8s";
export const config = new ConfigMap({ metadata: { name: "app-config" }, data: { DATABASE_URL: "postgres://localhost:5432/mydb" },});
export const secret = new Secret({ metadata: { name: "app-secret" }, stringData: { API_KEY: "changeme" },});Default labels and annotations
Section titled “Default labels and annotations”Use defaultLabels() and defaultAnnotations() to inject metadata into all resources:
import { defaultLabels } from "@intentius/chant-lexicon-k8s";
export const labels = defaultLabels({ "app.kubernetes.io/managed-by": "chant", "app.kubernetes.io/part-of": "my-system",});Explicit labels on individual resources take precedence over defaults.
Tip: Avoid hardcoding
metadata.namespace— the WK8001 lint rule will flag it. Use a config variable or pass namespace at deploy time instead.
Telemetry attribution
Section titled “Telemetry attribution”Inside a workspace, the k8s lexicon adds two variables to the env of every container of a Deployment, StatefulSet, DaemonSet, ReplicaSet, Job, CronJob or Pod, so that its spans name the declaration that produced them (#3059, ws-060).
containers: - name: api image: nginx:1.27 env: - name: OTEL_SERVICE_NAME value: api - name: CHANT_RELEASE_ATTRIBUTES valueFrom: fieldRef: fieldPath: metadata.annotations['chant.intentius.io/release-attributes'] - name: OTEL_RESOURCE_ATTRIBUTES value: chant.workspace=acme,chant.member=svc,chant.decl=api$(CHANT_RELEASE_ATTRIBUTES)OTEL_SERVICE_NAME is the workload’s metadata.name. OTEL_RESOURCE_ATTRIBUTES lists chant.workspace, chant.member, chant.decl (the declaration’s export name, which is its node id in chant workspace graph without the member prefix) and, when the build has an environment from --env or ownership.env, deployment.environment.name. A container whose image is pinned by digest (image@sha256:...) also gets service.version. A variable the container already sets is kept, and only the missing attributes are added; one set through valueFrom is left alone. Init containers are not stamped.
The git revision and the release’s digest are set by the deploy, not the build (ws-081). OTEL_RESOURCE_ATTRIBUTES ends with $(CHANT_RELEASE_ATTRIBUTES), which reads the pod annotation chant.intentius.io/release-attributes. A kubectl-apply step in chant run --components sets that annotation on the pod template of each stamped workload in what it applies, adding service.version and vcs.ref.head.revision. Any other apply leaves it absent, which reads as empty, and the manifest does not change with a release.
A project with no chant.workspace.json is unchanged. It can opt in with telemetry.attribution: true in chant.config.ts, which stamps the attributes that need no workspace, and inside a workspace telemetry.attribution: false turns it off.