Welcome back, aspiring AI developer! In previous chapters, we’ve explored the foundational aspects of AWS Kiro, learned how to set up our environment, and started leveraging its out-of-the-box AI capabilities for coding. Kiro is already a powerful assistant, but what if your development workflow has unique needs that Kiro doesn’t address by default?
This chapter is where Kiro truly transforms from an intelligent assistant into a bespoke development partner. We’re going to unlock Kiro’s full potential by learning how to build custom Kiro agents. You’ll discover how to extend Kiro’s functionalities, automate specific tasks, and integrate your own logic directly into the AI-powered development environment. By the end of this chapter, you’ll be able to design, implement, and test your own Kiro agents, tailoring Kiro to your exact project requirements.
To get the most out of this chapter, ensure you have a working Kiro setup from Chapter 2 and a basic understanding of Kiro’s core interaction model from Chapter 3. Let’s dive in and make Kiro truly yours!
Core Concepts of Kiro Agent Development
Before we jump into coding, let’s understand the fundamental building blocks that make custom Kiro agents possible. Kiro’s architecture is designed for extensibility, allowing you to inject your own intelligence and logic at various stages of its operation.
The Kiro Agent Architecture: Intent, Knowledge, Execution, Oversight
Kiro agents operate within a sophisticated four-layer architecture that governs how they understand, plan, act, and review tasks. Understanding these layers is key to knowing where and how your custom agent fits in.
- Intent: This is the initial layer where Kiro (or your custom agent) interprets the user’s request. It’s about understanding what the user wants to achieve, identifying the core problem, and breaking it down into actionable steps.
- Knowledge: Once the intent is clear, the agent accesses relevant information. This includes project context, official documentation, internal best practices, and even external APIs. Your custom agent can contribute to or leverage this knowledge base.
- Execution: This is where the agent performs the actual work. It generates code, modifies files, runs tests, or interacts with external tools. Your custom logic primarily lives here, or influences actions taken at this stage.
- Oversight: After execution, the agent reviews its work. Did it meet the intent? Are there any errors? Does the code adhere to best practices? This layer provides a feedback loop, often allowing for self-correction or user interaction for approval.
Custom agents can plug into and influence any of these layers, but they often shine in enhancing the Knowledge and Execution phases, and by adding specific checks in the Oversight phase.
Here’s a simplified view of the Kiro Agent architecture:
Agent Manifest (agent.yaml)
Every Kiro agent needs a blueprint, and that’s precisely what the agent.yaml file provides. This YAML-formatted file is the heart of your agent, defining its metadata, capabilities, and how it interacts with the Kiro environment. It specifies:
- Agent Name and Description: How Kiro identifies and describes your agent.
- Intents: The specific types of tasks or problems your agent is designed to handle. Kiro uses this to decide when to invoke your agent.
- Hooks: The entry points for your custom code. These are functions that Kiro calls at specific stages of its workflow.
- Dependencies: Any external libraries or tools your agent requires.
Agent Hooks: Your Custom Logic Injection Points
Hooks are functions or scripts that your custom agent provides, which Kiro invokes at predefined points in its development workflow. Think of them as event listeners for Kiro’s operations. Common hook types include:
pre-execution: Runs before Kiro attempts to execute a task (e.g., before generating code). Useful for validating input, setting up context, or performing initial checks.post-execution: Runs after Kiro completes a task. Ideal for reviewing output, running tests, formatting code, or updating external systems.on-error: Runs if an error occurs during execution. Useful for custom error handling or logging.
By implementing these hooks, you can effectively “steer” Kiro’s behavior, ensuring it aligns with your project’s specific needs, quality standards, or integration requirements.
Model Context Protocol (MCP)
The Model Context Protocol (MCP) is Kiro’s standardized way for agents to communicate with each other and with Kiro’s core AI models. It allows agents to:
- Access Kiro’s internal system prompts and instructions.
- Inject additional context or constraints into the AI model’s thinking process.
- Receive structured information about the current project state.
While you might not directly interact with MCP at the lowest level when building simple agents, understanding its role helps grasp how your agent’s input influences Kiro’s powerful underlying models.
Kiro Agent SDK
To make agent development straightforward, Kiro provides Software Development Kits (SDKs), primarily for Python and TypeScript. These SDKs offer utility functions and classes to interact with the Kiro environment, access project files, log information, and return structured results from your hooks. We’ll be using the Python SDK for our examples due to its widespread adoption and ease of use.
Step-by-Step Implementation: Building a Simple Validation Agent
Let’s build a practical custom agent that enforces a simple coding best practice: ensuring all new Python files start with a docstring. This will demonstrate how to define an intent, implement a pre-execution hook, and interact with the Kiro environment.
Step 1: Initialize a New Kiro Agent Project
First, let’s create a new directory for our agent and initialize a Kiro agent project.
Create a Project Directory: Open your terminal or command prompt and navigate to a suitable location.
mkdir kiro-docstring-agent cd kiro-docstring-agentInitialize the Agent: Now, use the Kiro CLI to initialize the agent. This command creates the basic structure for your agent.
kiro agent initYou’ll be prompted for some information:
- Agent Name:
docstring-validator - Description:
Ensures Python files have docstrings. - Language:
Python(orTypeScriptif you prefer, but we’ll use Python for this guide)
After initialization, your directory will look something like this:
kiro-docstring-agent/ ├── agent.yaml └── src/ └── main.py (or main.ts)- Agent Name:
Step 2: Define the Agent’s Intent in agent.yaml
Open agent.yaml in your favorite code editor. You’ll see some boilerplate. We need to define an intent that tells Kiro when to consider activating our agent. For our docstring validator, we want it to run whenever Kiro is about to create or modify a Python file.
Here’s how to modify your agent.yaml. We’ll add a section for intents and specify a trigger based on file changes.
# kiro-docstring-agent/agent.yaml
agent:
name: docstring-validator
description: Ensures Python files have docstrings.
language: python # Or typescript if you chose that
version: "0.1.0" # Current version of your agent
# This is where we define what our agent cares about
intents:
- name: validate-python-docstring
description: "Validate if a Python file has a docstring."
# We want this agent to be considered whenever Kiro generates or modifies code
triggers:
- type: code_generation
- type: file_modification
# Specify the hooks that will run when this intent is matched
hooks:
pre-execution:
- src/main.py:validate_docstring # Path to your script and function name
Explanation:
intents: This top-level key holds a list of intents your agent can handle.name: A unique identifier for this specific intent.description: A human-readable explanation of what this intent does.triggers: This is crucial. It tells Kiro when to consider activating this intent. We’ve specifiedcode_generationandfile_modification, meaning Kiro will evaluate this intent whenever it’s about to create or change code/files.hooks: Inside the intent, we link to our actual code.pre-executionmeans ourvalidate_docstringfunction (located insrc/main.py) will run before Kiro proceeds with its primary task.
Step 3: Implement the pre-execution Hook
Now, let’s write the Python code for our validate_docstring hook. Open src/main.py.
# kiro-docstring-agent/src/main.py
import os
import logging
from typing import Dict, Any
# Kiro provides a context object with useful information
# You might need to install 'kiro-sdk' if not already installed: pip install kiro-sdk
# For current Kiro versions (as of 2026-01-24), the context object is typically passed
# directly to the hook function, and the SDK provides helpers.
# Let's assume a simplified context for this example.
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
def validate_docstring(context: Dict[str, Any]) -> Dict[str, Any]:
"""
A pre-execution hook to validate if a Python file has a docstring.
If Kiro is about to create/modify a Python file, this hook checks its content.
"""
logger.info("Docstring validator agent: Pre-execution hook activated.")
# Kiro's context object contains information about the current operation.
# We're interested in the files Kiro is proposing to change or create.
# The exact structure of 'files_to_modify' or 'proposed_changes'
# can vary slightly with Kiro versions, but it generally contains
# file paths and their proposed content.
# Let's simulate retrieving proposed changes.
# In a real scenario, context.get('proposed_changes', {}) or similar
# would provide actual file changes. For this example, we'll assume
# 'file_path' and 'new_content' are directly available for the target file.
# For simplicity, let's assume the context contains a 'target_file' key
# with the path and 'proposed_content' for that file.
# In a real Kiro environment, you'd iterate through 'proposed_changes'.
target_file_path = context.get('target_file_path')
proposed_content = context.get('proposed_content')
if not target_file_path or not proposed_content:
logger.warning("Docstring validator: No target file path or content found in context.")
return {"status": "skipped", "message": "No relevant file changes to validate."}
# Only validate Python files
if not target_file_path.endswith('.py'):
logger.info(f"Docstring validator: Skipping non-Python file: {target_file_path}")
return {"status": "skipped", "message": "Not a Python file."}
logger.info(f"Docstring validator: Checking file: {target_file_path}")
# Check for a docstring (very basic check: presence of triple quotes at the start)
# This is a simplified check. A more robust solution might use AST parsing.
content_lines = proposed_content.strip().splitlines()
has_docstring = False
# Look for a docstring within the first few non-empty lines
for i, line in enumerate(content_lines):
stripped_line = line.strip()
if not stripped_line: # Skip empty lines
continue
if stripped_line.startswith(('"""', "'''")):
has_docstring = True
break
# If we encounter actual code before a docstring, assume no docstring at the top
if not stripped_line.startswith(('#', 'from', 'import', 'def', 'class')):
break # Found code before docstring
if i > 10: # Don't search too far down
break
if not has_docstring:
error_message = f"Error: Python file '{target_file_path}' is missing a top-level docstring."
logger.error(error_message)
# If the hook returns 'status': 'fail', Kiro will typically halt the operation
# and report the error to the user.
return {
"status": "fail",
"message": error_message,
"suggestion": "Please add a docstring to the beginning of your Python file, e.g., `\"\"\"A brief description.\"\"\"`."
}
else:
logger.info(f"Docstring validator: Docstring found in '{target_file_path}'.")
return {"status": "success", "message": "Docstring validation passed."}
Explanation of the Python Code:
validate_docstring(context: Dict[str, Any]): This is our hook function. Kiro automatically passes acontextdictionary containing details about the current operation.logger: We use standard Python logging for better visibility into our agent’s actions when it runs.target_file_pathandproposed_content: In a real Kiro hook, thecontextobject would contain structured data about the files Kiro is proposing to change. For this simplified example, we’re assuming these keys are directly available. In practice, you’d likely accesscontext['proposed_changes']which is a dictionary mapping file paths to their new content..endswith('.py'): We ensure our check only applies to Python files.content_lines = proposed_content.strip().splitlines(): We get the proposed content of the file and split it into lines.- Docstring Check: The core logic is a basic check for
"""or'''at the beginning of the file’s content. A more advanced agent might use Python’sastmodule to parse the code and verify a proper docstring structure. - Return Value:
- If a docstring is not found, we return a dictionary with
"status": "fail", anerror_message, and asuggestion. Kiro interprets"fail"as a signal to halt the current operation and inform the user. - If a docstring is found (or the file is not Python), we return
"status": "success"or"skipped". This allows Kiro to proceed.
- If a docstring is not found, we return a dictionary with
Step 4: Test Your Custom Agent
Kiro provides a way to test your agents locally without fully integrating them into a project.
Navigate to Agent Directory: Ensure you are in the
kiro-docstring-agentdirectory.Run a Test: We’ll simulate Kiro proposing to create a Python file with and without a docstring.
Test Case 1: Python file with a docstring (should pass)
kiro agent test validate-python-docstring --context '{"target_file_path": "my_module.py", "proposed_content": "\"\"\"This is a test module.\n\"\"\"\n\ndef hello():\n print(\"Hello\")"}'You should see output indicating “Docstring validation passed.” and the agent returning
{"status": "success", ...}.Test Case 2: Python file without a docstring (should fail)
kiro agent test validate-python-docstring --context '{"target_file_path": "no_docstring.py", "proposed_content": "def hello():\n print(\"Hello, no docstring!\")"}'This time, you should see an error message from your agent, indicating “Python file ’no_docstring.py’ is missing a top-level docstring.” and the agent returning
{"status": "fail", ...}.Test Case 3: A non-Python file (should be skipped)
kiro agent test validate-python-docstring --context '{"target_file_path": "README.md", "proposed_content": "# My Readme"}'This should show “Docstring validator: Skipping non-Python file: README.md” and return
{"status": "skipped", ...}.
What to Observe/Learn:
- You’ve successfully defined an intent and linked it to a Python hook.
- You’ve seen how the
contextobject passes information to your agent. - You’ve observed how returning
"status": "fail"can halt Kiro’s operation and provide feedback. - You’ve learned to use
kiro agent testto validate your agent’s logic.
Mini-Challenge: Extend the Docstring Agent
You’ve built a basic docstring validator. Now, let’s make it a bit smarter!
Challenge: Modify your docstring-validator agent so that, in addition to checking for a docstring, it also checks if any Python function (def) within the proposed content is missing its own docstring. If a function is found without a docstring, the agent should still fail, but provide a more specific error message, including the function’s name.
Hint:
- You’ll need to parse the
proposed_contentmore deeply. Regular expressions can be useful for findingdef function_name(...):patterns. - After finding a
defline, you’ll need to look at the lines immediately following it to see if a docstring ("""..."""or'''...''') is present before any actual code. - Remember to return
"status": "fail"with a clear message and suggestion if a missing function docstring is detected.
What to observe/learn: This challenge will deepen your understanding of parsing code within an agent, handling more complex validation logic, and providing granular feedback to the user.
Common Pitfalls & Troubleshooting
Building custom agents can be tricky at first. Here are some common issues and how to troubleshoot them:
agent.yamlSyntax Errors:- Pitfall: YAML is sensitive to indentation and syntax. A misplaced space or incorrect key can prevent your agent from being recognized.
- Troubleshooting:
- Use a YAML linter (many IDEs have them built-in).
- Double-check indentation. YAML uses spaces, not tabs.
- Ensure all keys are correctly spelled (e.g.,
intentsvs.intent). - Kiro CLI often provides helpful error messages if
agent.yamlis malformed duringkiro agent testorkiro agent deploy.
Agent Not Being Invoked:
- Pitfall: Your agent is correctly defined, but Kiro never calls your hook function.
- Troubleshooting:
- Check
triggersinagent.yaml: Does thetypeof trigger match the scenario you’re expecting (e.g.,code_generation,file_modification)? - Verify
hookspath and function name: Issrc/main.py:validate_docstringcorrectly pointing to your file and function? - Examine Kiro’s logs: When Kiro runs, it often logs which agents it’s considering and why it’s activating/deactivating them. Look for messages related to your agent’s name.
- Ensure the intent is broad enough: If your intent is too specific, Kiro might not match it.
- Check
Permissions Issues (if interacting with AWS resources):
- Pitfall: Your agent tries to call an AWS API (e.g., S3, Lambda) but gets an “Access Denied” error.
- Troubleshooting:
- AWS CLI Configuration: Verify your local AWS CLI is configured with credentials that have the necessary permissions. Use
aws sts get-caller-identityto check the active principal. - Kiro Agent Role: When deploying agents to a shared Kiro environment, they often run with an IAM role. Ensure this role has the required permissions for the AWS services your agent needs to access. This is a common issue for agents that interact with external AWS services.
- AWS CLI Configuration: Verify your local AWS CLI is configured with credentials that have the necessary permissions. Use
Debugging Kiro Agents:
- Pitfall: Your agent runs but produces unexpected results, or silently fails.
- Troubleshooting:
- Extensive Logging: Use
logging.info(),logging.warning(), andlogging.error()liberally within your agent code. These logs will be visible when you runkiro agent testor if the agent runs within Kiro’s environment. - Print Statements (for quick checks): While logging is preferred,
print()statements can also provide immediate feedback during development withkiro agent test. - Inspect the
contextobject: Log the entirecontextdictionary at the beginning of your hook to understand exactly what information Kiro is providing to your agent.logger.debug(f"Context: {context}") - Step-through Debugging: For more complex agents, you might need to attach a debugger (like
pdbfor Python) to your hook function, though this can be more involved with how Kiro executes hooks.
- Extensive Logging: Use
Summary
Congratulations! You’ve taken a significant step in mastering AWS Kiro by learning how to build and customize your own AI agents.
Here’s a quick recap of what we covered:
- Kiro Agent Architecture: We explored the Intent, Knowledge, Execution, and Oversight layers that govern Kiro’s operations, understanding where custom logic fits in.
- Agent Manifest (
agent.yaml): You learned to define your agent’s identity, intents, triggers, and hooks in this crucial configuration file. - Agent Hooks: We delved into
pre-executionhooks, which allow you to inject custom logic before Kiro performs its main task, enabling powerful validation and context manipulation. - Step-by-Step Implementation: You successfully initialized a Kiro agent project, defined an intent, implemented a Python
pre-executionhook, and tested its behavior with the Kiro CLI. - Troubleshooting: We discussed common pitfalls like
agent.yamlerrors, invocation issues, permissions, and effective debugging strategies.
Building custom agents empowers you to tailor Kiro to your team’s specific coding standards, automate repetitive checks, and integrate seamlessly with your existing toolchain. This capability makes Kiro an incredibly flexible and powerful partner in your development journey.
What’s Next?
In the next chapter, we’ll explore how to deploy your custom agents to a Kiro environment for broader use, delve into more advanced agent functionalities, and discuss strategies for integrating Kiro agents into your CI/CD pipelines for truly automated quality and consistency checks.
References
- Kiro GitHub Repository (kirodotdev/Kiro)
- AWS Blog: Transform DevOps practice with Kiro AI-powered agents
- AWS Blog: AWS Weekly Roundup: Kiro, AWS Lambda remote debugging… (Mentions Kiro features)
- AWS Builder: Building “The Referee” with Kiro (Showcases agent-like behavior)
- GitHub: Kiro Best Practices Boilerplate (Examples of agent hooks and steering documents)
This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.