Skip to main content
Version: 0.7 (Next)

Konstruct 0.7.0

Released: August 2026

Highlights

  • Platform Themes replace Kontract — the theme-driven PaaS surface is now simply Themes. Konduit is the flagship platform theme; Ship It!, Metropolis, and your own themes sit alongside it. The word "kontract" is retired everywhere: APIs, CRDs, charts, repositories, and docs
  • Themes build on the control plane, serve on zone clusters — the shared build plane (kpack + Harbor) runs on the control plane for every organization; the built theme and app workloads run on a zone cluster (an ordinary workload cluster that hosts platform theme workloads)
  • New organization model — the platform team gets a visible platform organization that owns the control plane; the control plane appears in its clusters graph, with every other organization's management cluster ghosted alongside it for platform admins
  • Streamlined self-hosted install — bootstrap-as-cluster-template, a default template catalog, and one-command enablement of the Themes surface

Breaking changes

0.7.0 is a hard cutover for anything that used the old kontract names. There are no aliases and no conversion webhooks.

0.60.7.0
kontract-operator (chart, image, umbrella values key)theme-operator
KontractApp CRD (kontractapps.konstruct.civo.com)ThemedApp (themedapps.konstruct.civo.com)
REST routes /api/v1/kontract/*, /api/v1/kontract-cluster/api/v1/theme/*, /api/v1/theme/cluster
UI routes /kontract, /kontract/theme/:name/theme, /theme/run/:name
Workload namespaces kontract-{org}-{env}themed-{org}-{env}
Values gate konduitEnabledthemesEnabled
Env vars KONTRACT_FORGE_*, KONTRACT_METRICS_URLTHEME_FORGE_*, THEME_METRICS_URL
Theme contract kontract.js, global kontract, kontract-rpctheme.js, global theme, theme-rpc
Theme spec KONTRACT.md, manifest field kontractTheme: v1THEME.md, themeSpec: v1
Theme repos konstructio/kontract-theme-*konstructio/theme-* (old URLs redirect)
Cluster template / stored cluster_type value kontracttheme

Anything you pinned against the old names — API clients, MCP tool allowlists (tool names regenerate from the OpenAPI operation IDs), bookmarks, values files in your own gitops repositories — must move to the new names.

Organization model changes

Two behaviors change even if you never used Themes:

  1. Seed records are hidden from the organization list. A Project labeled konstruct.civo.com/bootstrap: "true" is treated as the control plane's seed record, not an organization. On pre-0.7.0 installs the bootstrap Project doubled as the platform team's organization — after upgrading it disappears from the organization picker until you migrate (below).
  2. The control plane is owned, not ambient. The clusters graph shows the control plane only to the organization that owns it — recorded as a konstruct.civo.com/platform-org annotation on the bootstrap Project. New installs link this automatically when the first organization is created; platform admins see unowned control planes regardless. Existing installs must add the link by hand.

Fresh 0.7.0 installs get this shape from the seed job automatically. Upgraded installs must create it — see step 7 below.

Upgrading from 0.6 (self-hosted)

Plan a maintenance window

The Themes surface is unavailable during the upgrade. Running apps on zone clusters keep serving, but their control-plane records are recreated and every registered theme must be rebuilt.

1. Before you upgrade

  1. Export the theme-surface resources: kubectl get kontractapps,zones,themes,characters,ratecards,skucatalogs,subscriptions -A -o yaml > kontract-backup.yaml
  2. Pause Argo CD auto-sync for the konstruct application.
  3. Scale the old operator down: kubectl -n konstruct-system scale deploy konstruct-kontract-operator --replicas=0
  4. Remove finalizers from every KontractApp so the CRD swap cannot hang — and do this after the operator is truly stopped; a self-healed operator re-adds them:
kubectl -n <org> patch kontractapp <name> --type=merge -p '{"metadata":{"finalizers":null}}'

2. Migrate secrets and values

  1. Dual-write the renamed secret keys before deploying — the chart's ExternalSecret maps Vault key names straight to env names. Add THEME_FORGE_* copies of every KONTRACT_FORGE_* key, and copy konstruct/kontract/harbor to konstruct/theme/harbor. Delete the old keys only after verification.
  2. In your gitops values for the umbrella: rename the kontract-operator: key to theme-operator:, point its image at .../images/theme-operator, and rename konduitEnabled to themesEnabled.
  3. Set theme-operator.seedGitops.domain (or both seedGitops.harborHost and seedGitops.vmHost explicitly). The 0.7.0 operator chart ships a PreSync seed job that commits its runtime prerequisites into the platform gitops repository, and the template refuses to render without these hostnames — an upgraded install that skips this sees its Argo CD comparison fail with execution error at .../seed-gitops-job.yaml. The job itself is skip-if-present, so on an already-seeded install it runs as a no-op. Set vmHost explicitly if your metrics ingest hostname is not the derived prometheus-remote-write.<domain>.

3. Deploy 0.7.0

Bump the umbrella chart. The upgrade installs the ThemedApp CRD and the new operator, and prunes the old operator deployment. The old kontractapps CRD is not pruned automatically — delete it after step 4.

4. Migrate the theme-surface resources

  1. Re-apply each exported KontractApp as kind: ThemedApp (same group/version). Drop status, and rewrite metadata.finalizers from kontractapp.konstruct.civo.com/finalizer to themedapp.konstruct.civo.com/finalizer — the new operator does not recognize the old string, and a carried-over finalizer strands the resource on delete.
  2. Registered themes: update each Theme to the renamed repository (konstructio/theme-*) — or delete and re-register; the operator recreates the backing ThemedApp itself.
  3. Delete the old CRD once nothing references it: kubectl delete crd kontractapps.konstruct.civo.com
  4. Delete the drained kontract-{org}-{env} namespaces. New workloads land in themed-{org}-{env}.

5. Migrate stored cluster records

Projects for zone clusters created before 0.7.0 store cluster_type: kontract. The new filters compare against theme, so an unmigrated record leaks into organization and cluster lists instead of being treated as platform infrastructure:

kubectl -n default patch project <zone-cluster> --type=merge \
-p '{"spec":{"cluster_type":"theme","cluster_template_name":"theme"}}'

6. Migrate the default template catalog

If your install carries the live-applied default catalog from 0.6, the theme template is still named kontract. Recreate it under the new name (the API resolves theme clusters against a template named theme):

kubectl -n default get clustertemplate kontract -o json \
| jq '.metadata = {name: "theme", namespace: "default"} | .spec.name = "theme"' \
| kubectl apply -f -
kubectl -n default delete clustertemplate kontract

7. Migrate the organization model

Pre-0.7.0 installs have a single bootstrap Project playing both roles. Split it to match the fresh-install shape.

Order matters

The team-management operator runs the full control-plane bootstrap against any bootstrap: "true" Project without a BootstrapComplete condition — on an already-running control plane that means re-initializing your gitops repository. Create the seed record with the label off, hydrate its status, and only then flip the label.

# 1. Seed record for the control plane — label OFF until status is hydrated
kubectl apply -f - <<'MANIFEST'
apiVersion: konstruct.civo.com/beta1
kind: Project
metadata:
name: <control-plane-cluster-name>
namespace: default
labels:
konstruct.civo.com/bootstrap: "false"
annotations:
konstruct.civo.com/platform-org: platform
spec:
name: <control-plane-cluster-name>
description: "Control plane seed record"
cluster_name: <control-plane-cluster-name>
custom_template_fields_inputs:
gitopsRepoName: <platform-gitops-repo>
MANIFEST

# 2. Mark bootstrap as already complete (this cluster IS the bootstrapped CP)
kubectl -n default patch project <control-plane-cluster-name> --subresource=status --type=merge -p '{
"status": {
"conditions": [{"type":"BootstrapComplete","status":"True","reason":"MigratedPreExisting",
"message":"Control plane bootstrapped pre-0.7.0","lastTransitionTime":"2026-01-01T00:00:00Z","observedGeneration":1}],
"phase": "provisioned", "detokenized": true, "downstream_repo_created": true,
"gitops_pushed": true, "repo_credentials_set": true, "template_rendered": true, "kbot_setup_check": true
}
}'

# 3. Now it is safe to mark it as the seed record
kubectl -n default label project <control-plane-cluster-name> konstruct.civo.com/bootstrap=true --overwrite

# 4. Rename the old bootstrap Project into the visible platform organization
kubectl -n default get project platform-org -o json \
| jq '.metadata = {name: "platform", namespace: "default", labels: {"konstruct.civo.com/bootstrap": "false"}} | .spec.name = "platform" | {apiVersion, kind, metadata, spec}' \
| kubectl apply -f -
kubectl -n default delete project platform-org

The platform organization is named platform (0.7.0 installs seed it under that name). Skipping this migration leaves the platform organization hidden and the control plane invisible to everyone except platform admins.

8. Migrate the gitops registry

In the registry repository your zone cluster syncs: rename the kontract/ tree to theme/ (and kontract-quotas/ to theme-quotas/), update the app-of-apps Application (kontract-appstheme-apps, path .../theme), and expect the app label konstruct.civo.com/themed-app and destination namespaces themed-{org}-{env} on operator-committed manifests. Land this in the same window as the operator upgrade or Argo CD orphans one of the two trees.

9. Rebuild every theme

The platform broker now speaks only theme-rpc. A theme built before 0.7.0 goes dark in the runner until rebuilt against the new contract. Trigger a pinned rebuild per theme app:

kubectl -n <org> annotate themedapp <name> konstruct.civo.com/rebuild-revision=<commit-sha> --overwrite

Verify

  • /api/v1/config returns themes_enabled; /api/v1/theme/* routes respond; /api/v1/kontract/* returns 404
  • kubectl get themedapps -A shows your apps; no kontract* CRDs remain
  • The platform organization appears in the organization picker and the control plane renders in its clusters graph
  • Each theme loads end-to-end in the runner (/theme/run/<name>)
  • grep -ri kontract over your own gitops repositories returns nothing

Also in this release

  • Zone clusters formalized — the run-target for platform theme workloads is a plain workload cluster; no special cluster template beyond the theme type

  • Registration templates — civo-microservice Pipeline and Helm templates with zero-detokenization CI

  • Operator seed job — once the theme-operator is scaled up (replicaCount: 1), its PreSync seed job bootstraps the initial-state secret, gitops prerequisites (Harbor, kpack, VictoriaMetrics components), and the platform organization; requires seedGitops.domain in values. Validated on a fresh self-hosted install with these caveats: the seed job does not create the platform namespace (create it before registering themes), the control plane is adopted by the first organization created (re-point the konstruct.civo.com/platform-org annotation to platform if that org should own it), and enabling the surface is a deliberate umbrella-values commit — provisioning a theme cluster alone does not flip it:

    konstruct-api:
    extraEnv:
    THEMES_ENABLED: "true"
    theme-operator:
    replicaCount: 1
    seedGitops:
    domain: <your-domain>
    config:
    validClusters:
    - <your-theme-cluster> # chart default is the SaaS zone list
    harbor:
    existingSecret: <secret with harbor_url/harbor_username/harbor_password>

    Themes also need a GitAccount on the platform organization (theme repositories are managed under its git group), and Harbor's admin password seeded at Vault secret/konstruct/foreman/harbor-admin before the harbor component syncs

  • Deployed version in the sidebar — the UI shows the exact deployed umbrella chart version, release-candidate suffix included, sourced from a new chart_version config field (KONSTRUCT_VERSION behavior unchanged)

  • Theme clusters from the UI — platform admins create and delete theme workload clusters from the clusters graph, which now renders them hanging off the control plane