Reference

Every callable in the library, generated from the same catalog the Assembler reads — so it never drifts from the code. The catalog itself is published at /catalog.json for programmatic use.

Workloads

Deployable starting points. Import a stage by its canonical path, compose + features, and render with kurly.list.

cnpg-cluster

A highly-available PostgreSQL cluster as a CloudNativePG Cluster custom resource (three instances, a bootstrapped database, a PodMonitor). Requires the CloudNativePG operator.

cluster cnpg

The PostgreSQL Cluster CR. Adapt it with the parameters and render with kurly.list — composed by parameter, not by + feature (it is a custom resource, not a base kind).

Import: import 'github.com/metio/kurly/workloads/cnpg-cluster/cluster.libsonnet'

ParameterTypeRequiredDefault
namestring"postgres"
instancesint3
storageSizequantity"10Gi"
databasestring"app"

tik

A lightweight ticket board and release supervisor. One process serves a read-only board and runs the store's writers over a shared append-only event store.

backend http

The tik backend supervisor: a single-writer http app over a ReadWriteOnce store (one replica, recreated to avoid deadlocking on the volume). Compose an exposure recipe to serve the board.

Import: import 'github.com/metio/kurly/workloads/tik/backend.libsonnet'

ParameterTypeRequiredDefault
imagestring"ghcr.io/metio/tik:2026.7.14194001"

valkey

A persistent Valkey server (the BSD Redis fork) on the official upstream image, as a kurly.stateful workload with a per-pod PVC and a headless Service. Single-instance stage; a Redis-compatible alternative runs by overriding the image.

cache worker

An in-memory Valkey cache that upgrades its version with zero downtime and no data loss, on the stock image and no orchestrator — the replication hand-off lives entirely in the pod manifests (headless Service, maxSurge, an initContainer that replicates the running peer, and a preStop failover).

Import: import 'github.com/metio/kurly/workloads/valkey/cache.libsonnet'

ParameterTypeRequiredDefault
imagestring"docker.io/valkey/valkey:8"
maxMemorystring"256mb"

instance stateful

The single-instance Valkey server: a StatefulSet with append-only persistence into a volumeClaimTemplate. Compose + features as usual (it is a composable kurly.stateful app).

Import: import 'github.com/metio/kurly/workloads/valkey/instance.libsonnet'

ParameterTypeRequiredDefault
imagestring"docker.io/valkey/valkey:8"
storageSizequantity"1Gi"

Kinds

The base workload each recipe starts from.

kurly.cron(name, image, schedule)

A scheduled job: a CronJob that runs to completion on a cron schedule.

ParameterTypeRequiredDefaultExample
namestringyes"nightly-report"
imagestringyes"ghcr.io/acme/report:1.2.3"
schedulestringyes"0 2 * * *"

kurly.daemon(name, image)

A per-node agent: a DaemonSet running one pod on every node.

ParameterTypeRequiredDefaultExample
namestringyes"node-exporter"
imagestringyes"ghcr.io/acme/node-agent:1.2.3"

kurly.http(name, image)

An HTTP workload: a Deployment (2 replicas) and a ClusterIP Service. Compose an exposure feature to accept traffic from outside the cluster.

ParameterTypeRequiredDefaultExample
namestringyes"storefront"
imagestringyes"ghcr.io/acme/storefront:1.2.3"

kurly.job(name, image)

A one-off task that runs to completion: a Job with restartPolicy OnFailure. No Service, no replicas.

ParameterTypeRequiredDefaultExample
namestringyes"db-migrate"
imagestringyes"ghcr.io/acme/migrate:1.2.3"

kurly.stateful(name, image)

A workload with stable identity and per-pod storage: a StatefulSet plus the headless Service that names it. The store feature renders as a per-pod volumeClaimTemplate.

ParameterTypeRequiredDefaultExample
namestringyes"postgres"
imagestringyes"ghcr.io/acme/postgres:16"

kurly.worker(name, image)

A background worker: a Deployment with no Service. Reaches out (queues, schedules) rather than serving traffic.

ParameterTypeRequiredDefaultExample
namestringyes"indexer"
imagestringyes"ghcr.io/acme/indexer:1.2.3"

Features

Composable + capabilities. Each contributes only to the merged config, so features late-bind regardless of compose order.

container

kurly.annotations(annotations)

Extra annotations on metadata and the pod template.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
annotationsobjectyes{"prometheus.io/scrape":"true"}

kurly.args(args)

Appends arguments to the image's own entrypoint — typically a subcommand selecting the workload.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
argsarrayyes["backend","--config=/etc/tik/pipelines.edn"]

kurly.command(command)

Overrides the image entrypoint entirely.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
commandarrayyes["/bin/app"]

kurly.env(env)

Environment variables as a name→value map, appended to the container.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
envobjectyes{"LOG_LEVEL":"info"}

kurly.image(image)

Overrides the container image.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
imagestringyes"ghcr.io/acme/app:1.2.3"

kurly.imagePullSecrets(names)

Names of existing Secrets the kubelet uses to pull the image.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
namesarrayyes["regcred"]

kurly.initContainer(container)

An init container run to completion before the main one — the full container spec, passed through. Composes more than once.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
containerobjectyes{"command":["sh","-c","echo ready"],"image":"busybox:1","name":"setup"}

kurly.labels(labels)

Extra labels on metadata and the pod template (never on immutable selectors).

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
labelsobjectyes{"team":"payments"}

kurly.lifecycle(preStop, postStart)

Container lifecycle handlers (postStart / preStop), passed through verbatim.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
preStopobject{"exec":{"command":["sh","-c","valkey-cli failover"]}}
postStartobject

kurly.livenessProbe(probe)

An explicit liveness probe spec (exec/tcpSocket/httpGet), overriding the default http probe.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
probeobjectyes{"tcpSocket":{"port":6379}}

kurly.podAnnotations(podAnnotations)

Annotations on the pod template ONLY — for sidecar injection and scrape hints that are meaningless on the controller object.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
podAnnotationsobjectyes{"linkerd.io/inject":"enabled"}

kurly.podLabels(podLabels)

Labels on the pod template ONLY (never the workload metadata or the immutable selector) — for network-policy selectors and log collection.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
podLabelsobjectyes{"tier":"database"}

kurly.port(port)

The container port the workload listens on (also the Service target).

kinds: http
ParameterTypeRequiredDefaultExample
portintyes8080

kurly.priorityClassName(priorityClassName)

The pod's scheduling priority class.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
priorityClassNamestringyes"high-priority"

kurly.probes(path)

HTTP readiness and liveness probes on the named http port.

kinds: http
ParameterTypeRequiredDefaultExample
pathpath"/healthz""/tickets.edn"

kurly.readinessProbe(probe)

An explicit readiness probe spec (exec/tcpSocket/httpGet), overriding the default http probe.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
probeobjectyes{"exec":{"command":["sh","-c","valkey-cli ping"]}}

kurly.recreate()

The single-writer strategy: tears the old pod down before starting the new one, so a ReadWriteOnce store never deadlocks a rollout.

kinds: http, worker

kurly.replicas(replicas)

The desired number of pod replicas.

kinds: http, worker, stateful
ParameterTypeRequiredDefaultExample
replicasintyes3

kurly.resourcePreset(preset)

A named resource size (nano/micro/small/medium/large) — a memory request equal to its limit and a CPU request with no limit. Replaces resources wholesale.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
presetstringyes"small"

kurly.resources(requests, limits)

Container resource requests and/or limits.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
requestsobject{"cpu":"100m","memory":"128Mi"}
limitsobject{"memory":"256Mi"}

kurly.rollingUpdate(maxSurge, maxUnavailable)

RollingUpdate tuning so a new pod surges alongside the old during an update — the overlap a replication hand-off needs.

kinds: http, worker
ParameterTypeRequiredDefaultExample
maxSurgeany1
maxUnavailableany

kurly.serviceAccount(serviceAccountName)

Runs the pod under a named ServiceAccount (also gates token automount).

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
serviceAccountNamestringyes"storefront"

kurly.strategy(strategy)

The Deployment update strategy.

kinds: http, worker
ParameterTypeRequiredDefaultExample
strategystringyes"RollingUpdate"

kurly.terminationGracePeriod(seconds)

How long the pod gets to shut down gracefully (a preStop hook's window).

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
secondsintyes120

kurly.version(version)

The workload version, stamped as app.kubernetes.io/version on every object.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
versionstringyes"1.2.3"

networking

kurly.headlessService(port, publishNotReady)

A headless Service (clusterIP: None) selecting the pods, for DNS peer discovery — the discovery a replication hand-off needs.

kinds: http, worker, daemon, stateful
ParameterTypeRequiredDefaultExample
portint6379
publishNotReadyboolfalse

kurly.networkPolicy(ingress, egress, policyTypes)

A NetworkPolicy firewalling the pods (ingress/egress rules and policyTypes passed through verbatim).

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
ingressarray
egressarray
policyTypesarray

observability

kurly.serviceMonitor(port, path, interval)

A Prometheus-Operator ServiceMonitor scraping the workload Service.

kinds: http
ParameterTypeRequiredDefaultExample
portstring"http"
pathpath"/metrics"
intervalstring

placement

kurly.affinity(affinity)

A pod/node affinity object, merged onto the pod template.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
affinityobjectyes{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"disktype","operator":"In","values":["ssd"]}]}]}}}

kurly.nodeSelector(nodeSelector)

Restricts the pod to nodes carrying these labels.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
nodeSelectorobjectyes{"disktype":"ssd"}

kurly.tolerations(tolerations)

Tolerations letting the pod schedule onto tainted nodes.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
tolerationsarrayyes[{"effect":"NoSchedule","key":"gpu","operator":"Exists"}]

kurly.topologySpread(constraints)

Topology-spread constraints spreading the pods across a topology domain (keep version-bound labels in the selector so a rollout spreads the new set independently).

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
constraintsarrayyes[{"labelSelector":{"matchLabels":{"app.kubernetes.io/name":"web"}},"maxSkew":1,"topologyKey":"kubernetes.io/hostname","whenUnsatisfiable":"DoNotSchedule"}]

reliability

kurly.hpa(minReplicas, maxReplicas, targetCPU, targetMemory)

A HorizontalPodAutoscaler scaling the Deployment on CPU and/or memory utilization.

kinds: http, worker
ParameterTypeRequiredDefaultExample
minReplicasintyes2
maxReplicasintyes10
targetCPUint80
targetMemoryint

kurly.pdb(minAvailable, maxUnavailable)

A PodDisruptionBudget capping voluntary disruption. Set one of minAvailable / maxUnavailable.

kinds: http, worker, daemon, stateful
ParameterTypeRequiredDefaultExample
minAvailableany1
maxUnavailableany

scheduling

kurly.concurrencyPolicy(concurrencyPolicy)

How to treat a job that is still running when the next is due (Allow/Forbid/Replace).

kinds: cron
ParameterTypeRequiredDefaultExample
concurrencyPolicystringyes"Forbid"

kurly.schedule(schedule)

The cron schedule expression.

kinds: cron
ParameterTypeRequiredDefaultExample
schedulestringyes"0 2 * * *"

security

kurly.hostUsers()

Shares the host user namespace (relaxes hostUsers=false).

kinds: http, worker, cron, daemon, stateful, job

kurly.rbac(rules)

Mints a ServiceAccount, a namespaced Role with the given rules, and the RoleBinding, and runs the pod under that ServiceAccount.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
rulesarrayyes[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get","list","watch"]}]

kurly.rootUser()

Allows the container to run as root (relaxes runAsNonRoot).

kinds: http, worker, cron, daemon, stateful, job

kurly.runAs(uid, gid, fsGroup)

Pins the run-as user/group (and matching fsGroup) for images that do not declare a non-root USER.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
uidintyes12345
gidint
fsGroupint

kurly.writableRootFilesystem()

Makes the root filesystem writable (relaxes readOnlyRootFilesystem).

kinds: http, worker, cron, daemon, stateful, job

storage

kurly.config(files, mountPath)

Renders a ConfigMap from a filename→content map and mounts it read-only.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
filesobjectyes{"app.conf":"key = value"}
mountPathpath"/etc/config"

kurly.scratch(mountPath, sizeLimit)

A writable emptyDir — the escape valve a read-only root filesystem needs for /tmp and the like.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
mountPathpathyes"/tmp"
sizeLimitquantity

kurly.secretMount(secretName, mountPath, readOnly, optional, defaultMode)

Mounts an EXISTING Secret (kurly never mints key material).

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
secretNamestringyes"tik-tls"
mountPathpathyes"/etc/tls"
readOnlybooltrue
optionalboolfalse
defaultModeint

kurly.store(mountPath, size, accessModes, storageClass, selector, annotations)

The workload's own PersistentVolumeClaim, mounted at a path.

kinds: http, worker, cron, daemon, stateful, job
ParameterTypeRequiredDefaultExample
mountPathpathyes"/var/lib/tik"
sizequantityyes"1Gi"
accessModesarray["ReadWriteOnce"]
storageClassstring
selectorobject
annotationsobject

Exposure

Routing recipes composed onto an http workload. All join the exposure exclusion group — one exposure per workload.

kurly.expose.gateway(host, gateway, gatewayNamespace, sectionName)

Attaches an HTTPRoute to an existing shared Gateway (the usual platform-team setup).

kinds: httpexclusive: exposurerequires a Service
ParameterTypeRequiredDefaultExample
hosthostnameyes"storefront.example.com"
gatewaystringyes"shared"
gatewayNamespacestring
sectionNamestring

kurly.expose.ingress(host, ingressClass)

Routes the host to the workload through the Ingress API.

kinds: httpexclusive: exposurerequires a Service
ParameterTypeRequiredDefaultExample
hosthostnameyes"storefront.example.com"
ingressClassstring

kurly.expose.listenerSet(host, listenerSet, listenerSetNamespace, sectionName)

Attaches an HTTPRoute to an existing ListenerSet (per-tenant listener ownership).

kinds: httpexclusive: exposurerequires a Service
ParameterTypeRequiredDefaultExample
hosthostnameyes"storefront.example.com"
listenerSetstringyes"tenant-a"
listenerSetNamespacestring
sectionNamestring

kurly.expose.ownGateway(host, gatewayClass)

Generates a dedicated Gateway plus the HTTPRoute — for clusters with no shared Gateway to attach to.

kinds: httpexclusive: exposurerequires a Service
ParameterTypeRequiredDefaultExample
hosthostnameyes"storefront.example.com"
gatewayClassstringyes"istio"

kurly.expose.ownListenerSet(host, gateway, gatewayNamespace)

Generates a ListenerSet that adds the workload's own listener to a shared Gateway, plus the HTTPRoute. The Gateway must opt in via spec.allowedListeners.

kinds: httpexclusive: exposurerequires a Service
ParameterTypeRequiredDefaultExample
hosthostnameyes"storefront.example.com"
gatewaystringyes"shared"
gatewayNamespacestring

Security

Pod Security Standards profiles, composed as mixins. The last profile composed wins; single-knob hatches (in Features) fine-tune after it.

kurly.security.baseline

Relaxes what only restricted requires (root allowed, default capabilities kept, privilege escalation and unpinned seccomp permitted); keeps the read-only root filesystem and user namespaces.

kurly.security.privileged

Emits no security fields at all — the manifest constrains nothing.

kurly.security.restricted

The default posture, written out. Compose after another profile to re-tighten.

Helpers

Rendering terminals — turn a composed app or an explicit set of parts into the output a consumer applies or publishes.

kurly.join(parts)

Builds one flat array from parts that may be null (dropped) or nested arrays (flattened one level), for assembling any value with conditionals and optional groups. A Jsonnet `if` with no else is null when false, so an unmet condition drops out.

ParameterTypeRequiredDefaultExample
partsarrayyes

kurly.list(app)

Renders one composed app as a kind: List, including its hidden owned manifests (the store PVC, the config ConfigMap).

ParameterTypeRequiredDefaultExample
appobjectyes

kurly.listOf(parts)

Renders an explicit set of parts as a kind: List. Joins the parts first, so entries can be null (dropped) or nested arrays (flattened) — build the set with conditionals and optional groups.

ParameterTypeRequiredDefaultExample
partsarrayyes