Getting started
Cloudcoil is a typed Kubernetes client and an async controller framework for Python
3.14. Use ordinary resource classes for API calls, then add a Controller when
something must continuously converge.
Install
uv add 'cloudcoil[kubernetes]'
# Add HTTPS hosting when your operator has admission policies:
uv add 'cloudcoil[operator,kubernetes]'
Select a Kubernetes model version for your cluster, following the support and versioning policy. Installing models supplies Python types; it does not install a cluster or CRDs.
Run the checkout
This guide follows repository source, including APIs that may not yet be published. From the repository root, install the development environment and matching models:
uv sync --group dev --extra codegen --extra kubernetes
uv run --no-sync python tools/generate_kubernetes.py \
--version 1.37.0 --output .build/kubernetes-models
uv pip install --no-deps .build/kubernetes-models
The checked-in development lockfile has a bootstrap model dependency. Use
uv run --no-sync after installing generated models so uv does not restore it.
For an application using published releases, install a compatible model package
normally; local generation is only needed when developing against this checkout.
Use your existing kubeconfig locally; applications in Kubernetes use their
ServiceAccount. The commands below target the default namespace.
Read a resource
from cloudcoil.models.kubernetes.core.v1 import Pod
pods = Pod.list(namespace="default")
for pod in pods.items:
print(pod.name)
Async applications use await Pod.async_list(namespace="default"). See
resource operations for writes, watches, pagination and builders,
and logs for workload log collection.
Write a controller
Save this as app.py:
from cloudcoil.models.kubernetes.core.v1 import ConfigMap
from cloudcoil.application import Application
app = Application("configmap-labeler")
configs = app.controller(ConfigMap, label_selector="example.com/manage=true")
@configs.reconcile()
async def reconcile(config: ConfigMap) -> ConfigMap:
config.data = {**(config.data or {}), "managed-by": "cloudcoil"}
return config
if __name__ == "__main__":
app.main()
Return the changed resource; Cloudcoil patches only differences and skips unchanged writes. Watches, retries, concurrency and shutdown are managed by the runtime.
export CLOUDCOIL_NAMESPACE=default
uv run --no-sync python app.py manifests # Review generated RBAC, without API access.
uv run --no-sync python app.py run
In another terminal, create a selected object:
kubectl -n default create configmap example --from-literal=message=hello
kubectl -n default label configmap example example.com/manage=true
kubectl -n default get configmap example -o yaml
Its data gains managed-by: cloudcoil. Stop the foreground controller with Ctrl-C.
For deployment, use operator installation to generate the
ServiceAccount, RBAC and Deployment for your application image.
Build an operator
Follow these guides in order:
- Custom resources: define a CRD with Pydantic fields.
- Controllers: reconcile, manage children and finalize objects.
- Stages and reporting: structure work, status and Events.
- Live clients and informer reads: read related resources explicitly.
- Admission: default or validate writes, with or without a controller.
- Deployment: generate manifests, install and run.
The Widget demo is a complete CRD and operator with three child kinds, readiness, TLS and admission. The pattern guide covers shared dependencies, existing resources, pruning, finalizers and multiple controllers.