Documentation

Add skills to agents#

Skills are descriptions of capabilities that help agents act more autonomously. They guide the agent's tool usage and planning by orienting responses toward goals rather than just reacting to prompts.

In this guide, you learn how to add container-based skills to your agents in kagent.

Before you begin#

  1. Install kagent by following the quick start guide.

  2. Review the concepts of agents and skills in kagent.

Container-based skills#

Container-based skills are executable skill implementations packaged as container images. These skills contain instructions, scripts, and other resources that the agent can discover and use at runtime. This way, you can reuse skills across agents.

Step 1: Build a skill container#

To create a container-based skill, package your skill files into a container image. This example creates a skill that deploys simple applications to Kubernetes.

  1. Create a skill directory with your skill files.

    mkdir k8s-deploy-skill
    cd k8s-deploy-skill
  2. Create a SKILL.md file with skill metadata and instructions. The file should include YAML frontmatter with the skill name and description, followed by detailed instructions for the agent.

    cat > SKILL.md <<'EOF'
    # Kubernetes simple deploy skill
    Use this skill when users want to deploy a basic app on the Kubernetes cluster.
    ## Instructions
    - Expect the user to provide the name for an app they wish to deploy, along with a docker image reference.
    Optionally they may supply number of replicas and port number, but these are not required, and have defaults.
    - Call the script `scripts/deploy-app.py` passing the supplied name, image, and optional parameters (# of replicas and port number) if supplied, in that order.
    - The script generates a correct two-resource manifest (Deployment + Service) and writes it to the file `temp-manifest.yaml`.
    You, the **agent**, are expected to apply the generated manifest `temp-manifest.yaml` against the current Kubernetes context.
    ## Example
    User: Deploy an app called "nginx" using image "docker/nginx" with 2 replicas on port 8080.
    Agent: Invokes `scripts/deploy-app.py nginx docker/nginx 2 8080`
    The skill creates a manifest named `temp-manifest.yaml` consisting of a Deployment + Service in one shot.
    The agent in turn applies the generated temp-manifest.yaml to the cluster.
    EOF

    The agent learns how to use the skill by reading this file. The instructions tell the agent when to use the skill, what parameters to expect, and how to invoke the scripts.

  3. Add any scripts or resources your skill needs.

    mkdir scripts
    cat > scripts/deploy-app.py <<'EOF'
    #!/usr/bin/env python3
    # deploy-app.py
    import sys
    from pathlib import Path
    from textwrap import dedent
    def generate_manifest(app_name, image, replicas=1, port=80):
    """Generate valid Kubernetes YAML using only built-in Python"""
    manifest = f"""\
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: {app_name}
    labels:
    app: {app_name}
    spec:
    replicas: {replicas}
    selector:
    matchLabels:
    app: {app_name}
    template:
    metadata:
    labels:
    app: {app_name}
    spec:
    containers:
    - name: {app_name}
    image: {image}
    ports:
    - containerPort: {port}
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: {app_name}
    labels:
    app: {app_name}
    spec:
    type: ClusterIP
    selector:
    app: {app_name}
    ports:
    - port: 80
    targetPort: {port}
    protocol: TCP
    """
    # Clean dedent + write
    clean_yaml = dedent(manifest).strip() + "\n"
    file_path = Path("temp-manifest.yaml")
    file_path.write_text(clean_yaml, encoding="utf-8")
    return str(file_path)
    def print_usage():
    print("""Kubernetes Zero-Dependency Deploy
    Usage:
    python deploy-app.py <name> <image> [replicas] [port]
    Examples:
    python deploy-app.py web nginx:latest
    python deploy-app.py api ghcr.io/myorg/api:v2 3 5000
    python deploy-app.py redis redis:7.2 1 6379
    No pip, no yaml, no problem.
    """)
    if __name__ == "__main__":
    args = sys.argv[1:]
    if not args or "-h" in args or "--help" in args:
    print_usage()
    sys.exit(0)
    if len(args) < 2:
    print("Error: Need <name> <image>")
    print_usage()
    sys.exit(1)
    app_name = args[0]
    image = args[1]
    replicas = 1
    port = 80
    # Parse optional positional numeric args: [replicas] [port]
    if len(args) > 2:
    if args[2].isdigit():
    replicas = int(args[2])
    else:
    print(f"Error: replicas must be a number, got '{args[2]}'")
    sys.exit(1)
    if len(args) > 3:
    if args[3].isdigit():
    port = int(args[3])
    else:
    print(f"Error: port must be a number, got '{args[3]}'")
    sys.exit(1)
    if len(args) > 4:
    print("Error: Too many arguments")
    print_usage()
    sys.exit(1)
    # Optional: validate reasonable ranges
    if replicas < 1:
    print("Error: replicas must be >= 1")
    sys.exit(1)
    if not (1 <= port <= 65535):
    print("Error: port must be between 1 and 65535")
    sys.exit(1)
    print(f"Deploying {app_name}")
    print(f" Image: {image}")
    print(f" Replicas: {replicas}")
    print(f" Container port: {port} → Service port: 80")
    print()
    path = generate_manifest(app_name, image, replicas, port)
    print(f"Manifest saved → {path}")
    print()
    print("Next:")
    print(f" kubectl apply -f {path}")
    EOF
    chmod +x scripts/deploy-app.py

    The scripts perform the actual work. In this example, deploy-app.py generates Kubernetes manifests based on the parameters provided.

  4. Create a Dockerfile.

    cat > Dockerfile <<'EOF'
    FROM scratch
    COPY . /
    EOF
  5. For local testing, start a Docker registry on your local host. Before building and pushing to a localhost registry, check if you already have one running.

    docker ps | grep registry
    • If you see a registry container, note the port mapping (for example, 127.0.0.1:5001->5000/tcp means the registry is accessible on port 5001).
    • If no registry is running, start one.
    docker run -d -p 5000:5000 --restart=always --name local-registry registry:2

    If your registry is on a different port (like 5001), use that port in the following commands instead of 5000.

  6. Build and push the image to a container registry. You can push skill containers to any container registry:

    • Localhost registry: localhost:PORT/skill-name:tag
    • Docker Hub: docker.io/username/skill-name:tag
    • GitHub Container Registry: ghcr.io/username/skill-name:tag
    • Google Container Registry: gcr.io/project/skill-name:tag
    • Amazon ECR: 123456789012.dkr.ecr.region.amazonaws.com/skill-name:tag
    • Any private registry: registry.example.com/skill-name:tag
    docker build -t localhost:5000/k8s-deploy-skill:latest .
    docker push localhost:5000/k8s-deploy-skill:latest

Step 2: Use container-based skills in an agent#

To load container-based skills into your agent, reference them in the spec.skills.refs field.

kubectl apply -f - <<EOF
apiVersion: kagent.dev/v1alpha2
kind: Agent
metadata:
name: k8s-assistant-with-skills
namespace: kagent
spec:
description: A Kubernetes AI agent with deployment skills
type: Declarative
skills:
# Only for development/testing (e.g., localhost registry)
insecureSkipVerify: true
refs:
# For Kind clusters, use kind-registry:5000 instead of localhost:5000
- kind-registry:5000/k8s-deploy-skill:latest
declarative:
modelConfig: default-model-config
stream: true
tools:
- type: McpServer
mcpServer:
name: kagent-tool-server
kind: RemoteMCPServer
toolNames:
- k8s_apply_manifest
- k8s_get_resources
- k8s_describe_resource
systemMessage: |
You are a Kubernetes assistant that helps users deploy and manage applications.
You have access to skills that can help automate common tasks.
EOF

When the agent starts, kagent automatically:

  1. Pulls the skill images using an init container.
  2. Extracts the skill files to /skills in the agent container.
  3. Makes them available to the agent through the SkillsTool.

The agent can then discover and load skills using the SkillsTool, which reads the SKILL.md files and makes the skill instructions available to the LLM.

Step 3: Test container-based skills#

After creating the agent, test it with queries that match your skills.

  1. Ask the agent what skills it has.

    kagent invoke --agent k8s-assistant-with-skills --task "What skills do you have?"

    Example output:

    {"artifacts":[{"artifactId":"91afd732-3fa5-4e25-8f0e-07a4968050e5","parts":[{"kind":"text","text":"I am a Kubernetes AI agent with deployment skills. I can help you deploy and manage Kubernetes applications by working with manifests, describing resources, getting resource details, and applying configurations to your Kubernetes cluster. However, currently, I do not have any additional specialized skills loaded beyond these core Kubernetes capabilities. If you have any Kubernetes-related tasks or questions, feel free to ask!"}]}],"contextId":"f130122c-06e1-467c-9eb3-fe3704988b4d","history":[{"contextId":"f130122c-06e1-467c-9eb3-fe3704988b4d","kind":"message","messageId":"msg-cd691a32-c0d8-471d-b8eb-e4e3265621ce","parts":[{"kind":"text","text":"What skills do you have?"}],"role":"user","taskId":"b7ee2804-b15e-4dee-b6e9-ca2901383a10"},{"contextId":"f130122c-06e1-467c-9eb3-fe3704988b4d","kind":"message","messageId":"msg-cd691a32-c0d8-471d-b8eb-e4e3265621ce","parts":[{"kind":"text","text":"What skills do you have?"}],"role":"user","taskId":"b7ee2804-b15e-4dee-b6e9-ca2901383a10"},{"kind":"message","messageId":"e22926e1-50d2-4571-a039-a3dcf8dfb2b8","parts":[{"kind":"text","text":"I am a Kubernetes AI agent with deployment skills. I can help you deploy and manage Kubernetes applications by working with manifests, describing resources, getting resource details, and applying configurations to your Kubernetes cluster. However, currently, I do not have any additional specialized skills loaded beyond these core Kubernetes capabilities. If you have any Kubernetes-related tasks or questions, feel free to ask!"}],"role":"agent"}],"id":"b7ee2804-b15e-4dee-b6e9-ca2901383a10","kind":"task","metadata":{"kagent_app_name":"kagent__NS__k8s_assistant_with_skills","kagent_author":"k8s_assistant_with_skills","kagent_invocation_id":"e-ceaee83e-40a1-4088-b545-89e96f71608e","kagent_session_id":"f130122c-06e1-467c-9eb3-fe3704988b4d","kagent_usage_metadata":{"candidatesTokenCount":74,"promptTokenCount":1236,"totalTokenCount":1310},"kagent_user_id":"admin@kagent.dev"},"status":{"state":"completed","timestamp":"2025-11-21T22:13:16.484468+00:00"}}
  2. Invoke a skill, such as by asking it to deploy an app.

    kagent invoke --agent k8s-assistant-with-skills --task "Use your skill to deploy an app named 'httpbin' using the image 'docker.io/mccutchen/go-httpbin:v2.15.0' on port 8080"

    The agent:

    1. Reviews the instructions in the skill's SKILL.md file.
    2. Invokes the appropriate script with the correct parameters.
    3. Uses its tools to apply the generated resources (in this case, applying the Kubernetes manifest).

    Example output:

    {"artifacts":[{"artifactId":"9f7ad622-9e1a-4b6e-8c59-7b33846e6245","parts":[{"kind":"text","text":"The app named 'httpbin' has been deployed using the image 'docker.io/mccutchen/go-httpbin:v2.15.0' on port 8080. A deployment and a corresponding service have been created. Let me know if you need any other assistance with this deployment."}]}],"contextId":"6d25b097-ab63-4f9b-8c37-7481fe9a1098","history":[{"contextId":"6d25b097-ab63-4f9b-8c37-7481fe9a1098","kind":"message","messageId":"msg-7e6a6435-997b-4afa-9f63-2777ad44a154","parts":[{"kind":"text","text":"Use your skill to deploy an app named 'httpbin' using the image 'docker.io/mccutchen/go-httpbin:v2.15.0' on port 8080"}],"role":"user","taskId":"3020e09e-3e9b-4840-a805-feb9817d20a2"},{"contextId":"6d25b097-ab63-4f9b-8c37-7481fe9a1098","kind":"message","messageId":"msg-7e6a6435-997b-4afa-9f63-2777ad44a154","parts":[{"kind":"text","text":"Use your skill to deploy an app named 'httpbin' using the image 'docker.io/mccutchen/go-httpbin:v2.15.0' on port 8080"}],"role":"user","taskId":"3020e09e-3e9b-4840-a805-feb9817d20a2"},{"kind":"message","messageId":"114436b5-1b9e-4191-aabc-cc4f1db6f6a0","parts":[{"kind":"data","data":{"args":{"manifest":"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: httpbin\nspec:\n replicas: 1\n selector:\n matchLabels:\n app: httpbin\n template:\n metadata:\n labels:\n app: httpbin\n spec:\n containers:\n - name: httpbin\n image: docker.io/mccutchen/go-httpbin:v2.15.0\n ports:\n - containerPort: 8080\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: httpbin\nspec:\n selector:\n app: httpbin\n ports:\n - protocol: TCP\n port: 8080\n targetPort: 8080\n type: ClusterIP\n"},"id":"call_PdIQF51hPu1iBcOt3v1DkOzC","name":"k8s_apply_manifest"},"metadata":{"kagent_type":"function_call"}}],"role":"agent"},{"kind":"message","messageId":"1279457b-137b-4730-a1be-5dbe2985973b","parts":[{"kind":"data","data":{"id":"call_PdIQF51hPu1iBcOt3v1DkOzC","name":"k8s_apply_manifest","response":{"result":{"content":[{"text":"deployment.apps/httpbin created\nservice/httpbin created\n","type":"text"}],"isError":false}}},"metadata":{"kagent_type":"function_response"}}],"role":"agent"},{"kind":"message","messageId":"aefb1f07-3258-46bb-b078-515a9a6f08e5","parts":[{"kind":"text","text":"The app named 'httpbin' has been deployed using the image 'docker.io/mccutchen/go-httpbin:v2.15.0' on port 8080. A deployment and a corresponding service have been created. Let me know if you need any other assistance with this deployment."}],"role":"agent"}],"id":"3020e09e-3e9b-4840-a805-feb9817d20a2","kind":"task","metadata":{"kagent_app_name":"kagent__NS__k8s_assistant_with_skills","kagent_author":"k8s_assistant_with_skills","kagent_invocation_id":"e-b8f3e41b-a741-4338-b19b-f3a46ca33826","kagent_session_id":"6d25b097-ab63-4f9b-8c37-7481fe9a1098","kagent_usage_metadata":{"candidatesTokenCount":60,"promptTokenCount":1505,"totalTokenCount":1565},"kagent_user_id":"admin@kagent.dev"},"status":{"state":"completed","timestamp":"2025-11-21T22:14:33.755060+00:00"}}
  3. Check that the httpbin app was deployed successfully.

    kubectl get pods --namespace kagent | grep httpbin

    Example output:

    httpbin-b8b86ff46-rn7mf 1/1 Running 0 2m16s

Cleanup#

When you're done, you can clean up the resources that you created.

  1. Delete the agents that you created.

    kubectl delete agent k8s-troubleshooting-agent -n kagent
    kubectl delete agent k8s-assistant-with-skills -n kagent
  2. Clean up any applications that were deployed during testing, such as the httpbin app.

    kubectl delete deployment httpbin -n kagent
    kubectl delete service httpbin -n kagent
  3. Remove the skill directory and files that you created.

    cd ..
    rm -rf k8s-deploy-skill
  4. Optionally, remove the Docker image and registry that you used for local testing.

    docker rmi localhost:5000/k8s-deploy-skill:latest
    docker stop local-registry
    docker rm local-registry

Next steps#

  • Learn more about agents and their components
  • Explore tools available in kagent
  • Check out other examples to see different agent configurations
Kagent Lab: Discover kagent and kmcp
Free, on‑demand lab: build custom AI agents with kagent and integrate tools via kmcp on Kubernetes.