AI Agents

  • Fixed

    Full Changelog: https://github.com/giantswarm/klausctl/compare/v0.4.0...v0.4.1

  • Fixed

    • The kagent Namespace (kagent.namespaceOverride, when it differs from the release namespace) renders only while the kagent component is on — the last of the standalone generator’s nine template patches, landed upstream. An installation without kagent no longer gets an empty, Helm-owned kagent namespace, and turning kagent off removes it with the release. On a management cluster where kagent is off, the connectivity upgrade deletes the empty kagent namespace; the fleet’s hand-written kagent-flux identity that used to live there was handed over to the chart first (where kagent runs) or orphaned (where it does not), so nothing else is in it. Where kagent is on, nothing changes.
  • Added

    • kagent.fluxServiceAccountName (default kagent-flux), in both charts: the tenant identity of the agents’ Flux HelmReleases, from ONE value. The connectivity chart renders ServiceAccount kagent-flux in the kagent namespace with a RoleBinding to cluster-admin (namespace-scoped admin: full control of the kagent namespace, nothing outside it) whenever kagent is on (templates/kagent/flux-service-account.yaml); the meta chart derives agent-manager’s flux.helmReleaseServiceAccount from the same value (agent-platform.componentDerivedValues, merged over the forwarded agent-manager block — agent-manager.flux.helmReleaseServiceAccount is no longer set in values.yaml, and a value set there must agree or the render fails naming the one key); and the agent-platform.kagent.fluxServiceAccountName helper exports it for the portal’s agentPlatform.fluxServiceAccountName. Changing it in one place changes all three; an empty value renders no identity and hands both callers an empty name. Under a Flux multi-tenancy lockdown (helm-controller with --no-cross-namespace-refs and a rights-less default ServiceAccount, or the Flux multi-tenancy admission policy on Giant Swarm management clusters) a HelmRelease without it runs as the default ServiceAccount and fails with secrets is forbidden. make verify-identity (in CI) asserts the objects, the single value across the three consumers, the guard and the empty case. No installation needs to act: a management cluster carried the same two objects hand-written in its Flux bases; the chart’s copy has the same spec, helm-controller takes ownership of them on the upgrade (its default) and both writers set the same fields. The hand-written copy is removed from the bases in a follow-up.

    Fixed

    • Six of the text patches the standalone umbrella’s generator applied to its copy of the connectivity templates were bugs here too and are fixed at their upstream location, so no generator is needed:
      • The kagent UI HTTPRoute (kagent.uiRoute without oauth2-proxy) targets the Service the kagent chart names from kagent.fullnameOverride (kagent-ui), not <release>-ui — as the oauth2-proxy branch and the controller route already did. The fleet runs the oauth2-proxy branch, so its render is unchanged.
      • The muster / HTTPRoute renders only while the muster component is on (components.muster.enabled): hostname-less on a shared Gateway, it blackholed every request when an umbrella turned muster off. The meta chart force-enables muster, so the fleet render is unchanged.
      • ingress.mode: muster-direct refuses the knobs that render agentgateway.dev objects or attach to the agentgateway Gateway — kagent.controllerRoute.enabled, klausGateway.agentgatewayRoute.enabled, and agent-platform-mcps’ agentgateway.enabled with mcpServers set — naming the knob, instead of shipping objects the API server rejects on a cluster without the agentgateway CRDs (the model-manager / agent-manager routes already guarded themselves this way). ci/test-klausgateway-obo-values.yaml moves to agentgateway-muster, ci/test-mcps-values.yaml sets agent-platform-mcps.agentgateway.enabled: false; every management cluster runs agentgateway-muster.
      • The legacy component-toggle probe (agent-platform.validateLegacyToggles, both charts) reports a leftover <block>.enabled whatever its value, also true under a component that is on: neither chart has a Helm dependency, so no chart default is ever coalesced into those blocks and the key can only be the operator’s. The “on + true passes” leg and its prose described an umbrella that feeds the blocks to real dependencies (the standalone patched both); make verify-modes asserts the strict probe in both charts.
      • The kserve API guard of the model-manager wiring defers to the platform’s own KServe when it is bundled: with components.kserve-resources or components.modelServing on, that component’s guards own the check (a missing API is then the first install) and the message names the components. The new agent-platform.optionalComponentEnabled helper treats a component absent from the roster as off — unlike componentEnabled, whose absent-is-on rule is for the force-on components.
      • The agent-platform.serviceMonitor helper’s prose stated default true, which an umbrella flipped; with the knob defaulting to auto (#291) the prose says so and no umbrella has a reason to flip it.
  • Added

    • The cluster-shape knobs default to auto and render by served API group (roadmap#4348, PRD Q4): kyvernoPolicies.enabled renders the Kyverno objects when kyverno.io/v1 is served; networkPolicy.flavor is cilium when cilium.io/v2 is served, else kubernetes; global.observability.metrics.serviceMonitor.enabled renders the monitor objects when monitoring.coreos.com/v1 is served; dicebear.route.enabled (an Envoy HTTPRouteFilter user) follows gateway.envoyproxy.io/v1alpha1; agentSandbox.podSecurity.enabled (a Kyverno mutate policy) follows the resolved kyvernoPolicies.enabled. The meta chart detects once, from .Capabilities.APIVersions (live under helm-controller, the Helm CLI and --dry-run=server; Helm’s built-in set under helm template, so an offline render without --api-versions yields the vanilla shape), resolves every knob before it inlines a component’s values, and derives the component-level copies from the same answers while they are left at auto: muster.networkPolicy.flavor, muster.muster.observability.metrics.prometheus.serviceMonitor.enabled / .prometheusRule.enabled, muster.muster.observability.grafanaDashboard.enabled, valkey.ciliumNetworkPolicy.enabled, valkey.valkey.metrics.podMonitor.enabled (written false only where monitors are off), kagent.otel.tracing.enabled / .logging.enabled, kagent.oauth2-proxy.metrics.serviceMonitor.enabled and the OTEL_EXPORTER_OTLP_HEADERS entry of kagent.controller.env (dropped when both OTel exporters are off). The connectivity chart carries the same defaults and the same resolution helpers (agent-platform.shape.*) for renders on its own; under the meta chart it receives resolved values, so the two cannot disagree on one cluster. Explicit true / false (cilium / kubernetes) values keep winning, on a knob and on a component copy; the schema accepts auto|true|false (auto|cilium|kubernetes) and rejects anything else; the connectivity chart’s .Capabilities guards for the Flux and KServe APIs stay hard failures. make verify-auto (in CI) asserts the resolution per shape, the byte-identical fleet render, the vanilla shape and the overrides. No installation needs to act: with the fleet’s API groups served the render is byte-identical to before; a kind or plain cloud cluster renders the vanilla shape from the same chart without a values file that describes it.
  • Added

    • Seven components, off by default — the extras the agent-platform-standalone umbrella carried as Helm dependencies on top of this roster, so a cluster with none of them turns them on from the same components: map: components.backstage (the Giant Swarm Backstage portal, 0.x), components.mcp-kubernetes (>=1.1.1 <2.0.0, the global.identity fallbacks its block relies on), components.cloudnative-pg (the upstream CloudNativePG operator from oci://ghcr.io/cloudnative-pg/charts, 0.29.x — one chart minor is one operator line and an operator upgrade rolls every instance pod, so moving it is a deliberate edit) and the four KServe charts components.kserve-crd, components.kserve-resources, components.kserve-llmisvc-crd, components.kserve-llmisvc-resources (0.2.x, one repository, moving together). Each is rendered by the existing loop as one OCIRepository + HelmRelease; the new top-level blocks backstage:, mcp-kubernetes:, cloudnative-pg:, kserve-crd:, kserve-resources:, kserve-llmisvc-crd:, kserve-llmisvc-resources: carry the standalone’s defaults (Backstage’s chart Ingress and VPA off, the base config restated, the Agent Platform app-config mounted from agent-platform-backstage-app-config, the credentials Secret and optional identity-provider CA from global.identity; mcp-kubernetes as an OAuth 2.1 resource server acting as the user with downstream OAuth; KServe in Standard deployment mode without per-model routes; the llm-d controller reusing the shared objects) and are forwarded verbatim with global injected. dependsOn replaces the standalone’s two-phase first-install guard: kserve-resources after kserve-crd, kserve-llmisvc-resources after kserve-crd, kserve-llmisvc-crd and kserve-resources, backstage after cloudnative-pg, and the CR consumers agent-platform-connectivity (the CNPG Cluster, the model serving objects) after cloudnative-pg and kserve-resources, model-manager after kserve-resources — every reference dropped at render time while the component is off, as before. None of the seven ships a crds/ dir (kserve-crd, kserve-llmisvc-crd and cloudnative-pg render their CRDs as templates, upgraded with the release), so none carries a crds: policy. kserve-llmisvc-crd is a component the standalone could not have: its 4.5 MB of CRDs did not fit in the umbrella’s one release Secret; as its own release it does. examples/customer-bom.yaml pins all seven (the standalone’s tested pins). The roster forwarded to the connectivity release carries the seven flags, so the wiring the standalone rendered by hand for them (the Backstage app-config and route, the mcp-kubernetes MCPServer, the model serving runtimes) can gate on them when it moves into the connectivity chart in a following release; the connectivity chart declares the seven roster entries and the seven blocks already. make verify-components asserts the roster (off by default, sources, ranges, order, BOM pins, the forwarded tree against the connectivity schema, schema symmetry between the two charts); make verify-components-charts pulls the seven charts at the range’s resolution and at the BOM pin and renders each with the forwarded values. No installation needs to act: the fleet render changes by the seven <name>: {enabled: false} roster lines inside the connectivity HelmRelease’s values only — one Helm revision of that release with unchanged objects and no pod rolled.
    • components.<name>.omitKeys applies to a forwardAllValues component too, dropping top-level blocks from the forwarded tree. components.agent-platform-connectivity.omitKeys holds the seven new blocks back from the connectivity release until its wiring reads them: that chart’s root schema is additionalProperties: false, and while both charts release off one tag, the fleet’s connectivity release re-resolves its chart on its own OCIRepository interval — a block the live chart does not declare would fail that release on every installation until the chart caught up. The release that adds the wiring drops the blocks from the list; the connectivity values.yaml declares them from this release on, so that step has no such window.
  • Removed

    • The Argo CD render engine of the meta-package. gitops.engine accepts flux only (enum: [flux] in the schema, a template guard behind it); templates/components.yaml renders a Flux OCIRepository + HelmRelease per component and nothing else; gitops.argo.project / gitops.argo.server are gone from the values and the schema. The Argo Application branch was never verified against a running Argo CD and no installation selected it, and the platform cannot run on Argo CD in any case: agents are Flux objects on every path (the Backstage agent create flow and agent-manager write an OCIRepository + HelmRelease per agent). gitops.engine: argo now fails the render — the schema first, the guard with gitops.engine=argo is not supported; flux is the only engine — and gitops.argo.* fails the schema. make verify-meta asserts the refusal on both layers, that the Flux render carries no argoproj.io object and that an explicit gitops.engine: flux renders exactly the default; the Argo render assertions of verify-meta and verify-presets are gone with the branch. No installation needs to act: the Flux render is byte-identical. See UPGRADE.md.
  • Fixed

    • kagent.oauth2ProxyIngress is dropped from the values forwarded to the kagent chart (components.kagent.omitKeys). It is read by the connectivity chart only, and the flattened kagent 0.2.x chart rejects it (additional properties 'oauth2ProxyIngress' not allowed), so an installation that set it (glean) failed the kagent upgrade to 0.2.0. tests/verify-kagent-wiring.py now derives the umbrella-only keys from what the connectivity templates read under .Values.kagent, so a new one cannot be forwarded unnoticed.
  • Changed

    • The kagent component tracks the 0.2.x chart line, which flattened the upstream keys onto the chart root. The forwarded values block is no longer nested under a kagent key, and the umbrella-only keys (controllerRoute, modelConfigs, remoteMcpServers, serviceMonitor, uiRoute) are dropped before forwarding (omitKeys) because the flattened chart’s schema rejects them. The top-level kagent: values block is unchanged, so no installation has to move an override. examples/customer-bom.yaml pins 0.2.0. The kagent controller and UI pods roll once on the upgrade (three labels and the pod annotations that hash them change).
  • Added

    • model-manager.lmstudio.endpoint / .agentHost and the lmstudio backend in the connectivity chart’s model-manager wiring: an LM Studio on the host (llama.cpp on GPU and CPU, MLX on Apple silicon) as a serving backend. templates/model-manager/validate.yaml accepts the name and, as for ollama and lemonade, fails the render when the endpoint is missing or carries no scheme; _helpers.tpl gains modelManager.lmstudioEndpoint and the lmstudio arms of hostEndpoint/hostTargets, so the model-manager NetworkPolicy opens egress to the LM Studio host in both flavors. Requires model-manager >= 0.19.0, and that is a pin to move rather than a backend to select: values.yaml forwards the whole model-manager block — lmstudio included — to every release, and the key does not exist before 0.19.0, whose schema is additionalProperties: false, so a chart pinned below it rejects the values outright even on an installation that never touches LM Studio (examples/customer-bom.yaml floors it accordingly). LM Studio serves no delete (lms rm is host-only), so that call answers 501 unsupported.
  • Changed

    • components.kagent.versionRange is 0.1.x (was 0.x). kagent 0.2.0 flattens the upstream keys onto the chart root and takes no nested kagent: block, so the current wiring must not pick it up. The wiring change and the 0.2.x range ship together in a later release. No installation needs to act. A BOM that pins components.kagent.versionRange inside 0.1.x is unaffected.