Version tags, GHCR images, digest-pinned install.yaml, upgrades, and uninstall.

Release and image versioning

The current public release is v0.1.0-alpha.2. Kontext releases use SemVer-compatible git tags:

vMAJOR.MINOR.PATCH
vMAJOR.MINOR.PATCH-PRERELEASE

Build metadata suffixes (+...) are not supported because they are not valid OCI tag characters.

Published images

Each release publishes the same tag for four public GHCR images:

ghcr.io/mfs-code/kontext-operator:<release-tag>
ghcr.io/mfs-code/kontext-echo:<release-tag>
ghcr.io/mfs-code/kontext-reporter:<release-tag>
ghcr.io/mfs-code/kontext-reference:<release-tag>

Every image index includes linux/amd64 and linux/arm64. Releases do not publish mutable latest or dev tags. The workflow refuses to overwrite an existing release image tag, verifies anonymous pulls, and attaches an image-digests.json asset containing immutable image@sha256:... references.

GitHub provides no API to change container package visibility, so each GHCR package must be made public once, manually, in its package settings on GitHub. Visibility persists across pushes. The workflow verifies that every package is public and fails with a link to the settings page if one is not. Publication fails before a GitHub release is created if anonymous access cannot be verified.

Install

Install a tagged release on an existing cluster without cloning the repository or building images:

VERSION=v0.1.0-alpha.2
kubectl apply -f \
  "https://github.com/MFS-code/Kontext/releases/download/${VERSION}/install.yaml"

install.yaml contains the CRDs, Namespace, RBAC, controller Deployment, webhook Service, NetworkPolicy, and narrow admission registration. It contains no certificate or private key. The controller creates and rotates the namespaced TLS Secret after installation. Its operator and trusted reporter references use the immutable digests recorded in image-digests.json, while app.kubernetes.io/version and kontext.dev/release retain the human-readable release tag.

The registration matches only sparse referenced AgentRun CREATE requests. It fails matching requests closed, uses a five-second timeout, and leaves complete standalone and controller-created runs outside the webhook. Every controller replica reconciles the shared TLS Secret and registration, reloads renewed serving certificates, and must agree with the registered CA bundle before becoming ready.

Webhook permissions are split from controller reconciliation and leader election. A namespaced Role manages only the TLS Secret. A separate ClusterRole manages only the named MutatingWebhookConfiguration, except that Kubernetes RBAC cannot name-scope the create verb. The release NetworkPolicy is ingress-only and selects controller Pods for webhook port 9443 and health port 8081. It does not restrict AgentRun workloads or controller egress.

Given a downloaded digest manifest, the release artifact is reproducible from the tagged source:

make release-manifest IMAGE_DIGESTS=image-digests.json

Upgrade between alpha releases

v1alpha1 does not imply compatibility between Kontext distribution versions. Read the target release notes first, especially any CRD schema, defaulting, runtime-contract, or status changes. Back up custom resources before upgrading:

kubectl get agents,agentruns --all-namespaces -o yaml \
  > kontext-custom-resources-backup.yaml

Apply the new release manifest over the existing installation and wait for the controller rollout:

NEW_VERSION="<target-release-tag>"
kubectl apply -f \
  "https://github.com/MFS-code/Kontext/releases/download/${NEW_VERSION}/install.yaml"

# Remove identities used by releases before the kontext- name prefix.
kubectl delete deployment/controller-manager \
  -n kontext-system --ignore-not-found=true --wait=true
kubectl delete \
  mutatingwebhookconfiguration/task-agentrun-mutator.kontext.dev \
  clusterrolebinding/manager-rolebinding \
  clusterrolebinding/webhook-registration-manager \
  clusterrole/manager-role \
  clusterrole/webhook-registration-manager \
  --ignore-not-found=true
kubectl delete \
  service/webhook-service \
  serviceaccount/controller-manager \
  rolebinding/leader-election-manager \
  rolebinding/webhook-certificate-manager \
  role/leader-election-manager \
  role/webhook-certificate-manager \
  networkpolicy/controller-manager-webhook \
  -n kontext-system --ignore-not-found=true

kubectl rollout status deployment/kontext-controller-manager \
  --namespace kontext-system \
  --timeout=180s

The explicit cleanup is idempotent. It stops an unprefixed controller from retaining the shared leader-election Lease and removes its fail-closed webhook before the old Service disappears. The namespaced TLS Secret remains and is renewed for the prefixed webhook Service.

Kubernetes updates the CRDs and current resources declaratively; existing Agent and AgentRun resources remain. Downgrades are not supported as an API compatibility guarantee. Release CI nevertheless migrates in both directions, applies the previous manifest after the candidate as a rollback safety check, verifies baseline workloads remain available, and then restores the candidate.

Uninstall

To remove only the Kontext control plane while retaining the CRDs and custom resources in other namespaces:

kubectl delete clusterrolebinding kontext-manager-rolebinding \
  --ignore-not-found=true
kubectl delete clusterrole kontext-manager-role \
  --ignore-not-found=true
kubectl delete mutatingwebhookconfiguration \
  kontext-task-agentrun-mutator.kontext.dev --ignore-not-found=true
kubectl delete clusterrolebinding kontext-webhook-registration-manager \
  --ignore-not-found=true
kubectl delete clusterrole kontext-webhook-registration-manager \
  --ignore-not-found=true
kubectl delete mutatingwebhookconfiguration \
  task-agentrun-mutator.kontext.dev --ignore-not-found=true
kubectl delete clusterrolebinding manager-rolebinding \
  webhook-registration-manager --ignore-not-found=true
kubectl delete clusterrole manager-role \
  webhook-registration-manager --ignore-not-found=true
kubectl delete namespace kontext-system \
  --ignore-not-found=true --wait=true

Deleting kontext-system removes the controller and its ServiceAccount. Agent and AgentRun resources in other namespaces remain stored and can be reconciled again by reapplying an install manifest. Any custom resources created inside kontext-system are deleted with that Namespace.

To remove Kontext completely, including both CRDs:

VERSION=v0.1.0-alpha.2
kubectl delete -f \
  "https://github.com/MFS-code/Kontext/releases/download/${VERSION}/install.yaml" \
  --ignore-not-found=true --wait=true

Deleting a CRD deletes all custom resources of that kind across the cluster. Back them up first if their history or results must be retained. Release CI verifies both the retention procedure and complete removal.

API relationship

The git tag, GitHub release, and image tags identify one version of the Kontext distribution. They do not change the Kubernetes API group/version: current releases serve kontext.dev/v1alpha1, and maintained runtimes emit the versioned event and result contracts documented in the API specification.

v1alpha1 is intentionally unstable. A new Kontext alpha release may make breaking CRD, runtime-contract, or status-shape changes while retaining the same Kubernetes API version. Consumers must read the release notes and follow the documented upgrade procedure rather than treating matching v1alpha1 labels as compatibility guarantees.