Human-in-the-Loop with kagent#
AI agents that can take action are powerful — but you don't always want them acting without your say-so. This tutorial walks you through building a Kubernetes-native AI agent that pauses and asks for your approval before doing anything destructive.
What You'll Build#
By the end of this tutorial, you'll have an agent running on a local Kind cluster that:
- Reads cluster resources freely (no approval needed)
- Pauses for your approval before creating, modifying, or deleting resources
- Asks you questions when it needs more information
Prerequisites#
Make sure you have these installed before starting:
| Tool | Install Link |
|---|---|
| Docker | get-docker |
| Kind | quick-start |
| kubectl | install-tools |
| Helm | install |
You'll also need an OpenAI API key.
Step 1 — Create a Kind Cluster#
Spin up a local Kubernetes cluster:
kind create cluster --name kagent-hitl
Verify it's running:
kubectl cluster-info --context kind-kagent-hitl
You should see the control plane address printed. If so, you're good to go.
Step 2 — Install kagent#
There are two Helm charts to install: the CRDs first, then kagent itself.
Install the CRDs:
helm install kagent-crds oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds \--namespace kagent \--create-namespace
Set your API key:
export OPENAI_API_KEY="your-api-key-here"
Install kagent:
helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent \--namespace kagent \--set providers.default=openAI \--set providers.openAI.apiKey=$OPENAI_API_KEY
Wait for everything to come up:
kubectl wait --for=condition=ready pod --all -n kagent --timeout=120s
Once all pods report condition met, move on.
Step 3 — Deploy the Agent#
This is the core of the tutorial. You'll create an agent that uses kagent's built-in Kubernetes tools (served via the kagent tool server), with approval gates on the destructive ones.
Save this as hitl-agent.yaml:
apiVersion: kagent.dev/v1alpha2kind: Agentmetadata:name: hitl-agentnamespace: kagentspec:description: A Kubernetes agent with human-in-the-loop approval for destructive operations.type: Declarativedeclarative:modelConfig: default-model-configsystemMessage: |You are a Kubernetes management agent. You help users inspect and manageresources in the cluster. Before making any changes, explain what youplan to do. If the user's request is ambiguous, use the ask_user toolto clarify before proceeding.tools:- type: McpServermcpServer:name: kagent-tool-serverkind: RemoteMCPServerapiGroup: kagent.devtoolNames:- k8s_get_resources- k8s_describe_resource- k8s_get_pod_logs- k8s_get_events- k8s_get_resource_yaml- k8s_apply_manifest- k8s_delete_resource- k8s_patch_resourcerequireApproval:- k8s_apply_manifest- k8s_delete_resource- k8s_patch_resource
Create the agent:
kubectl apply -f hitl-agent.yaml
Here's what each tool does:
| Tool | What Happens |
|---|---|
k8s_get_resources | Runs immediately — lists pods, services, deployments, etc. |
k8s_describe_resource | Runs immediately — shows resource details |
k8s_get_pod_logs | Runs immediately — reads pod logs |
k8s_get_events | Runs immediately — shows cluster events |
k8s_get_resource_yaml | Runs immediately — exports resource YAML |
k8s_apply_manifest | Pauses for approval — creates or updates resources |
k8s_delete_resource | Pauses for approval — deletes resources |
k8s_patch_resource | Pauses for approval — modifies resources |
ask_user | Built-in on every agent — asks you questions anytime |
The key is requireApproval — any tool listed there will pause execution until you explicitly approve it. Read-only tools run freely; write operations need your sign-off.
Step 4 — Open the UI#
Port-forward the kagent dashboard:
kubectl port-forward -n kagent svc/kagent-ui 8080:8080
Open http://localhost:8080 in your browser. You should see the kagent UI with your hitl-agent listed.
Step 5 — Try It Out#
Now for the fun part. Run through these tests to see human-in-the-loop in action.
Test 1: Read Without Approval#
- Select the hitl-agent in the UI
- Type:
List all pods in the kagent namespace - The agent calls
k8s_get_resources— it runs immediately with no approval prompt - You see the pod listing right away
This shows that read-only tools are not gated.
Test 2: Approve a Create#
- Type:
Create a ConfigMap called test-config in the default namespace with the key message set to "hello from kagent" - The agent calls
k8s_apply_manifest— execution pauses - You'll see Approve / Reject buttons appear, along with the YAML it wants to apply
- Click Approve
- The agent creates the ConfigMap and confirms
Test 3: Reject a Delete#
- Type:
Delete the ConfigMap test-config in the default namespace - The agent calls
k8s_delete_resource— execution pauses - Click Reject and enter a reason:
I want to keep this ConfigMap for now - The agent sees your reason and responds accordingly — it doesn't delete anything
Test 4: Agent Asks You a Question#
- Type:
Set up a namespace for my application - The request is vague, so the agent calls
ask_userto clarify (e.g., "What should the namespace be called?") - Answer the question and the agent continues with your input
How It Works#
The flow is straightforward:
You send a message
-> Agent decides which tool to call
-> Is the tool in requireApproval?
-> YES: Execution pauses, you see Approve/Reject in the UI
-> Approve: tool runs normally
-> Reject: agent receives your reason and adapts
-> NO: Tool runs immediately
The ask_user tool works the same way — the agent pauses, you answer, and it continues. Both use the same underlying confirmation mechanism, which keeps things simple.
Cleanup#
Delete the cluster when you're done:
kind delete cluster --name kagent-hitl
Key Takeaways#
requireApprovalis all you need — list the tools that need human sign-off- Read-only tools run freely, write operations pause for approval
ask_useris built-in on every agent — no extra config required- Rejection reasons are sent back to the LLM so it can adjust its approach