Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ jobs:
replicas: 0
kagent-tools:
enabled: false
# The lifecycle suite applies its own Harness named kagent.
builtins:
harness:
enabled: false
substrateWorkerPool:
create: true
replicas: 4
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ helm-version: helm-cleanup
helm package -d "$(HELM_DIST_FOLDER)" "$(HELM_SOURCE_DIR)/kagent-crds"
helm package -d "$(HELM_DIST_FOLDER)" "$(HELM_SOURCE_DIR)/kagent"

.PHONY: builtin-skills-catalog
builtin-skills-catalog: ## Regenerate the built-in skills catalog from the kagent-tools image
bash scripts/builtin-skills-catalog.sh > "$(HELM_SOURCE_DIR)/kagent/files/builtin-skills.json.tmp"
mv "$(HELM_SOURCE_DIR)/kagent/files/builtin-skills.json.tmp" "$(HELM_SOURCE_DIR)/kagent/files/builtin-skills.json"

.PHONY: helm-dev
helm-dev: ## Prepare development charts with the images published by local builds
@test -d "$(RUNTIME_BUILD_METADATA_DIR)" || { echo "Missing runtime image metadata. Run make build before preparing development charts." >&2; exit 1; }
Expand Down
2 changes: 1 addition & 1 deletion helm/kagent/Chart-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ annotations:
"org.opencontainers.image.source": "https://github.com/kagent-dev/kagent"
dependencies:
- name: kagent-tools
version: 0.3.0
version: 0.3.1
repository: oci://ghcr.io/kagent-dev/tools/helm
condition: kagent-tools.enabled
- name: oauth2-proxy
Expand Down
20 changes: 20 additions & 0 deletions helm/kagent/files/builtin-skills.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"image": "ghcr.io/kagent-dev/kagent/tools@sha256:607cb0ac95c9905529ad1cfebeff3aa2fbf68aa81861ed3bbba9d71a7477d640",
"skills": [
{
"name": "helm-release-management",
"description": "Inspect, upgrade, roll forward and uninstall Helm releases with the kagent-tools helm_* MCP tools. Use for questions about installed charts, release status, values, failed upgrades, or adding chart repositories.",
"path": "opt/kagent-tools-skills/skills/helm-release-management"
},
{
"name": "istio-traffic-debugging",
"description": "Debug Istio service-mesh traffic (503s, mTLS failures, routing not applied, sidecar or ambient/waypoint issues) using the kagent-tools istio_* MCP tools. Use when requests between mesh services fail or routing rules do not take effect.",
"path": "opt/kagent-tools-skills/skills/istio-traffic-debugging"
},
{
"name": "k8s-troubleshooting",
"description": "Diagnose unhealthy Kubernetes workloads (CrashLoopBackOff, Pending, ImagePullBackOff, OOMKilled, failing readiness, unreachable Services) using the kagent-tools k8s_* MCP tools. Use when a pod, deployment or service is not working as expected.",
"path": "opt/kagent-tools-skills/skills/k8s-troubleshooting"
}
]
}
23 changes: 23 additions & 0 deletions helm/kagent/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,29 @@
{{- $images | mustToJson -}}
{{- end -}}

{{/*
The built-in skills catalog as JSON. builtins.skills.image and builtins.skills.list
replace the packaged catalog. Empty when turned off.
*/}}
{{- define "kagent.builtinSkillsCatalog" -}}
{{- if and (dig "builtins" "enabled" false .Values.AsMap) (dig "builtins" "skills" "enabled" false .Values.AsMap) -}}
{{- $catalog := .Files.Get "files/builtin-skills.json" | mustFromJson -}}
{{- with .Values.builtins.skills.image -}}
{{- $catalog = dict "image" . "skills" ($.Values.builtins.skills.list | default (list)) -}}
{{- end -}}
{{- if not (regexMatch "^[^[:space:]@]+@sha256:[0-9a-f]{64}$" $catalog.image) -}}
{{- fail (printf "builtins.skills.image must be pinned by sha256 digest: %q" $catalog.image) -}}
{{- end -}}
{{- range $catalog.skills -}}
{{- if not (and .name .path) -}}
{{- fail (printf "builtins.skills.list: each skill needs a name and a path, got %s" (mustToJson .)) -}}
{{- end -}}
{{- end -}}
{{- $_ := set $catalog "image" (include "kagent.mirroredImage" (dict "root" $ "image" $catalog.image)) -}}
{{- $catalog | mustToJson -}}
{{- end -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
*/}}
Expand Down
19 changes: 19 additions & 0 deletions helm/kagent/templates/default-harness.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- if and (dig "builtins" "enabled" false .Values.AsMap) (dig "builtins" "harness" "enabled" false .Values.AsMap) .Values.substrateWorkerPool.create }}
{{- if not .Values.builtins.harness.snapshotLocation }}
{{- fail "builtins.harness.snapshotLocation is required: set the snapshot storage location for the default Harness" }}
{{- end }}
apiVersion: api.kagent.dev/v1alpha3
kind: Harness
metadata:
name: {{ .Values.builtins.harness.name | quote }}
namespace: {{ include "kagent.namespace" . }}
labels:
{{- include "kagent.labels" . | nindent 4 }}
spec:
kagent: {}
substrate:
workerPoolRef:
name: {{ .Values.substrateWorkerPool.name | quote }}
snapshotPolicy:
location: {{ .Values.builtins.harness.snapshotLocation | quote }}
{{- end }}
80 changes: 80 additions & 0 deletions helm/kagent/templates/k8s-agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{{- $catalog := include "kagent.builtinSkillsCatalog" . | default "{}" | mustFromJson }}
{{- $skill := dict }}
{{- range $catalog.skills | default (list) }}
{{- if eq .name "k8s-troubleshooting" }}{{ $skill = . }}{{ end }}
{{- end }}
{{- if and (dig "builtins" "enabled" false .Values.AsMap) (dig "builtins" "k8sAgent" "enabled" false .Values.AsMap) (dig "builtins" "harness" "enabled" false .Values.AsMap) .Values.substrateWorkerPool.create (index .Values "kagent-tools" "enabled") $skill }}
{{- $toolServer := printf "%s-tool-server" (include "kagent.fullname" .) }}
apiVersion: api.kagent.dev/v1alpha3
kind: Agent
metadata:
name: {{ .Values.builtins.k8sAgent.name | quote }}
namespace: {{ include "kagent.namespace" . }}
labels:
{{- include "kagent.labels" . | nindent 4 }}
spec:
harnessRef:
name: {{ .Values.builtins.harness.name | quote }}
template:
inline:
description: "Kubernetes assistant: finds and fixes problems with workloads in the cluster where kagent runs."
modelConfig:
name: {{ include "kagent.defaultModelConfigName" . }}
promptTemplate:
dataSources:
- name: kagent-builtin-prompts
alias: builtin
systemPrompt: |
You help users run and troubleshoot workloads in the Kubernetes cluster
where kagent runs. When a question matches one of your skills, load that
skill and follow it.

{{`{{include "builtin/skills-usage"}}`}}

{{`{{include "builtin/kubernetes-context"}}`}}

{{`{{include "builtin/tool-usage-best-practices"}}`}}

{{`{{include "builtin/safety-guardrails"}}`}}
tools:
- mcp:
server:
kind: RemoteMCPServer
name: {{ $toolServer }}
tools:
- k8s_describe_resource
- k8s_generate_resource
- k8s_get_available_api_resources
- k8s_get_cluster_configuration
- k8s_get_events
- k8s_get_pod_logs
- k8s_get_resource_yaml
- k8s_get_resources
- k8s_wait
# These tools change the cluster, so each call waits for the user's approval.
- mcp:
server:
kind: RemoteMCPServer
name: {{ $toolServer }}
requireApproval: true
tools:
- k8s_annotate_resource
- k8s_apply_manifest
- k8s_check_service_connectivity
- k8s_create_resource
- k8s_create_resource_from_url
- k8s_delete_resource
- k8s_execute_command
- k8s_label_resource
- k8s_patch_resource
- k8s_patch_status
- k8s_remove_annotation
- k8s_remove_label
- k8s_rollout
- k8s_scale
skills:
- name: {{ $skill.name | quote }}
source:
oci: {{ $catalog.image | quote }}
path: {{ $skill.path | quote }}
{{- end }}
3 changes: 3 additions & 0 deletions helm/kagent/templates/ui-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ data:
{{- if .Values.ui.streamTimeoutSeconds }}
KAGENT_UI_STREAM_TIMEOUT_MS: {{ mul (int .Values.ui.streamTimeoutSeconds) 1000 | quote }}
{{- end }}
{{- with include "kagent.builtinSkillsCatalog" . }}
KAGENT_UI_BUILTIN_SKILLS: {{ . | quote }}
{{- end }}
78 changes: 78 additions & 0 deletions helm/kagent/tests/default-harness_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
suite: test the default Harness
templates:
- default-harness.yaml
release:
namespace: kagent
set:
substrateWorkerPool.create: true
substrateWorkerPool.workerImage: ghcr.io/kagent-dev/substrate/ateworker-gvisor:v1
tests:
- it: creates a Go ADK Harness on the chart's worker pool
asserts:
- isKind:
of: Harness
- equal:
path: metadata.name
value: kagent
- equal:
path: metadata.namespace
value: kagent
- exists:
path: spec.kagent
- equal:
path: spec.substrate.workerPoolRef.name
value: kagent-default
- equal:
path: spec.substrate.snapshotPolicy.location
value: s3://ate-snapshots/kagent/

- it: uses the configured name, pool and snapshot location
set:
builtins.harness.name: team
builtins.harness.snapshotLocation: gs://bucket/team/
substrateWorkerPool.name: other-pool
asserts:
- equal:
path: metadata.name
value: team
- equal:
path: spec.substrate.workerPoolRef.name
value: other-pool
- equal:
path: spec.substrate.snapshotPolicy.location
value: gs://bucket/team/

- it: renders nothing when turned off
set:
builtins.harness.enabled: false
asserts:
- hasDocuments:
count: 0

- it: renders nothing when all built-ins are turned off
set:
builtins.enabled: false
asserts:
- hasDocuments:
count: 0

- it: renders nothing when the built-ins values are missing
set:
builtins: null
asserts:
- hasDocuments:
count: 0

- it: requires a snapshot location
set:
builtins.harness.snapshotLocation: ""
asserts:
- failedTemplate:
errorMessage: "builtins.harness.snapshotLocation is required: set the snapshot storage location for the default Harness"

- it: renders nothing without the chart's worker pool
set:
substrateWorkerPool.create: false
asserts:
- hasDocuments:
count: 0
Loading
Loading