Skip to content
giantswarmPublic

About

Helm chart to deploy a kagent declarative agent

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

CircleCI

agent chart

The generic Helm chart for creating kagent agents on the Giant Swarm Agent Platform. One chart release = one agent: the chart renders the agent's Agent (api.kagent.dev/v1alpha3) with its template inline (spec.template: what the agent is: prompt, model, skills, plugins, tools) and the platform Harness referenced by name (spec.harnessRef: how it runs), and, unless the agent is chat-only, the agent's own muster RemoteMCPServer, the carrier of its toolset.

The design: one release of this chart per agent, with the agent's own muster RemoteMCPServer carrying its toolset. Charts 1.x and 2.x target the kagent API v2 shape, where how an agent runs is a separate Harness the agent references.

What the chart does — and deliberately does not — render

The chart renders, in the release namespace and named after the agent:

  • the Agent: spec.template carries the description, the system prompt, the ModelConfig by name, the skills and plugins (immutable sources) and the tool bindings; spec.harnessRef names the Harness that runs it (agent.harness, default kagent). The object carries the annotations ui.giantswarm.io/display-name and ui.giantswarm.io/icon-url the Dev Portal reads. No admission label: the Agent selects its Harness, the Harness admits nothing;
  • the RemoteMCPServer pointing at muster's MCP endpoint (muster.url), STREAMABLE_HTTP, with the agent's toolset as the static X-Muster-Toolset header and the label kagent.dev/discovery: disabled (muster is an OAuth resource server; the controller has no user token to discover tools with). Never an Authorization header: the Harness propagates the signed-in person's token, and a static header would override it. The Agent's template binds this server. Not rendered for a chat-only agent (toolset: ["preset:none"]) or with muster.enabled: false.

It never touches:

  • the Harness — platform-owned (rendered by the agent-platform connectivity chart); it decides the runtime image, the token propagation, the Substrate worker pool, capacity and placement. An Agent whose Harness does not exist in its namespace reports ResolvedRefs=False and never becomes Ready;
  • ModelConfig CRs and the Secrets they reference (LLM credentials) — platform-owned, provisioned per tenant namespace. The chart wires the agent to one by name (modelConfig.name, default default-model-config).

Usage

Install with whatever you already use for Helm charts (Argo CD, Flux HelmRelease, helm install). A minimal values file yields a working agent:

agent:
  displayName: "SRE Assistant"        # Unicode, becomes the ui.giantswarm.io/display-name annotation
  description: Helps the SRE team triage incidents.
  systemMessage: |
    You are an SRE assistant. Be concise.

skills:
  - name: sre-runbooks
    git:
      url: https://github.com/example/agent-skills
      commit: 0123456789abcdef0123456789abcdef01234567   # a full commit id, never a branch
    path: sre-runbooks

labels:
  giantswarm.io/owner: sre-team

The technical resource name defaults to the Helm release name. By default the agent is wired to the platform's muster gateway with all of its (dynamic) tools — implicit full access to everything the gateway exposes to the invoking human. Declare a toolset to compose the agent with a subset:

toolset:
  - preset:read-only            # a preset muster knows (built in: read-only, none, full;
  - workflow:incident-triage    #   the platform ships infrastructure and agent-platform)
  - server:mcp-kubernetes       # every tool of one MCP server
  - tool:x_mcp-prometheus_query # one exposed tool

The chart renders the selectors as the static X-Muster-Toolset header on the agent's RemoteMCPServer (spec.headersFrom, joined by ,); muster resolves it on every request, so the agent's meta-tools list and call only what the toolset selects. Exactly ["preset:none"] renders no RemoteMCPServer and no muster binding at all — a chat-only agent. An empty list fails the render (say preset:none), more than 32 inline selectors fail (define a preset), and toolset:<name> is reserved. Composition, not authorization: the human's identity and the backends' own authorization remain the boundary. The agent gets no wider access of its own.

muster.tools narrows the binding to a subset of muster's meta-tools (list_tools, call_tool, ...), not the tools behind the gateway — a toolset is the way to narrow those. A Harness enforces a partial selection only when it can discover the server's tools; with discovery off (the default) it may expose the whole server and report a warning in the Agent's status.warnings.

Skills are pinned

A skill source is immutable: a git repository at a full 40- or 64-hex commit id, or an image at a @sha256: digest. A branch, a tag, a short SHA or an image tag fails helm template with a message naming the field — the same rule the Agent CRD enforces at admission, applied where the values are written. The agent-creation flows (agent-manager, the Dev Portal) resolve the branch a skill is picked from to its head commit and re-pin on request; the chart itself carries no branch.

Plugins

A plugin is an Agent Plugins bundle: one immutable source (pinned like a skill) and the names of the bundle's skills to enable. Nothing else in the bundle reaches the agent:

plugins:
  - git:
      url: https://github.com/example/agent-plugins
      commit: 0123456789abcdef0123456789abcdef01234567
    path: bundles/sre
    skills: [triage, postmortem]
  - oci: registry.example.io/plugins/sre@sha256:<digest>
    skills: [k8s]

Rendered into spec.template.plugins[] as {source: {git | oci, path}, skills}. The schema refuses an entry without a source, with two sources, with a mutable source or without at least one skill name.

Private skill repositories

One chart value covers every private git skill and git plugin of an agent; authors do not pick a credential per skill:

skillsGitAuthSecretRef:
  name: kagent-skills-token   # a Secret in the agent's namespace, key `token`

When set, every skills[] and plugins[] entry with git renders source.git.credentialRef: {name, key: token}; OCI sources are unchanged. Every git skill and plugin then needs an https:// URL: the CRD refuses a credential on any other source and the chart fails the render first, naming the entry. The platform side of the contract (the egress gateway, the credential provider, agent-manager's minted Secret) is agent-platform's Private skill repositories (under "The kagent line").

  • Who provisions it, where. The tenant, in the agent's namespace (on the platform: the kagent namespace, where the agents are compiled), labelled ui.giantswarm.io/agent-skills-git-auth: "true" so the Dev Portal offers it; or agent-manager, which mints and refreshes agent-manager-skills-token from its skills GitHub App when the installation turns that on. The chart never creates it.
  • Shape. The key token holds base64("<username>:<token>") — on GitHub x-access-token:<token>, a fine-grained PAT or App installation token with read access to the repositories — the value the egress gateway sends as Authorization: Basic.
  • One credential per host. It goes with every request to that host, public repositories included; two Secrets for one host in an agent are refused.
  • Rotation. Replace the Secret's contents, never its name. The egress gateway reads the Secret on every fetch, so a new token needs no restart; a new name is an edit of every referencing agent and a new revision of each.
  • Where the token is visible. In the Secret, to whoever may read Secrets in its namespace, and to the platform's credential provider and egress gateway, which send it to the source's host over TLS. Not in the Agent, the actor's environment (it holds a placeholder) or the snapshots.

What an author sees when it goes wrong (the Agent's conditions, see Readiness):

Symptom Cause
Ready=False ActorTemplateRetrying quoting the git fetch's failure, then ActorTemplateFailed (golden boot 6 of 6 failed (…); no retries left) the Secret is missing, the token is wrong or lacks read access, or the namespace has no credential-provider policy (atespace "ate-golden" is not permitted to resolve secrets)
Compatible=False UnsupportedConfiguration (conflicting credentials for <host> header authorization) two credentials for one host

The field needs the kagent line 1.1.0 or later (giantswarm/kagent-upstream, the platform's line), where the egress gateway injects the credential.

Readiness

The Agent reports its own readiness on the Harness it names:

kubectl -n <namespace> get agent.api.kagent.dev <name> -o jsonpath='{.status}'

Conditions Accepted, ResolvedRefs, Compatible and Ready, with desiredRevision against latestSuccessfulRevision and warnings. ResolvedRefs=False naming the Harness means agent.harness names a Harness that does not exist in the agent's namespace.

Values

See the chart values reference for all available values and their defaults.

values.schema.json encodes the curated contract (additionalProperties: false), so bad values (including every 0.x value that has no place in 2.x) fail with a legible error before anything hits the cluster.

Upgrades are values changes plus a re-apply; uninstalling the release removes the agent. Pin the chart version for reproducibility.

Migrating from 1.x

Chart 2.0 renders the kagent API that ships the Agent kind (api.kagent.dev/v1alpha3, kagent-dev/kagent#2952): one Agent named after the release, the template inline under spec.template, the Harness by name in spec.harnessRef, plus the per-agent RemoteMCPServer in the new group. No kagent.dev/v1alpha3 AgentTemplate is rendered, and the admission label is gone with Harness.spec.allowedAgentTemplates. The chart installs only on a platform that serves api.kagent.dev; an upgrade of a 1.x release replaces the AgentTemplate with an Agent of the same name. The values contract is the 1.x one plus plugins:

1.x value 2.x What changed
agent.harness same name, default kagent now spec.harnessRef.name, a reference the Agent resolves in its namespace; the label agent-platform.giantswarm.io/harness is no longer rendered and no Harness selector is involved
agent.name, agent.displayName, agent.description, agent.iconUrl, agent.systemMessage, modelConfig.name, skills, skillsGitAuthSecretRef, muster.*, toolset unchanged the template fields move under spec.template; the annotations stay on the object
— plugins[] (new, empty) {git | oci, path, skills[]} entries rendered into spec.template.plugins[]; same pinning rules and credential as skills
extraTools same list a sub-agent binding is {subAgent: {name, description, templateRef}} instead of {agent: {...}}
extraAgentSpec unchanged deep-merges into spec.template only, never into spec.harnessRef
labels unchanged an extra agent-platform.giantswarm.io/harness label is rendered as given and means nothing to the platform
context.compaction unchanged still accepted, still renders nothing

Migrating from 0.x

Chart 1.0 renders the kagent API v2 shape (kagent.dev/v1alpha3): an AgentTemplate plus a per-agent RemoteMCPServer instead of a kagent.dev/v1alpha2 Agent. It installs only on a platform that serves that API, and the values contract changes with it. Value by value:

0.x value 1.x What changed
agent.name, agent.displayName, agent.description, agent.systemMessage unchanged systemMessage renders into spec.systemPrompt; the display name stays the ui.giantswarm.io/display-name annotation
agent.iconUrl unchanged rendered as the ui.giantswarm.io/icon-url annotation (the template has no icon field)
agent.runtime removed the Harness is the runtime; the platform Harness runs the Go ADK
— agent.harness (new, default kagent) the value of the admission label agent-platform.giantswarm.io/harness
modelConfig.name unchanged renders into spec.modelConfig.name
skills.refs[] (image references) skills[].{name, oci} a digest-pinned reference <ref>@sha256:<digest>; a tag is refused
skills.gitRefs[] ({url, ref, path}) skills[].{name, git: {url, commit}, path} a full commit id; a branch, tag or short SHA is refused; names are unique
skills.gitAuthSecretRef ({name}) skillsGitAuthSecretRef.name (since 1.2) a sibling of the skills list; one Secret (key token) rendered as credentialRef on every git skill; every git skill needs an https URL
muster.enabled unchanged gates the RemoteMCPServer and the binding
muster.serverRef.* removed the chart renders the agent's own RemoteMCPServer, named after the agent, in its namespace
muster.allowedHeaders removed the Harness propagates the caller's token (KAGENT_PROPAGATE_TOKEN)
muster.toolNames muster.tools the binding's tools (muster's meta-tools)
muster.stsWellKnownUri removed the platform's dex-only trust model has no token exchange
— muster.url (new) muster's MCP endpoint; default http://muster.agent-platform.svc.cluster.local:8090/mcp
— muster.discovery.enabled (new, default false) false labels the server kagent.dev/discovery: disabled
toolset unchanged the header moves to the RemoteMCPServer's spec.headersFrom; grammar and render failures unchanged
extraTools same list, v1alpha3 entries {mcp: {server: {kind: RemoteMCPServer, name}, tools, requireApproval}} or {agent: {name, description, templateRef}} instead of {type: McpServer, mcpServer: {...}}
replicas, resources, nodeSelector, tolerations removed capacity and placement are the Harness's worker pool — platform values
labels unchanged merged over the standard set on both objects
annotations unchanged merged next to the ui annotations on the AgentTemplate
extraAgentSpec unchanged deep-merges into the AgentTemplate spec (v1alpha3 fields) only — never into the RemoteMCPServer

Every removed value is refused by the values schema, so a stale composer fails the render instead of silently losing a field. The 0.x line lives on as chart 0.x (release-v0.x) for platforms that still run kagent 0.10.

About

Helm chart to deploy a kagent declarative agent

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages