AI Agents

  • Added

    • The cut-over of an installation to the kagent API v2 line, in the connectivity chart (giantswarm/agent-platform#346; bumblebee-plans#51 D9, D11). The database: the connectivity chart’s postgres.databases map (introduced with Agent Substrate, giantswarm/agent-platform#342 — one CNPG Database per entry on the existing Cluster, <clusterName>-<key>, owned by the bootstrap role, and a post-install,post-upgrade hook Job <release>-postgres-databases that derives each entry’s connection Secret <clusterName>-<key>-app from the bootstrap Secret <clusterName>-app) gains the shipped entry kagent-v2: spec.name: kagent_v2, the vector extension, databaseReclaimPolicy: retain, rendered while the kagent component is on. Its derived Secret kagent-pg-kagent-v2-app in the kagent namespace is what the kagent API v2 controller mounts (database.postgres.urlFile; the mount examples and ci/test-postgres-values.yaml name it, the fleet template’s secretName follows). The controller refuses the 0.10 schema and no conversation history is migrated, so it starts fresh on kagent_v2; the 0.10 database kagent stays untouched for 30 days and is then dropped — the new postgres.applicationDatabase.ensure: absent renders ensure: absent on its Database object in the ImageVolume extension mode (the chart otherwise re-creates it after a hand DROP), the psql command otherwise (UPGRADE.md). The bootstrap database’s own Database and sessionsDatabase keep their templates. The migration: agentManager.migration (both charts; on by default, rendered when kagent and agent-manager are on) renders a plain Job agent-platform-connectivity-agent-manager-migrate-<8-hex hash of its image, args and environment> in the kagent namespace running agent-manager migrate (dryRun adds --dry-run) from agent-manager’s image at image.tag — the meta chart’s BOM pin for the agent-manager component — as the tenant identity kagent.fluxServiceAccountName (the helper, never the literal), with its inputs as environment (the kagent namespace, the additional managed namespaces, the agent chart’s OCI URL and range, the GitOps namespaces, the platform Harness kagent, GITHUB_TOKEN from githubToken.secretName/key, default kagent-skills-token/token, optional). Deliberately not a Helm hook: a migrate failure must never fail the upgrade that renders the platform Harness, and the meta chart’s new roster key components.<name>.disableWaitForJobs (install/upgrade.disableWaitForJobs: true, set on agent-platform-connectivity) stops helm-controller from waiting on the release’s Jobs — hooks are unaffected. The hash in the name makes a changed spec a new Job (the old-named one is removed) instead of an immutable-template error; an unchanged spec leaves the completed Job in place, so the expand phase runs when 4.0 first renders the Job and the contract phase is a re-run (a clone by hand, or the next upgrade after the Job’s day-long TTL). Its migration-only rights are plain objects too: ONE ClusterRole on customresourcedefinitions confined to the five removed CRDs (agents, sandboxagents, agentharnesses, memories, toolservers of kagent.dev) with get, delete, bound by ONE ClusterRoleBinding — the chart’s only cluster-scoped binding — and a Role + RoleBinding (get, list on helmreleases, ocirepositories) per namespace in gitopsNamespaces (the fleet: flux-giantswarm, where the GitOps-owned agents’ releases live). A network policy in both flavors admits the Job’s egress to DNS, the API server, api.github.com and the agent chart’s registry. The report is the ConfigMap agent-manager-migrate-report in the kagent namespace (written by the command); a failed phase leaves the v1alpha2 objects in place; a FAILED Job stays a day and can be cloned by hand (kubectl create job --from takes CronJob sources only; UPGRADE.md carries the command), or the hooks are re-run with flux reconcile helmrelease --force. An empty tenant identity with the migration on fails the render. The Job and its bindings retire in a later 4.x release. make verify-postgres (verify-postgres-kagent-v2), verify-identity (verify-identity-migration: exactly that one ClusterRoleBinding, none while off) and the new verify-migration (plain Job, stable hash name that changes with the image, the roster key on the connectivity release only) assert it; tests/pick-doc.py selects one object of a render by kind and name. The ATS kind smoke keeps agentManager.migration.enabled: false — the bare smoke serves no live kagent API v2 for migrate to act on; the migration rehearsal is agentlab#143. No 3.x installation is affected: the connectivity chart of this line is bounded below 4.0; the objects render on the 4.0 line, whose cut-over UPGRADE.md describes.
  • Added

    • The connectivity chart renders one platform Harness per managed namespace (giantswarm/agent-platform#344, bumblebee-plans#51 D5). On kagent API v2 how an agent runs is a kagent.dev/v1alpha3 Harness: a digest-pinned Go ADK runtime image, an environment and the Substrate policy an AgentTemplate runs under; a template becomes Ready only when a Harness admits it (allowedAgentTemplates.selector), its readiness read from AgentTemplate.status.harnesses[] (Harness.status is never written). 4.0 renders exactly one Harness, kagent (the kagent runtime only — no free list of arbitrary types; a second runtime is a later object), in each managed namespace (today the kagent namespace; a WorkerPool and a workerPoolRef are namespace-local): workload.image = kagent.harness.image (the line’s Go ADK image by digest — a tag fails the render naming the requirement, as the CRD rejects it; the digest moves with kagent.tag on a re-pin), env = KAGENT_PROPAGATE_TOKEN=true (the Go ADK re-emits the caller’s bearer on its MCP calls, so muster sees the person; the private-skills credential is added only if the D8 spike chooses the per-namespace-credential route — undecided, nothing more today), substrate.workerPoolRef.name = kagent.substrateWorkerPool.name (the meta chart’s default WorkerPool, forwarded), snapshotPolicy.location = kagent.harness.snapshotLocation (#342), and allowedAgentTemplates.selector.matchLabels = {agent-platform.giantswarm.io/harness: kagent} — the one label the Generic agent chart 1.x sets on every template (giantswarm/agent#25), the whole admission contract. make verify-kagent-harness (tests/verify-kagent-harness.py) asserts exactly one Harness with the shape, the workerPoolRef following kagent.substrateWorkerPool.name, a tag image failing the render and none while kagent is off; make verify-kagent-crds now also validates the rendered Harness against the line’s CRD at the pinned release.
    • The Substrate WorkerPool’s replicas and pod template are the platform’s capacity and scheduling knobs (giantswarm/agent-platform#344). kagent.substrateWorkerPool.replicas and kagent.substrateWorkerPool.template (resources, nodeSelector, tolerations, nodeAffinity, priorityClassName) — the kagent chart’s WorkerPool values forwarded by the meta chart — carry the capacity: one worker hosts one actor at a time, so a worker’s resources.limits bound one agent’s sandbox (memory → RAM, CPU → vCPU count) and replicas bound the concurrently active agents. Defaults with sizing guidance in the README (“Agent Substrate: worker capacity”): four workers, each requesting 250m/512Mi and limited to 2 vCPU / 2Gi (an idle worker holds ~16Mi; a Go ADK golden boot and turn stay well under the limit — measured in agentlab), the pool pinned to amd64 (#342). The Generic chart 1.x has no per-agent runtime/replicas/resources/nodeSelector/tolerations any more (giantswarm/agent#25); capacity is the WorkerPool (UPGRADE.md).
  • Added

    • Agent Substrate ships inside the chart (meta chart 4.0, giantswarm/agent-platform#342). kagent API v2 has no runtime without it — every agent is a Substrate actor in a gVisor worker pod — so two roster entries deliver it from the Giant Swarm Substrate line (giantswarm/substrate, branch giantswarm: the upstream release kagent’s go.mod pins plus the carried patches; FORK.md there is the ledger), oci://ghcr.io/giantswarm/substrate/helm: components.substrate-crds (the three ate.dev CRDs as templates) and components.substrate (the control plane — ate-api-server, ate-controller, the atenet router, egress gateway and dns, the per-node atelet DaemonSet — in ate-system, the podcertificate-controller in its own namespace). Both follow components.kagent when left unset (the render refuses kagent on with either off, and Substrate on without its CRDs — agent-platform.validateSubstrate), both land in ate-system through the new roster key components.<name>.targetNamespace (the chart’s Roles and Service names are fixed to it), both carry one version pin — the same string in the two versionRanges and in kagent.substrateWorkerPool.workerImage, held to one by make verify-components: the range >=0.0.27-gs.2 <0.0.28-0 (the line’s releases of upstream 0.0.27 from v0.0.27-gs.2 on — the egress gateway’s frontend policy for its agentgateway dataplane, the connection string from a Secret, atelet scheduling), its floor the worker image’s tag. Roster components rather than the kagent charts’ substrate subchart switches: each release has its own Flux status, the order is explicit, the repository is a value (a mirror for a proxied installation, with substrate.image.registry), Substrate’s namespace is not kagent’s. The substrate: block is forwarded verbatim (the chart has no schema): postgres.enabled: auto (below), rustfs.enabled: false (the bundled in-cluster store is a lab’s), atelet.storageBackend, atelet.{nodeSelector,tolerations,affinity} (carried patch of the line; empty = every node the DaemonSet controller admits, the worker nodes on a cluster whose control planes are tainted), atelet.extraEnv (an S3-compatible store’s endpoint and credentials). Bootstrap: the connectivity release’s pre-install,pre-upgrade hook Job <release>-substrate-bootstrap mints what the substrate chart mounts but does not render — the CA pools service-dns-ca-pool, pod-identity-ca-pool (podcertificate-controller-system), the JWT authority pool actor-id-jwt-pool, the CA pool actor-id-ca-pool and the derived trust anchor actor-id-ca-certs (ate-system), and the ConfigMap ate-api-authentication with the apiserver’s own issuer read from its OpenID discovery document — with openssl in an init container (an ED25519 root per CA pool, an ECDSA P-256 ES256 authority, in the pools’ wire format) and kubectl, creates the two namespaces bare when missing, and never touches a pool that exists (a re-run, every upgrade, logs present; a regenerated root would orphan every certificate issued from it). Hook include agent-platform.hooks.job (templates/_hooks.tpl) and the hook identity <release>-hooks (a ClusterRole on secrets, configmaps and namespaces for the hook’s lifetime; hooks.kubectlImage, hooks.opensslImage). Install order: substrate-crds, kagent-crds → agent-platform-connectivity → substrate → kagent → the managers — the connectivity release dependsOn the CRD components, never kagent or substrate, which depend on it (their pods start against what its hooks mint), so nothing waits on a pod that waits on a later release and components.kagent.installDisableWait is gone. Database: postgres.databases — a map of further CNPG Databases on the platform Cluster (<clusterName>-<key>, owned by the application role, retain) each with a derived connection Secret <clusterName>-<key>-app copied into postgres.namespace and every secretNamespaces entry by the post-install,post-upgrade hook <release>-postgres-databases (CNPG mints <clusterName>-app for the initdb database only, a Database mints none; the hook waits for it and rewrites dbname, uri, jdbc-uri, pgpass; server-side applied, idempotent); shipped entry substrate (spec.name substrate, secretNamespaces: [ate-system], renders while the component is on), an installation adds its own. substrate.postgres.enabled: auto resolves in the meta chart’s shape pass: the Cluster’s Database with postgres.enabled (the meta chart derives substrate.postgres.connectionStringSecretRef → <clusterName>-substrate-app/uri; a disagreeing explicit value fails the render), the chart’s bundled single-instance StatefulSet without it (a lab); true/false force, connectionString names an external one, none of the three fails the render. Snapshot store: kagent.harness.snapshotLocation (the platform Harness’s snapshotPolicy.location, s3://<bucket>/<prefix>) is required whenever kagent is on — S3 via IRSA on CAPA (bucket provisioning documented, not rendered), an S3-compatible store through substrate.atelet.extraEnv, a lab’s in-cluster store; the render fails without it. Scheduling: the WorkerPool pinned to one CPU architecture (kagent.substrateWorkerPool.template.nodeSelector kubernetes.io/arch: amd64; the golden snapshot is architecture-specific). Kyverno: one PolicyException per Substrate workload in kyvernoPolicies.policyExceptionNamespace — substrate-atelet, substrate-workers (label ate.dev/worker-pool, every WorkerPool in the kagent namespace), substrate-control-plane, substrate-podcertificate-controller — each naming exactly the restricted-PSS rules its pod spec violates with their autogen- copies, looked up in the new kyvernoPolicies.rules map; make verify-kyverno (tests/verify-kyverno.py) renders the substrate chart at the pin with the forwarded values, computes every workload’s violations (and the worker pod’s, from ate-controller’s pod template) and holds the exceptions to them. Network policies (both flavours, templates/substrate/netpol.yaml): Substrate’s hops — atelet ↔ ate-api, the kagent controller → ate-api and the atenet router, the router → a worker’s tunnel :443, ate-api → atelet’s hostPort 8085 (the egress rule upstream lacks), the workers → the egress gateway and the dns — and the actors’ destinations on the egress gateway atenet-egress (muster, the kagent controller, the LLM provider or the agentgateway LLM listener, the built-in tool server, world:443, cluster 443/10443), which the kagent controller admits (substrate-actors-to-kagent-controller); the worker pods reach only the egress gateway, the dns and the cluster DNS; make verify-kagent-netpol asserts it. Prerequisites: Kubernetes 1.35 with the ClusterTrustBundle, ClusterTrustBundleProjection and PodCertificateRequest gates on apiserver, controller-manager and kubelet (README “Agent Substrate”, UPGRADE.md); a live render refuses a cluster that does not serve certificates.k8s.io/v1beta1/PodCertificateRequest, naming the gates and that the kubelet’s cannot be seen — never helm template. Security write-up for installation owners and reviewers: docs/substrate-security.md. Not lab-verified: Kyverno admission, Cilium enforcement of the policies and IRSA against S3 (the lab has none of the three); their render is asserted, the runtime proof is the first Giant Swarm installation of the rollout.

    Changed

    • kyvernoPolicies.rules (rule → ClusterPolicy of the cluster’s Pod Security Standard policies, upstream kyverno-policies’ names by default) replaces kyvernoPolicies.seccompPolicyName, seccompRuleNames, volumeTypesPolicyName and volumeTypesRuleNames; the CNPG ImageVolume exception reads restricted-volumes from it. The helper agent-platform.kyverno.exceptions renders an exception’s exceptions: from a rule list. An installation that overrode the four keys moves the names into the map (UPGRADE.md); the schema refuses the old keys.
    • The kagent controller’s network policies open Substrate: egress to ate-api-server :443 and atenet-router :8080 in ate-system (replacing the egress to the v1alpha2 agent pods), and the CNPG Cluster’s policy admits ate-api-server on 5432 while Substrate’s database rides the Cluster. The model-serving predictor policies admit the actors through Substrate’s egress gateway instead of app: kagent pods.

    Removed

    • The kagent-declarative-seccomp PolicyException and the <release>-kagent-agent-muster-egress CiliumNetworkPolicy, both selecting app: kagent — the label of the v1alpha2 per-agent Deployments, which nothing carries on kagent API v2 (templates/kagent/policy-exception.yaml is gone). Their successors are substrate-workers and the actors’ rules on substrate-atenet-egress; the kagent controller’s ingress policies no longer admit app: kagent pods. components.kagent.installDisableWait: the kagent release depends on the connectivity release now, so the CNPG connection Secret exists before its first install and every component install waits for its workload.
  • Changed

    • The kagent controller route is a GRPCRoute with the JWT policy on by default (#345; kagent API v2, giantswarm/giantswarm#37705, bumblebee-plans#51 D4/D13/D16). kagent.controllerRoute renders the controller’s API through the agentgateway data plane matched by gRPC service and method — one rule per service, one exact match per RPC of kagent.api.v1alpha1.{AgentInstanceService, AgentTemplateService, ModelService, SystemService} and lf.a2a.v1.A2AService, 39 at the line’s pin, as the value kagent.controllerRoute.grpc.services (the agentgateway controller translates a service-only match into the exact path /<service>/, which no request has, and ignores type: RegularExpression, so a service-only route would fall through to the MCP catch-all; exact service/method matches are translated faithfully and outrank the catch-all’s PathPrefix: / — verified on the data plane’s config dump; reported to the agentgateway line) — on both hops: GRPCRoute kagent-controller on the data-plane Gateway (hostname-less, so the in-cluster authority agentgateway.<namespace>.svc.cluster.local:8080 matches) and GRPCRoute kagent-controller-public on the public Gateway for kagent.controllerRoute.hostname, which makes the outer Gateway carry HTTP/2 to the agentgateway Service; the AgentgatewayBackend kagent keeps policies.auth.passthrough, so the bearer reaches the controller and, through the Harness, the actor, and pins no protocol version: agentgateway infers HTTP/2 (h2c) for gRPC and keeps HTTP/1.1 for gRPC-Web, the split the controller’s one-port dispatcher needs (an HTTP/2 request with application/grpc-web+proto goes to its native gRPC server and is answered 415). Native gRPC over HTTP/2 end to end from the public hostname and from the in-cluster Service; gRPC-Web on the same route. kagent.controllerRoute.jwtAuthentication.enabled defaults to true, Strict, the issuer from global.identity.issuerUrl, the JWKS from jwtAuthentication.jwks (new jwks.tls.{enabled,caSecretName} for an issuer serving its keys over TLS, as modelManager.route has); the AgentgatewayPolicy kagent-controller-jwt targets the GRPCRoute and now also carries the identity transformation — x-user-id is set to jwt.<claim> with the claim from kagent.controller.auth.userIdClaim (email, the ONE value the controller’s AUTH_USER_ID_CLAIM reads too), replacing every inbound value — and an authorization rule that refuses a validated token without that claim (it would otherwise reach the controller as its default user). The kagent UI HTTPRoute gains a RequestHeaderModifier filter removing x-user-id (the UI’s nginx forwards it; the identity on that path is the bearer oauth2-proxy supplies). The controller’s network policy admits the agentgateway data-plane pods and the kagent UI only, in both flavours (the kubernetes flavour admitted the whole release namespace; the intra-namespace app: kagent admission is gone with the per-agent pods). A BackendTrafficPolicy kagent-controller-public on the public hop carries ingress.backendTrafficPolicy.timeout (a GRPCRoute rule has no timeouts; Envoy’s default would cut every A2A streaming turn). The Dev Portal’s app-config agentPlatform.kagent.installations.<inst>.apiBaseUrl is the gRPC origin https://<hostname> (no path); the meta chart’s klausGateway.a2a.url defaults to grpc://agentgateway.agent-platform.svc.cluster.local:8080. docs/authentication.md gains “The kagent controller route — two authentication layers” (the header contract, why agentgateway must stay the only path). make verify-kagent-route asserts all of it; ci/test-kagent-jwt-policy-values.yaml is the default shape and ci/test-kagent-jwt-off-values.yaml the off switch. An installation with the controller route on needs gateway.jwksEgress open (the render fails otherwise) and its clients on gRPC — see UPGRADE.md.

    Removed

    • The REST HTTPRoute on kagent.controllerRoute.pathPrefix (/kagent) and the pathPrefix key (#345): the kagent API v2 controller serves no REST and the route is a GRPCRoute matched by service, so there is no prefix to strip; a pathPrefix left in an installation’s values fails the render naming the key. With it goes the portal’s <hostname>/kagent/api REST base and klaus-gateway’s …/kagent/api/a2a/kagent A2A base — both are gRPC targets now (above).
  • Changed

    • Connectivity 4.0 renders the kagent catalog at kagent.dev/v1alpha3 — kagent.modelConfigs[] (ModelConfig) and kagent.remoteMcpServers[] (RemoteMCPServer) in the kagent namespace, the spec fields unchanged; the only version the kagent line serves (#299). New make verify-kagent-crds (tests/verify-kagent-crds.py) validates every kagent.dev object of every ci/*.yaml shape and a catalog shape against the line’s CRDs at the pinned release (v0.11.0-gs.1: every field known to the CRD, the required fields, enums, the CEL rules the shapes can trip) and asserts no render of the chart carries kagent.dev/v1alpha2; a self-test proves the validator refuses an unknown field, a foreign provider block, a missing required field, a two-source header and a v1alpha2 object.
    • The muster MCP URL reaches the composers from one helper, agent-platform.musterMcpUrl (both charts: http://<muster.fullnameOverride>.<release namespace>.svc.cluster.local:<muster.service.port>/mcp while the muster component is on). The meta chart derives agent-manager’s chart value muster.url from it — next to flux.helmReleaseServiceAccount; a differing agent-manager.muster.url fails the render naming the source — and the connectivity chart renders it into the portal’s app-config as agentPlatform.musterMcpUrl. Both composers pass it to the Generic agent chart 1.x as muster.url, whose own default is the same URL on a default install (#299). make verify-identity, verify-wiring and verify-kagent-discovery assert it in both charts.
    • The connectivity chart is published on every branch push (push-connectivity-chart, in lockstep with the meta chart’s branch build: same commit, same version, gsoci and the test catalog), so a lab can follow a pull request’s connectivity chart through components.agent-platform-connectivity.versionRange + semverFilter; main publishes on tags only, as before.

    Removed

    • The shared RemoteMCPServer agent-platform/muster (allowedNamespaces.from: All, the cross-namespace contract the Generic agent chart 0.x’s default serverRef depended on). On kagent API v2 an AgentTemplate binds a RemoteMCPServer of its own namespace and the binding carries no headers, so the Generic agent chart 1.x renders one per agent — muster’s URL, STREAMABLE_HTTP, the X-Muster-Toolset header, the kagent.dev/discovery: disabled label — and binds it (giantswarm/agent#25); Helm deletes the shared object with the connectivity release on the upgrade (#299). make verify-kagent-discovery is re-scoped: no RemoteMCPServer of the platform’s own targets muster, nothing the platform renders for muster carries a static header, the operator extras render v1alpha3 in the kagent namespace with tokenSecret as a Secret-sourced Authorization header and no opt-out label. docs/authentication.md describes the per-agent carrier and the opt-out label the agent chart sets.
    • The two Kyverno ClusterPolicies that mutated the kagent controller’s input — <release>-kagent-declarative-pod-security (spec.declarative.deployment.*SecurityContext on every Agent) and <release>-kagent-srt-settings (enableWeakerNestedSandbox into the per-agent srt-settings.json Secret) — and their README text: no Agent CR, no per-agent Deployment and no config Secret exists on kagent API v2 (#299). kyvernoPolicies keeps its keys — the seccomp PolicyException (re-targeted at the Substrate worker pods in #342), the CNPG exception and agentSandbox.podSecurity read them. make verify-modes asserts the two kyverno.io objects of the kagent + agent-sandbox shape and the absence of any Agent mutation; make verify-auto asserts it on every cluster shape.
  • Added

    • components.<name>.semverFilter and gitops.self.semverFilter select a dev channel: a Go regexp rendered as OCIRepository.spec.ref.semverFilter, which Flux applies to the registry’s tags before it evaluates the semver range. With a prerelease-admitting range (>=3.0.0-0 <4.0.0-0) and the filter of one branch’s dev builds (.*-dev\.<sanitized-branch>\..*) a component — or, under self-management, the chart itself — follows that branch’s newest build and never falls back to a stable tag. Unset by default. The dead components.<name>.filterTags block (an ImagePolicy field, never an OCIRepository one, undeclared in the schema) is gone.

    Changed

    • BREAKING — meta chart 4.0: components.kagent delivers the kagent line (kagent API v2, kagent.dev/v1alpha3). components.kagent and the new roster entry components.kagent-crds resolve the charts kagent and kagent-crds of giantswarm/kagent-upstream (upstream kagent main at a pinned commit plus the carried patches) from oci://ghcr.io/giantswarm/kagent/helm on the line’s release range >=0.11.0-gs.1 <0.11.1-0 — the releases 0.11.0-gs.N of upstream 0.11.0, not the line’s 0.11.0-dev.giantswarm.… builds (Flux’s Masterminds semver compares prerelease identifiers left to right, dev < gs; the -0 on the ceiling admits prereleases at all, and the ceiling holds the patch because a prerelease is confined to no patch tuple; a bare 0.11.0 would be admitted, should upstream’s release ever appear at this OCI path) — instead of the giantswarm/kagent 0.x wrapper (kagent 0.10, v1alpha2) from gsoci. kagent-crds renders the five v1alpha3 CRDs as templates carrying helm.sh/resource-policy: keep (no crds/ dir, no crds: policy), follows components.kagent unless switched explicitly (agent-platform.componentEnabled), the kagent release and the connectivity release dependsOn it, and the render refuses kagent on without it (agent-platform.validateKagentCrds). The kagent: block names one build of the line: registry: ghcr.io, the fork’s image names (giantswarm/kagent/{controller,golang-adk,ui}), an explicit tag equal to the chart version of the build (upstream’s chart falls back to .Chart.Version, which under helm-controller is <version>+<oci digest>, an invalid image tag), kagent.harness.image — the Go ADK image by digest the connectivity chart renders the platform Harness from (the CRD accepts no tag) — controller.substrate.* (ate-api, atenet-router in ate-system, the default WorkerPool) and substrateWorkerPool (kagent-default, four gVisor workers on the Giant Swarm Substrate line’s worker image), pgvector on the bundled Postgres; a re-pin of the line moves the tag, the digest and the two ranges together from the fork’s builds.md ledger (README “Re-pinning the kagent line”). Every sibling range selects the kagent API v2 line: agent-platform-connectivity >=4.0.0 <5.0.0 (its own major; the 3.x line held <4.0.0), agent-manager and backstage 1.x (their 1.0 releases; until published the ranges resolve nothing — both are off by default), model-manager >=0.20.0 <1.0.0 (0.20.0 renders the ModelConfig version the cluster serves; the line stays 0.x); no semverFilter anywhere by default, gitops.self.semverFilter empty. agent-manager.agentChart.semver defaults to 1.x (was x.x.x, which would have rolled the Generic agent chart 1.0.0 to every existing agent the moment it is published). examples/customer-bom.yaml pins the line (kagent and kagent-crds 0.11.0-gs.1 — the same release, one build — agent-platform-connectivity 4.0.0, agent-manager and backstage 1.0.0, model-manager 0.20.0). Every installation acts (UPGRADE.md “3.x → 4.0”): the release is inert until the fleet’s agent-platform range bound (<4.0.0) is lifted per installation; a 4.0 installation with kagent on needs Kubernetes 1.35 with the ClusterTrustBundle, ClusterTrustBundleProjection and PodCertificateRequest feature gates and Agent Substrate in ate-system. make verify-meta (tests/verify-kagent-wiring.py, with tests/fluxsemver.py reimplementing Flux’s constraint semantics offline) asserts the sources, the range’s admitted and refused shapes, one build (tag and range on one upstream version, the Harness image a digest), the omitted keys and the retired ones; make verify-components the sibling ranges, kagent-crds following kagent and the BOM; make verify-components-charts pulls the managers’ and the kagent line’s charts at what the ranges resolve to (the way Flux resolves, -gs.N prereleases included) and renders the forwarded blocks against them — while a range waits for an unpublished release (a sibling’s 1.0, the line’s first tag) it renders against the build kagent.tag names or the newest 0.x and says so.

    Removed

    • The ten bundled example agents’ value blocks (kagent.k8s-agent … kagent.cilium-debug-agent, each enabled: false with namespaceOverride: kagent), kagent.controller.skillsInitImage and the METRICS_BIND_ADDRESS / METRICS_SECURE entries of kagent.controller.env: the kagent line ships none of the agents and no skills-init image, and its controller serves no Prometheus /metrics. With that kagent.serviceMonitor.enabled defaults to false in both charts and the forwarded kagent.controller.metrics.enabled is false explicitly — the connectivity chart’s controller metrics Service and ServiceMonitor and upstream’s metrics Service would point at a port nothing listens on and sit at up=0; nothing reads those metrics (the fleet’s KagentControllerDown reads kube-state-metrics). make verify-global asserts the default renders no kagent monitor and that kagent.serviceMonitor.enabled: true still renders it under the global gate; both go back on when upstream serves metrics. The ATS kind smoke keeps kagent and agent-manager off and skips the agent round trips with the reason while the cluster has neither the feature gates nor Substrate (tests/ats/values-kagent.yaml, KAGENT_ON); agentlab proves them, giantswarm/agent-platform#343 turns them back on.
  • Fixed

    • agent-manager.agentChart.semver is >=0.2.1 <1.0.0 (was x.x.x) in both charts. Generic agent chart 1.0.0 (published 2026-09-11) renders the kagent API v2 shape (kagent.dev/v1alpha3 AgentTemplate), which no 3.x installation can install; agent-manager composes this range into the per-namespace agent OCIRepository it writes on every create_agent, and the meta chart’s explicit forward wins over agent-manager 0.4.5’s own bounded default — so an open range here pulled 1.0.0 into every new managed namespace (the ATS round trip on this branch reproduced it: HelmRelease ats-managed-agent InstallFailed no matches for kind AgentTemplate). The three pre-existing per-namespace OCIRepository objects were bounded by hand already; this makes every future one bounded too. Every installation with agent-manager on rolls the agent-manager pod once (--agent-chart-semver changes); nothing else in the render differs. The 4.0 line moves the range to 1.x.
  • Fixed

    • (agent-manager) Compose the bounded agent chart range on the 3.x line

    Full Changelog: https://github.com/giantswarm/agent-platform/compare/v3.22.8...v3.22.9

  • Changed

    • The agentgateway data plane runs the Giant Swarm line of agentgateway: the connectivity chart’s agentgateway.proxy.image.tag (rendered into AgentgatewayParameters) is v1.5.1-gs.1 — upstream v1.5.0 rebuilt, scanned and signed in giantswarm/agentgateway-upstream (its FORK.md; tracking giantswarm/giantswarm#37758) and mirrored into gsoci by the retagger — the same release the giantswarm/agentgateway packaging chart pins for the controller, so a fix the platform needs in agentgateway can be carried on the line and reaches every installation as the next -gs.N release. Every installation with the agentgateway component on rolls its data-plane pods once to an image built from the same source as before; nothing else in the render changes.
  • Changed

    • components.agent-platform-connectivity.versionRange is >=1.0.0 <4.0.0 (was >=1.0.0, open upwards). The connectivity chart is released off the same tag as this chart and every installation’s Flux re-resolves the range on each reconcile of the connectivity OCIRepository, so the first v4.0.0 tag of this repository – the kagent API v2 line (giantswarm/giantswarm#37705), whose connectivity templates render kagent.dev/v1alpha3 objects – would have upgraded the wiring of every 3.x installation within minutes, ahead of its cut-over (#348). The 3.x line now stays on its own wiring chart; 4.0 resets the range to its line. No installation needs to act: the connectivity OCIRepository’s spec.ref.semver changes (a Flux spec update; the current 3.x release stays resolved) and nothing else in the render differs. make verify-components asserts the bound.