Skip to content
Install the CLI

How-to guide Author packages and clusters

Declare package roles and metadata

Add meta beside a package’s options and build attributes:

how-to/composition/config-package.nix
meta = {
version = "1.0.0";
description = "Configuration owned by an application team";
owner = "platform";
lifecycle = "stateless";
scope = "namespace";
};

View source on GitHub ↗

Use these fields to describe the package:

  • version identifies the package version shown by inspection commands and in PackageInstance records.
  • description gives the package a short human-readable purpose.
  • owner identifies the team responsible for it and supports governance scorecard rules.
  • lifecycle classifies its state as stateless, stateful, durable, or ephemeral. Kix records the value in the kix.run/lifecycle annotation. Only "stateful" changes evaluation and deployment behavior: custom resources in a "stateful" package must declare holdsData, and replacing a data-holding resource in a "stateful" package triggers the deployment migration gate. Other values are descriptive only.
  • scope says which namespaces may use the package. A package argument is filled from the consumer’s own namespace. An instance in another namespace is used only when the cluster definition names it, with deps.<arg> = ref.<namespace>.<instance>, or when the provider’s package serves the whole cluster. A package serves the whole cluster when it sets meta.scope = "cluster", claims a role in meta.roles, or declares meta.conflictsWith on a cluster: key; operators, ingress controllers, and certificate issuers are the usual cases. Stand-ins made with kix.mkImport serve the whole cluster unless they set scope = "namespace"; when several imports answer one name, name the one you mean with ref. meta.scope = "cluster" also makes auto-instantiation place the package once per cluster. An instance that Kix creates from availablePackages or enables via optional = true to satisfy a dependency binds from any namespace, unless its scope is "namespace". meta.scope = "namespace" goes the other way: the package is never used from another namespace, not even with ref. Databases, caches, and anything that hands out a Secret leave scope unset, so a consumer in another namespace names the instance it means.

version, description, and owner describe the package. lifecycle and scope affect evaluation and deployment behavior, so choose them carefully.

Add meta.roles only when the package provides one of Kix’s registered cluster infrastructure roles. This minimal provider claims the storageClasses role:

how-to/composition/storage-provider.nix
meta = {
version = "1.0.0";
description = "Default StorageClass for the composition example";
owner = "platform";
roles = [ "storageClasses" ];
};

View source on GitHub ↗

Registered roles are also dependency-resolution aliases. Kix validates role names, prevents conflicting providers, and checks any required out attributes when a consumer resolves the role.

The storageClasses role requires an exported storageClassName, so the package root supplies it:

how-to/composition/storage-provider.nix
root = {
resource = self.storageClass;
out.storageClassName = self.storageClass.out.name;
};

View source on GitHub ↗

Do not use roles as general package tags. Ordinary application dependencies are resolved through instance names, aliases, or explicit deps wiring.

Run the normal checks after adding or changing metadata:

kix-examples/
❱ kix check how-to-composition
 TOOL       RESULT  DETAILS                      
 eval       pass    15 manifests evaluated       
 scorecard  pass    0 errors, 0 warnings, 0 info

Evaluation fails if a role name is unknown, two managed packages claim the same role, or a resolved provider does not satisfy the role’s output contract.