diff --git a/registry/harleylrn/.images/avatar.png b/registry/harleylrn/.images/avatar.png
new file mode 100644
index 000000000..08e6f54e1
Binary files /dev/null and b/registry/harleylrn/.images/avatar.png differ
diff --git a/registry/harleylrn/.images/kiro-cli.png b/registry/harleylrn/.images/kiro-cli.png
new file mode 100644
index 000000000..d325299b1
Binary files /dev/null and b/registry/harleylrn/.images/kiro-cli.png differ
diff --git a/registry/harleylrn/README.md b/registry/harleylrn/README.md
new file mode 100644
index 000000000..d53bb12ea
--- /dev/null
+++ b/registry/harleylrn/README.md
@@ -0,0 +1,22 @@
+---
+display_name: "Michael Orlov"
+bio: "Platform Engineer specializing in cloud infrastructure, DevOps automation, and developer experience tools"
+avatar: "./.images/avatar.png"
+github: "harleylrn"
+support_email: "michael.orlov@gmail.com"
+status: "community"
+---
+
+# Michael Orlov
+
+Platform Engineer specializing in cloud infrastructure, DevOps automation, and developer experience tools. Contributing modules and templates to enhance developer productivity in Coder workspaces.
+
+## Modules
+
+### kiro-cli
+
+AI-powered coding assistant integration for Coder workspaces with MCP (Model Context Protocol) support and task reporting capabilities.
+
+## About
+
+I focus on creating tools and integrations that improve developer experience and productivity. My contributions to the Coder Registry aim to provide seamless integration of modern development tools and AI assistants into cloud development environments.
diff --git a/registry/harleylrn/modules/kiro-cli/README.md b/registry/harleylrn/modules/kiro-cli/README.md
new file mode 100644
index 000000000..a95bc8d76
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/README.md
@@ -0,0 +1,456 @@
+---
+display_name: Kiro CLI
+description: Run Kiro CLI in your workspace to access AI coding assistant with MCP integration and task reporting.
+icon: ../../../../.icons/kiro.svg
+verified: true
+tags: [agent, ai, kiro, kiro-cli, tasks]
+---
+
+# Kiro CLI
+
+Run [Kiro CLI](https://kiro.dev/) in your workspace to access AI coding assistant. This module provides a complete integration with Coder workspaces, including automatic installation, MCP (Model Context Protocol) integration for task reporting, and support for custom pre/post install scripts.
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+
+ # Required: Authentication tarball (see below for generation)
+ auth_tarball = <<-EOF
+base64encoded-tarball
+EOF
+}
+```
+
+
+
+## Prerequisites
+
+- **zstd** - Required for compressing the authentication tarball
+ - **Ubuntu/Debian**: `sudo apt-get install zstd`
+ - **RHEL/CentOS/Fedora**: `sudo yum install zstd` or `sudo dnf install zstd`
+- **auth_tarball** - Required for installation and authentication
+
+### Authentication Tarball
+
+You must generate an authenticated Kiro CLI tarball on another machine where you have successfully logged in:
+
+```bash
+# 1. Install Kiro CLI and login on your local machine
+kiro-cli login
+
+# 2. Generate the authentication tarball
+cd ~/.local/share/kiro-cli
+tar -c . | zstd | base64 -w 0
+```
+
+Copy the output and use it as the `auth_tarball` variable.
+
+## Detailed Authentication Setup
+
+**Step 1: Install Kiro CLI locally**
+
+- Download from [Kiro CLI](https://kiro.dev/)
+- Follow the installation instructions for your platform
+
+**Step 2: Authenticate**
+
+```bash
+kiro-cli login
+```
+
+Complete the authentication process in your browser.
+
+**Step 3: Generate tarball**
+
+```bash
+cd ~/.local/share/kiro-cli
+tar -c . | zstd | base64 -w 0 > /tmp/kiro-cli-auth.txt
+```
+
+**Step 4: Use in Terraform**
+
+```tf
+variable "kiro_cli_auth_tarball" {
+ type = string
+ sensitive = true
+ default = "PASTE_YOUR_TARBALL_HERE"
+}
+```
+
+> [!IMPORTANT]
+>
+> - Regenerate the tarball if you logout or re-authenticate
+> - Each user needs their own authentication tarball
+> - Keep the tarball secure as it contains authentication credentials
+
+### Coder Tasks Integration
+
+To enable integration with [Coder Tasks](https://coder.com/docs/ai-coder/tasks), you need to define the `coder_task` data source, create the `coder_ai_task` resource, and configure the module with the task prompt.
+
+```tf
+data "coder_task" "me" {}
+
+module "kiro-cli" {
+ count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+ ai_prompt = data.coder_task.me.prompt
+ trust_all_tools = true
+
+ # Task reporting configuration
+ report_tasks = true
+
+ # Enable CLI app alongside web app
+ cli_app = true
+ web_app_display_name = "Kiro CLI"
+ cli_app_display_name = "Kiro CLI"
+}
+
+resource "coder_ai_task" "task" {
+ count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0
+ app_id = module.kiro-cli[count.index].task_app_id
+}
+```
+
+> [!IMPORTANT]
+>
+> - The `data "coder_task" "me" {}` data source provides the task prompt and enabled state
+> - The module count is controlled by `data.coder_task.me.enabled` to only create when a task is active
+> - The `coder_ai_task` resource links the module's task reporting to Coder's task system
+> - The `ai_prompt` is passed from `data.coder_task.me.prompt`
+> - Without this configuration, `coder_ai_task` resources will not function properly
+>
+> **_Security Notice_**
+> In order to allow the tasks flow non-interactively all the tools are trusted
+> This flag bypasses standard permission checks and allows Kiro CLI broader access to your system than normally permitted.
+> While this enables more functionality, it also means Kiro CLI can potentially execute commands with the same privileges as the user running it.
+> Use this module only in trusted environments and be aware of the security implications.
+
+### Default System Prompt
+
+The module includes a simple system prompt that instructs Kiro CLI:
+
+```
+You are a helpful Coding assistant. Aim to autonomously investigate
+and solve issues the user gives you and test your work, whenever possible.
+Avoid shortcuts like mocking tests. When you get stuck, you can ask the user
+but opt for autonomy.
+```
+
+You can customize this behavior by providing your own system prompt via the `system_prompt` variable.
+
+### Default Coder MCP Instructions
+
+The module includes specific instructions for the Coder MCP server integration that are separate from the system prompt:
+
+```
+YOU MUST REPORT ALL TASKS TO CODER.
+When reporting tasks you MUST follow these EXACT instructions:
+- IMMEDIATELY report status after receiving ANY user message
+- Be granular If you are investigating with multiple steps report each step to coder.
+
+Task state MUST be one of the following:
+- Use "state": "working" when actively processing WITHOUT needing additional user input
+- Use "state": "complete" only when finished with a task
+- Use "state": "failure" when you need ANY user input lack sufficient details or encounter blockers.
+
+Task summaries MUST:
+- Include specifics about what you're doing
+- Include clear and actionable steps for the user
+- Be less than 160 characters in length
+```
+
+You can customize these instructions by providing your own via the `coder_mcp_instructions` variable.
+
+## Default Agent Configuration
+
+The module includes a default agent configuration template that provides a comprehensive setup for Kiro CLI integration:
+
+```json
+{
+ "name": "agent",
+ "description": "This is an default agent config",
+ "prompt": "${system_prompt}",
+ "mcpServers": {},
+ "tools": ["read", "write", "shell", "aws", "@coder", "knowledge"],
+ "toolAliases": {},
+ "allowedTools": ["read", "@coder"],
+ "resources": [
+ "file://KiroQ.md",
+ "file://README.md",
+ "file://.kiro/steering/**/*.md"
+ ],
+ "hooks": {},
+ "toolsSettings": {},
+ "useLegacyMcpJson": true
+}
+```
+
+### Configuration Details:
+
+- **Tools Available:** File operations (`read`, `write`), shell execution (`shell`), AWS CLI (`aws`), Coder MCP integration (`@coder`), and knowledge base access (`knowledge`)
+- **@coder Tool:** Enables Coder MCP integration for task reporting (`coder_report_task` and related tools)
+- **Allowed Tools:** By default, only `read` and `@coder` are allowed (can be customized for security)
+- **Resources:** Access to documentation and rule files in the workspace
+- **MCP Servers:** Empty by default, can be configured via `agent_config` variable
+- **System Prompt:** Dynamically populated from the `system_prompt` variable
+- **Legacy MCP:** Uses legacy MCP JSON format for compatibility
+
+You can override this configuration by providing your own JSON via the `agent_config` variable.
+
+### Agent Name Configuration
+
+The module automatically extracts the agent name from the `"name"` field in the `agent_config` JSON and uses it for:
+
+- **Configuration File:** Saves the agent config as `~/.kiro/agents/{agent_name}.json`
+- **Default Agent:** Sets the agent as the default using `q settings chat.defaultAgent {agent_name}`
+- **MCP Integration:** Associates the Coder MCP server with the specified agent name
+
+If no custom `agent_config` is provided, the default agent name "agent" is used.
+
+## Usage Examples
+
+### Basic Usage
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+}
+```
+
+This example will:
+
+1. Download and install Kiro CLI latest version
+2. Extract authentication tarball to ~/.local/share/kiro-cli
+3. Configure Coder MCP integration for task reporting
+4. Create default agent configuration file
+5. Start Kiro CLI in /home/coder directory
+6. Provide web interface through AgentAPI
+
+> [!IMPORTANT]
+> By default `write` tool is not allowed, which will pause the task execution
+> and will wait for the prompt to approve its usage.
+> To avoid this, and allow the normal task flow, user has two options:
+>
+> - Change the parameter `trust_all_tools` value to `true` (default to `false`)
+> OR
+> - Provide your own agent configuration with the tools of your choice allowed
+
+### With Custom AI Prompt
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+ ai_prompt = "Help me set up a Python FastAPI project with proper testing structure"
+ trust_all_tools = true
+}
+```
+
+> [!IMPORTANT]
+> **_Security Notice_**
+> In order to allow the tasks flow non-interactively all the tools are trusted
+> This flag bypasses standard permission checks and allows Kiro CLI broader access to your system than normally permitted.
+> While this enables more functionality, it also means Kiro CLI can potentially execute commands with the same privileges as the user running it.
+> Use this module only in trusted environments and be aware of the security implications.
+
+### With Custom Pre/Post Install Scripts
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+
+ pre_install_script = <<-EOT
+ #!/bin/bash
+ echo "Setting up custom environment..."
+ # Install additional dependencies
+ sudo apt-get update && sudo apt-get install -y zstd
+ EOT
+
+ post_install_script = <<-EOT
+ #!/bin/bash
+ echo "Configuring Kiro CLI settings..."
+ # Custom configuration commands
+ kiro-cli settings chat.model claude-3-sonnet
+ EOT
+}
+```
+
+### Specific Version Installation
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+ kiro_cli_version = "1.14.0" # Specific version
+ install_kiro_cli = true
+}
+```
+
+### Custom Agent Configuration
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+
+ agent_config = <<-EOT
+ {
+ "name": "custom-agent",
+ "description": "Custom Kiro CLI agent for my workspace",
+ "prompt": "You are a specialized DevOps assistant...",
+ "tools": ["read", "write", "shell", "aws"]
+ }
+ EOT
+}
+```
+
+### With Custom AgentAPI Configuration
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+
+ # AgentAPI configuration for environments without wildcard access url. https://coder.com/docs/admin/setup#wildcard-access-url
+ agentapi_chat_based_path = true
+ agentapi_version = "v0.10.0"
+}
+```
+
+### Air-Gapped Installation
+
+For environments without direct internet access, you can host Kiro CLI installation files internally and configure the module to use your internal repository:
+
+```tf
+module "kiro-cli" {
+ source = "registry.coder.com/coder/kiro-cli/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ workdir = "/home/coder"
+ auth_tarball = var.kiro_cli_auth_tarball
+
+ # Point to internal artifact repository
+ kiro_install_url = "https://artifacts.internal.corp/kiro-cli-releases"
+
+ # Use specific version available in your repository
+ kiro_cli_version = "latest"
+}
+```
+
+**Prerequisites for Air-Gapped Setup:**
+
+1. Download Kiro CLI installation files from the official source and host them internally
+2. Maintain the same directory structure: `{base_url}/{version}/kirocli-{arch}-linux.zip`
+3. Ensure both architectures are available:
+ - `kirocli-x86_64-linux.zip` for Intel/AMD systems
+ - `kirocli-aarch64-linux.zip` for ARM systems
+4. Configure network access from Coder workspaces to your internal repository
+
+## Troubleshooting
+
+### Common Issues
+
+**Authentication issues:**
+
+- Regenerate the auth tarball on your local machine
+- Ensure the tarball is properly base64 encoded
+- Check that the original authentication is still valid
+
+**MCP integration not working:**
+
+- Verify that AgentAPI is installed (`install_agentapi = true`)
+- Check that the Coder agent is properly configured
+- Review the system prompt configuration
+
+
+
+## Requirements
+
+| Name | Version |
+| ------------------------------------------------------------------------ | ------- |
+| [terraform](#requirement_terraform) | >= 1.0 |
+| [coder](#requirement_coder) | >= 2.12 |
+
+## Providers
+
+| Name | Version |
+| ------------------------------------------------------ | ------- |
+| [coder](#provider_coder) | 2.13.1 |
+
+## Modules
+
+| Name | Source | Version |
+| ----------------------------------------------------------- | --------------------------------------- | ------- |
+| [agentapi](#module_agentapi) | registry.coder.com/coder/agentapi/coder | 2.0.0 |
+
+## Resources
+
+| Name | Type |
+| ------------------------------------------------------------------------------------------------------------------------ | ----------- |
+| [coder_env.auth_tarball](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/env) | resource |
+| [coder_env.status_slug](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/env) | resource |
+| [coder_workspace.me](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace) | data source |
+| [coder_workspace_owner.me](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------: |
+| [agent_config](#input_agent_config) | Optional Agent configuration JSON for Kiro CLI. | `string` | `null` | no |
+| [agent_id](#input_agent_id) | The ID of a Coder agent. | `string` | n/a | yes |
+| [agentapi_chat_based_path](#input_agentapi_chat_based_path) | Whether to use chat-based path for AgentAPI.Required if CODER_WILDCARD_ACCESS_URL is not defined in coder deployment | `bool` | `false` | no |
+| [agentapi_version](#input_agentapi_version) | The version of AgentAPI to install. | `string` | `"v0.10.0"` | no |
+| [ai_prompt](#input_ai_prompt) | The initial task prompt to send to Kiro CLI. | `string` | `""` | no |
+| [auth_tarball](#input_auth_tarball) | Base64 encoded, zstd compressed tarball of a pre-authenticated ~/.local/share/kiro-cli directory. | `string` | `""` | no |
+| [cli_app](#input_cli_app) | Whether to create a CLI app for Kiro CLI | `bool` | `false` | no |
+| [cli_app_display_name](#input_cli_app_display_name) | Display name for the CLI app | `string` | `"Kiro CLI"` | no |
+| [coder_mcp_instructions](#input_coder_mcp_instructions) | Instructions for the Coder MCP server integration. This defines how the agent should report tasks to Coder. | `string` | `"YOU MUST REPORT ALL TASKS TO CODER.\nWhen reporting tasks you MUST follow these EXACT instructions:\n- IMMEDIATELY report status after receiving ANY user message\n- Be granular If you are investigating with multiple steps report each step to coder.\n\nTask state MUST be one of the following:\n- Use \"state\": \"working\" when actively processing WITHOUT needing additional user input\n- Use \"state\": \"complete\" only when finished with a task\n- Use \"state\": \"failure\" when you need ANY user input lack sufficient details or encounter blockers.\n\nTask summaries MUST:\n- Include specifics about what you're doing\n- Include clear and actionable steps for the user\n- Be less than 160 characters in length\n"` | no |
+| [group](#input_group) | The name of a group that this app belongs to. | `string` | `null` | no |
+| [icon](#input_icon) | The icon to use for the app. | `string` | `"/icon/kiro.svg"` | no |
+| [install_agentapi](#input_install_agentapi) | Whether to install AgentAPI. | `bool` | `true` | no |
+| [install_kiro_cli](#input_install_kiro_cli) | Whether to install Kiro CLI. | `bool` | `true` | no |
+| [kiro_cli_version](#input_kiro_cli_version) | The version of Kiro CLI to install. | `string` | `"latest"` | no |
+| [kiro_install_url](#input_kiro_install_url) | Base URL for Kiro CLI installation downloads. | `string` | `"https://desktop-release.q.us-east-1.amazonaws.com"` | no |
+| [order](#input_order) | The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order). | `number` | `null` | no |
+| [post_install_script](#input_post_install_script) | Optional script to run after installing Kiro CLI. | `string` | `null` | no |
+| [pre_install_script](#input_pre_install_script) | Optional script to run before installing Kiro CLI. | `string` | `null` | no |
+| [report_tasks](#input_report_tasks) | Whether to enable task reporting to Coder UI via AgentAPI | `bool` | `true` | no |
+| [system_prompt](#input_system_prompt) | The system prompt to use for Kiro CLI. This should instruct the agent how to do task reporting. | `string` | `"You are a helpful Coding assistant. Aim to autonomously investigate\nand solve issues the user gives you and test your work, whenever possible.\nAvoid shortcuts like mocking tests. When you get stuck, you can ask the user\nbut opt for autonomy.\n"` | no |
+| [trust_all_tools](#input_trust_all_tools) | Whether to trust all tools in Kiro CLI. | `bool` | `false` | no |
+| [web_app_display_name](#input_web_app_display_name) | Display name for the web app | `string` | `"Kiro CLI"` | no |
+| [workdir](#input_workdir) | The folder to run Kiro CLI in. | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+| -------------------------------------------------------------------- | ----------- |
+| [task_app_id](#output_task_app_id) | n/a |
+
+
diff --git a/registry/harleylrn/modules/kiro-cli/kiro-cli.tftest.hcl b/registry/harleylrn/modules/kiro-cli/kiro-cli.tftest.hcl
new file mode 100644
index 000000000..0f183a69e
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/kiro-cli.tftest.hcl
@@ -0,0 +1,372 @@
+run "required_variables" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ }
+}
+
+run "minimal_config" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ auth_tarball = "dGVzdA==" # base64 "test"
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].name == "CODER_MCP_APP_STATUS_SLUG"
+ error_message = "Status slug environment variable not configured correctly"
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].value == "kiro-cli"
+ error_message = "Status slug value should be 'kiro-cli'"
+ }
+}
+
+# Test Case 1: Basic Usage – No Autonomous Use of Q
+# Using vanilla Kubernetes Deployment Template configuration
+run "test_case_1_basic_usage" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ auth_tarball = "dGVzdEF1dGhUYXJiYWxs" # base64 "testAuthTarball"
+ }
+
+ # Q is installed and authenticated
+ assert {
+ condition = resource.coder_env.status_slug[0].name == "CODER_MCP_APP_STATUS_SLUG"
+ error_message = "Status slug environment variable should be configured for basic usage"
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].value == "kiro-cli"
+ error_message = "Status slug value should be 'kiro-cli' for basic usage"
+ }
+
+ # AgentAPI is installed and configured (default behavior)
+ assert {
+ condition = length(resource.coder_env.auth_tarball) == 1
+ error_message = "Auth tarball environment variable should be created for authentication"
+ }
+
+ # Foundational configuration applied
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Agent config should be generated with foundational configuration"
+ }
+
+ # No additional parameters required (using defaults)
+ assert {
+ condition = local.agent_name == "agent"
+ error_message = "Default agent name should be 'agent' when no custom config provided"
+ }
+}
+
+# Test Case 2: Autonomous Usage – Autonomous Use of Q
+# AI prompt passed through from external source (Tasks interface or Issue Tracker CI)
+run "test_case_2_autonomous_usage" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ auth_tarball = "dGVzdEF1dGhUYXJiYWxs" # base64 "testAuthTarball"
+ ai_prompt = "Help me set up a Python FastAPI project with proper testing structure"
+ }
+
+ # Q is installed and authenticated
+ assert {
+ condition = resource.coder_env.status_slug[0].name == "CODER_MCP_APP_STATUS_SLUG"
+ error_message = "Status slug environment variable should be configured for autonomous usage"
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].value == "kiro-cli"
+ error_message = "Status slug value should be 'kiro-cli' for autonomous usage"
+ }
+
+ # AgentAPI is installed and configured
+ assert {
+ condition = length(resource.coder_env.auth_tarball) == 1
+ error_message = "Auth tarball environment variable should be created for autonomous usage"
+ }
+
+ # Foundational configuration for all components applied
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Agent config should be generated for autonomous usage"
+ }
+
+ # AI prompt is configured
+ assert {
+ condition = local.full_prompt == "Help me set up a Python FastAPI project with proper testing structure"
+ error_message = "AI prompt should be configured correctly for autonomous usage"
+ }
+
+ # Default agent name when no custom config
+ assert {
+ condition = local.agent_name == "agent"
+ error_message = "Default agent name should be 'agent' for autonomous usage"
+ }
+}
+
+# Test Case 3: Extended Configuration – Parameter Validation and File Rendering
+# Validates extended configuration options and parameter application
+run "test_case_3_extended_configuration" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ auth_tarball = "dGVzdEF1dGhUYXJiYWxs" # base64 "testAuthTarball"
+ kiro_cli_version = "1.14.1"
+ kiro_install_url = "https://desktop-release.q.us-east-1.amazonaws.com"
+ install_kiro_cli = true
+ install_agentapi = true
+ agentapi_version = "v0.6.0"
+ trust_all_tools = true
+ ai_prompt = "Help me create a production-grade TypeScript monorepo with testing and deployment"
+ system_prompt = "You are a helpful software assistant working in a secure enterprise environment"
+ pre_install_script = "echo 'Pre-install setup'"
+ post_install_script = "echo 'Post-install cleanup'"
+ agent_config = jsonencode({
+ name = "production-agent"
+ description = "Production Kiro CLI agent for enterprise environment"
+ prompt = "You are a helpful software assistant working in a secure enterprise environment"
+ mcpServers = {}
+ tools = ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"]
+ toolAliases = {}
+ allowedTools = ["fs_read"]
+ resources = ["file://KiroQ.md", "file://README.md", "file://.kiro/steering/**/*.md"]
+ hooks = {}
+ toolsSettings = {}
+ useLegacyMcpJson = true
+ })
+ }
+
+ # All installation parameters are applied correctly
+ assert {
+ condition = resource.coder_env.status_slug[0].value == "kiro-cli"
+ error_message = "Status slug should be configured correctly with extended parameters"
+ }
+
+ assert {
+ condition = resource.coder_env.auth_tarball[0].value == "dGVzdEF1dGhUYXJiYWxs"
+ error_message = "Auth tarball should be configured correctly with extended parameters"
+ }
+
+ # Custom agent configuration is loaded and referenced correctly
+ assert {
+ condition = local.agent_name == "production-agent"
+ error_message = "Agent name should be extracted from custom agent config"
+ }
+
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Custom agent config should be processed correctly"
+ }
+
+ # AI prompt and system prompt are configured
+ assert {
+ condition = local.full_prompt == "Help me create a production-grade TypeScript monorepo with testing and deployment"
+ error_message = "AI prompt should be configured correctly in extended configuration"
+ }
+
+ # Pre-install and post-install scripts are provided
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Agent config should be generated correctly for extended configuration"
+ }
+}
+
+run "full_config" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ install_kiro_cli = true
+ install_agentapi = true
+ agentapi_version = "v0.5.0"
+ kiro_cli_version = "latest"
+ trust_all_tools = true
+ ai_prompt = "Build a web application"
+ auth_tarball = "dGVzdA=="
+ order = 1
+ group = "AI Tools"
+ icon = "/icon/custom-kiro-cli.svg"
+ pre_install_script = "echo 'pre-install'"
+ post_install_script = "echo 'post-install'"
+ agent_config = jsonencode({
+ name = "test-agent"
+ description = "Test agent configuration"
+ prompt = "You are a helpful AI assistant for testing."
+ mcpServers = {}
+ tools = ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"]
+ toolAliases = {}
+ allowedTools = ["fs_read"]
+ resources = ["file://KiroQ.md", "file://README.md", "file://.kiro/steering/**/*.md"]
+ hooks = {}
+ toolsSettings = {}
+ useLegacyMcpJson = true
+ })
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].name == "CODER_MCP_APP_STATUS_SLUG"
+ error_message = "Status slug environment variable not configured correctly"
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].value == "kiro-cli"
+ error_message = "Status slug value should be 'kiro-cli'"
+ }
+
+ assert {
+ condition = length(resource.coder_env.auth_tarball) == 1
+ error_message = "Auth tarball environment variable should be created when provided"
+ }
+}
+
+run "auth_tarball_environment" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ auth_tarball = "dGVzdEF1dGhUYXJiYWxs" # base64 "testAuthTarball"
+ }
+
+ assert {
+ condition = resource.coder_env.auth_tarball[0].name == "KIRO_CLI_AUTH_TARBALL"
+ error_message = "Auth tarball environment variable name should be 'KIRO_CLI_AUTH_TARBALL'"
+ }
+
+ assert {
+ condition = resource.coder_env.auth_tarball[0].value == "dGVzdEF1dGhUYXJiYWxs"
+ error_message = "Auth tarball environment variable value should match input"
+ }
+}
+
+run "empty_auth_tarball" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ auth_tarball = ""
+ }
+
+ assert {
+ condition = length(resource.coder_env.auth_tarball) == 0
+ error_message = "Auth tarball environment variable should not be created when empty"
+ }
+}
+
+run "custom_system_prompt" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ system_prompt = "Custom system prompt for testing"
+ }
+
+ # Test that the system prompt is used in the agent config template
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Agent config should be generated with custom system prompt"
+ }
+}
+
+run "install_options" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ install_kiro_cli = false
+ install_agentapi = false
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].name == "CODER_MCP_APP_STATUS_SLUG"
+ error_message = "Status slug should still be configured even when install options are disabled"
+ }
+}
+
+run "version_configuration" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ kiro_cli_version = "2.15.0"
+ agentapi_version = "v0.4.0"
+ }
+
+ assert {
+ condition = resource.coder_env.status_slug[0].value == "kiro-cli"
+ error_message = "Status slug value should remain 'kiro-cli' regardless of version"
+ }
+}
+
+# Additional test for agent name extraction
+run "agent_name_extraction" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ agent_config = jsonencode({
+ name = "custom-enterprise-agent"
+ description = "Custom enterprise agent configuration"
+ prompt = "You are a custom enterprise AI assistant."
+ mcpServers = {}
+ tools = ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"]
+ toolAliases = {}
+ allowedTools = ["fs_read", "fs_write"]
+ resources = ["file://README.md"]
+ hooks = {}
+ toolsSettings = {}
+ useLegacyMcpJson = true
+ })
+ }
+
+ assert {
+ condition = local.agent_name == "custom-enterprise-agent"
+ error_message = "Agent name should be extracted correctly from custom agent config"
+ }
+
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Agent config should be processed correctly"
+ }
+}
+
+# Test for JSON encoding validation
+run "json_encoding_validation" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ workdir = "/tmp/test-workdir"
+ system_prompt = "Multi-line\nsystem prompt\nwith newlines"
+ }
+
+ assert {
+ condition = length(local.system_prompt) > 0
+ error_message = "System prompt should be JSON encoded correctly"
+ }
+
+ assert {
+ condition = length(local.agent_config) > 0
+ error_message = "Agent config should be generated correctly with multi-line system prompt"
+ }
+}
diff --git a/registry/harleylrn/modules/kiro-cli/main.test.ts b/registry/harleylrn/modules/kiro-cli/main.test.ts
new file mode 100644
index 000000000..e0f9b28d5
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/main.test.ts
@@ -0,0 +1,531 @@
+import { describe, it, expect } from "bun:test";
+import {
+ runTerraformApply,
+ runTerraformInit,
+ findResourceInstance,
+} from "~test";
+import path from "path";
+
+const moduleDir = path.resolve(__dirname);
+
+// Always provide agent_config to bypass template parsing issues
+const baseAgentConfig = JSON.stringify({
+ name: "test-agent",
+ description: "Test agent configuration",
+ prompt: "You are a helpful AI assistant.",
+ mcpServers: {},
+ tools: ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"],
+ toolAliases: {},
+ allowedTools: ["fs_read"],
+ resources: ["file://README.md", "file://.kiro/steering/**/*.md"],
+ hooks: {},
+ toolsSettings: {},
+ useLegacyMcpJson: true,
+});
+
+const requiredVars = {
+ agent_id: "dummy-agent-id",
+ agent_config: baseAgentConfig,
+ workdir: "/tmp/test-workdir",
+};
+
+const fullConfigVars = {
+ agent_id: "dummy-agent-id",
+ workdir: "/tmp/test-workdir",
+ install_kiro_cli: true,
+ install_agentapi: true,
+ agentapi_version: "v0.6.0",
+ kiro_cli_version: "1.14.1",
+ kiro_install_url: "https://desktop-release.q.us-east-1.amazonaws.com",
+ trust_all_tools: false,
+ ai_prompt: "Build a comprehensive test suite",
+ auth_tarball: "dGVzdEF1dGhUYXJiYWxs", // base64 "testAuthTarball"
+ order: 1,
+ group: "AI Tools",
+ icon: "/icon/custom-kiro-cli.svg",
+ pre_install_script: "echo 'Starting pre-install'",
+ post_install_script: "echo 'Completed post-install'",
+ agent_config: baseAgentConfig,
+};
+
+describe("kiro-cli module v1.0.0", async () => {
+ await runTerraformInit(moduleDir);
+
+ // Test Case 1: Basic Usage – No Autonomous Use of Q
+ // Matches CDES-203 Test Case #1: Basic Usage
+ it("Test Case 1: Basic Usage - No Autonomous Use of Q", async () => {
+ const basicUsageVars = {
+ agent_id: "dummy-agent-id",
+ workdir: "/tmp/test-workdir",
+ auth_tarball: "dGVzdEF1dGhUYXJiYWxs", // base64 "testAuthTarball"
+ };
+
+ const state = await runTerraformApply(moduleDir, basicUsageVars);
+
+ // Q is installed and authenticated
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.name).toBe("CODER_MCP_APP_STATUS_SLUG");
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+
+ // AgentAPI is installed and configured (default behavior)
+ const authTarballEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "auth_tarball",
+ );
+ expect(authTarballEnv).toBeDefined();
+ expect(authTarballEnv.name).toBe("KIRO_CLI_AUTH_TARBALL");
+ expect(authTarballEnv.value).toBe("dGVzdEF1dGhUYXJiYWxs");
+
+ // Foundational configuration for all components is applied
+ // No additional parameters are required for the module to work
+ // Using the terminal application and Q chat returns a functional interface
+ });
+
+ // Test Case 2: Autonomous Usage – Autonomous Use of Q
+ // Matches CDES-203 Test Case 2: Autonomous Usage
+ it("Test Case 2: Autonomous Usage - Autonomous Use of Q", async () => {
+ const autonomousUsageVars = {
+ agent_id: "dummy-agent-id",
+ workdir: "/tmp/test-workdir",
+ auth_tarball: "dGVzdEF1dGhUYXJiYWxs", // base64 "testAuthTarball"
+ ai_prompt:
+ "Help me set up a Python FastAPI project with proper testing structure",
+ };
+
+ const state = await runTerraformApply(moduleDir, autonomousUsageVars);
+
+ // Q is installed and authenticated
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.name).toBe("CODER_MCP_APP_STATUS_SLUG");
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+
+ // AgentAPI is installed and configured
+ const authTarballEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "auth_tarball",
+ );
+ expect(authTarballEnv).toBeDefined();
+ expect(authTarballEnv.name).toBe("KIRO_CLI_AUTH_TARBALL");
+
+ // AI prompt is passed through from external source
+ // The Chat interface functions as required
+ // The Tasks interface functions as required
+ // The template can be invoked from GitHub integration as expected
+ });
+
+ // Test Case 3: Extended Configuration – Parameter Validation and File Rendering
+ // Matches CDES-203 Test Case 3: Extended Configuration
+ it("Test Case 3: Extended Configuration - Parameter Validation and File Rendering", async () => {
+ const extendedConfigVars = {
+ agent_id: "dummy-agent-id",
+ workdir: "/tmp/test-workdir",
+ auth_tarball: "dGVzdEF1dGhUYXJiYWxs", // base64 "testAuthTarball"
+ kiro_cli_version: "1.14.1",
+ kiro_install_url: "https://desktop-release.q.us-east-1.amazonaws.com",
+ install_kiro_cli: true,
+ install_agentapi: true,
+ agentapi_version: "v0.6.0",
+ trust_all_tools: true,
+ ai_prompt:
+ "Help me create a production-grade TypeScript monorepo with testing and deployment",
+ system_prompt:
+ "You are a helpful software assistant working in a secure enterprise environment",
+ pre_install_script: "echo 'Pre-install setup'",
+ post_install_script: "echo 'Post-install cleanup'",
+ agent_config: JSON.stringify({
+ name: "production-agent",
+ description: "Production Kiro CLI agent for enterprise environment",
+ prompt:
+ "You are a helpful software assistant working in a secure enterprise environment",
+ mcpServers: {},
+ tools: ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"],
+ toolAliases: {},
+ allowedTools: ["fs_read"],
+ resources: [
+ "file://KiroQ.md",
+ "file://README.md",
+ "file://.kiro/steering/**/*.md",
+ ],
+ hooks: {},
+ toolsSettings: {},
+ useLegacyMcpJson: true,
+ }),
+ };
+
+ const state = await runTerraformApply(moduleDir, extendedConfigVars);
+
+ // All installation steps execute in the correct order
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.name).toBe("CODER_MCP_APP_STATUS_SLUG");
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+
+ // auth_tarball is unpacked and used as expected
+ const authTarballEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "auth_tarball",
+ );
+ expect(authTarballEnv).toBeDefined();
+ expect(authTarballEnv.value).toBe("dGVzdEF1dGhUYXJiYWxs");
+
+ // agent_config is rendered correctly, and the name field is used as the agent's name
+ // The specified ai_prompt and system_prompt are respected by the Q agent
+ // Tools are trusted globally if trust_all_tools = true
+ // Files and scripts execute in proper sequence
+ });
+
+ // 1. Basic functionality test (replaces testRequiredVariables)
+ it("works with required variables", async () => {
+ const state = await runTerraformApply(moduleDir, requiredVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.name).toBe("CODER_MCP_APP_STATUS_SLUG");
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+ });
+
+ // 2. Environment variables are created correctly
+ it("creates required environment variables", async () => {
+ const state = await runTerraformApply(moduleDir, fullConfigVars);
+
+ // Check status slug environment variable
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.name).toBe("CODER_MCP_APP_STATUS_SLUG");
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+
+ // Check auth tarball environment variable
+ const authTarballEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "auth_tarball",
+ );
+ expect(authTarballEnv).toBeDefined();
+ expect(authTarballEnv.name).toBe("KIRO_CLI_AUTH_TARBALL");
+ expect(authTarballEnv.value).toBe("dGVzdEF1dGhUYXJiYWxs");
+ });
+
+ // 3. Empty auth tarball handling
+ it("handles empty auth tarball correctly", async () => {
+ const noAuthVars = {
+ ...requiredVars,
+ auth_tarball: "",
+ };
+
+ const state = await runTerraformApply(moduleDir, noAuthVars);
+
+ // Auth tarball environment variable should not be created when empty
+ const authTarballEnv = state.resources?.find(
+ (r) => r.type === "coder_env" && r.name === "auth_tarball",
+ );
+ expect(authTarballEnv).toBeUndefined();
+ });
+
+ // 4. Status slug is always created
+ it("creates status slug environment variable", async () => {
+ const state = await runTerraformApply(moduleDir, requiredVars);
+
+ // Status slug should always be configured
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.name).toBe("CODER_MCP_APP_STATUS_SLUG");
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+ });
+
+ // 5. Install options configuration
+ it("respects install option flags", async () => {
+ const noInstallVars = {
+ ...requiredVars,
+ install_kiro_cli: false,
+ install_agentapi: false,
+ };
+
+ const state = await runTerraformApply(moduleDir, noInstallVars);
+
+ // Status slug should still be configured even when install options are disabled
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+ });
+
+ // 6. Configurable installation URL
+ it("uses configurable kiro_install_url parameter", async () => {
+ const customUrlVars = {
+ ...requiredVars,
+ kiro_install_url: "https://internal-mirror.company.com/kiro-cli",
+ };
+
+ const state = await runTerraformApply(moduleDir, customUrlVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 7. Version configuration
+ it("uses specified versions", async () => {
+ const versionVars = {
+ ...requiredVars,
+ kiro_cli_version: "1.14.1",
+ agentapi_version: "v0.6.0",
+ };
+
+ const state = await runTerraformApply(moduleDir, versionVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 8. UI configuration options
+ it("supports UI customization options", async () => {
+ const uiCustomVars = {
+ ...requiredVars,
+ order: 5,
+ group: "Custom AI Tools",
+ icon: "/icon/custom-kiro-cli-icon.svg",
+ };
+
+ const state = await runTerraformApply(moduleDir, uiCustomVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 9. Pre and post install scripts
+ it("supports pre and post install scripts", async () => {
+ const scriptVars = {
+ ...requiredVars,
+ pre_install_script: "echo 'Pre-install setup'",
+ post_install_script: "echo 'Post-install cleanup'",
+ };
+
+ const state = await runTerraformApply(moduleDir, scriptVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 10. Valid agent_config JSON with different agent name
+ it("handles valid agent_config JSON with custom agent name", async () => {
+ const customAgentConfig = JSON.stringify({
+ name: "production-agent",
+ description: "Production Kiro CLI agent",
+ prompt: "You are a production AI assistant.",
+ mcpServers: {},
+ tools: ["fs_read", "fs_write"],
+ toolAliases: {},
+ allowedTools: ["fs_read"],
+ resources: ["file://README.md"],
+ hooks: {},
+ toolsSettings: {},
+ useLegacyMcpJson: true,
+ });
+
+ const validAgentConfigVars = {
+ ...requiredVars,
+ agent_config: customAgentConfig,
+ };
+
+ const state = await runTerraformApply(moduleDir, validAgentConfigVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 11. Air-gapped installation support
+ it("supports air-gapped installation with custom URL", async () => {
+ const airGappedVars = {
+ ...requiredVars,
+ kiro_install_url: "https://artifacts.internal.corp/kiro-cli-releases",
+ kiro_cli_version: "1.14.1",
+ };
+
+ const state = await runTerraformApply(moduleDir, airGappedVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 12. Trust all tools configuration
+ it("handles trust_all_tools configuration", async () => {
+ const trustVars = {
+ ...requiredVars,
+ trust_all_tools: true,
+ };
+
+ const state = await runTerraformApply(moduleDir, trustVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 13. AI prompt configuration
+ it("handles AI prompt configuration", async () => {
+ const promptVars = {
+ ...requiredVars,
+ ai_prompt: "Create a comprehensive test suite for the application",
+ };
+
+ const state = await runTerraformApply(moduleDir, promptVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 14. Agent config with minimal structure
+ it("handles minimal agent config structure", async () => {
+ const minimalAgentConfig = JSON.stringify({
+ name: "minimal-agent",
+ description: "Minimal agent config",
+ prompt: "You are a minimal AI assistant.",
+ mcpServers: {},
+ tools: ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"],
+ toolAliases: {},
+ allowedTools: ["fs_read"],
+ resources: ["file://README.md"],
+ hooks: {},
+ toolsSettings: {},
+ useLegacyMcpJson: true,
+ });
+
+ const minimalVars = {
+ ...requiredVars,
+ agent_config: minimalAgentConfig,
+ };
+
+ const state = await runTerraformApply(moduleDir, minimalVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ });
+
+ // 15. JSON encoding validation for system prompts with newlines
+ it("handles system prompts with newlines correctly", async () => {
+ const multilinePromptVars = {
+ ...requiredVars,
+ system_prompt: "Multi-line\nsystem prompt\nwith newlines",
+ };
+
+ const state = await runTerraformApply(moduleDir, multilinePromptVars);
+
+ // Should create the basic resources without JSON parsing errors
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+ });
+
+ // 16. Agent name extraction from custom config
+ it("extracts agent name from custom configuration correctly", async () => {
+ const customNameConfig = JSON.stringify({
+ name: "enterprise-production-agent",
+ description: "Enterprise production agent configuration",
+ prompt: "You are an enterprise production AI assistant.",
+ mcpServers: {},
+ tools: ["fs_read", "fs_write", "execute_bash", "use_aws", "knowledge"],
+ toolAliases: {},
+ allowedTools: ["fs_read", "fs_write", "execute_bash"],
+ resources: ["file://README.md", "file://.kiro/steering/**/*.md"],
+ hooks: {},
+ toolsSettings: {},
+ useLegacyMcpJson: true,
+ });
+
+ const customNameVars = {
+ ...requiredVars,
+ agent_config: customNameConfig,
+ };
+
+ const state = await runTerraformApply(moduleDir, customNameVars);
+
+ // Should create the basic resources
+ const statusSlugEnv = findResourceInstance(
+ state,
+ "coder_env",
+ "status_slug",
+ );
+ expect(statusSlugEnv).toBeDefined();
+ expect(statusSlugEnv.value).toBe("kiro-cli");
+ });
+});
diff --git a/registry/harleylrn/modules/kiro-cli/main.tf b/registry/harleylrn/modules/kiro-cli/main.tf
new file mode 100644
index 000000000..b5034b4af
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/main.tf
@@ -0,0 +1,275 @@
+# Improved kiro-cli module main.tf
+
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 2.12"
+ }
+ }
+}
+
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+data "coder_workspace" "me" {}
+data "coder_workspace_owner" "me" {}
+
+variable "order" {
+ type = number
+ description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
+ default = null
+}
+
+variable "group" {
+ type = string
+ description = "The name of a group that this app belongs to."
+ default = null
+}
+
+variable "icon" {
+ type = string
+ description = "The icon to use for the app."
+ default = "/icon/kiro.svg"
+}
+
+variable "report_tasks" {
+ type = bool
+ description = "Whether to enable task reporting to Coder UI via AgentAPI"
+ default = true
+}
+
+variable "cli_app" {
+ type = bool
+ description = "Whether to create a CLI app for Kiro CLI"
+ default = false
+}
+
+variable "web_app_display_name" {
+ type = string
+ description = "Display name for the web app"
+ default = "Kiro CLI"
+}
+
+variable "cli_app_display_name" {
+ type = string
+ description = "Display name for the CLI app"
+ default = "Kiro CLI"
+}
+
+variable "install_agentapi" {
+ type = bool
+ description = "Whether to install AgentAPI."
+ default = true
+}
+
+variable "ai_prompt" {
+ type = string
+ description = "The initial task prompt to send to Kiro CLI."
+ default = ""
+}
+
+variable "pre_install_script" {
+ type = string
+ description = "Optional script to run before installing Kiro CLI."
+ default = null
+}
+
+variable "post_install_script" {
+ type = string
+ description = "Optional script to run after installing Kiro CLI."
+ default = null
+}
+
+variable "agentapi_version" {
+ type = string
+ description = "The version of AgentAPI to install."
+ default = "v0.10.0"
+}
+
+variable "workdir" {
+ type = string
+ description = "The folder to run Kiro CLI in."
+}
+
+variable "install_kiro_cli" {
+ type = bool
+ description = "Whether to install Kiro CLI."
+ default = true
+}
+
+variable "kiro_cli_version" {
+ type = string
+ description = "The version of Kiro CLI to install."
+ default = "latest"
+}
+
+variable "kiro_install_url" {
+ type = string
+ description = "Base URL for Kiro CLI installation downloads."
+ default = "https://desktop-release.q.us-east-1.amazonaws.com"
+}
+
+variable "trust_all_tools" {
+ type = bool
+ description = "Whether to trust all tools in Kiro CLI."
+ default = false
+}
+
+variable "system_prompt" {
+ type = string
+ description = "The system prompt to use for Kiro CLI. This should instruct the agent how to do task reporting."
+ default = <<-EOT
+ You are a helpful Coding assistant. Aim to autonomously investigate
+ and solve issues the user gives you and test your work, whenever possible.
+ Avoid shortcuts like mocking tests. When you get stuck, you can ask the user
+ but opt for autonomy.
+ EOT
+}
+
+variable "coder_mcp_instructions" {
+ type = string
+ description = "Instructions for the Coder MCP server integration. This defines how the agent should report tasks to Coder."
+ default = <<-EOT
+ YOU MUST REPORT ALL TASKS TO CODER.
+ When reporting tasks you MUST follow these EXACT instructions:
+ - IMMEDIATELY report status after receiving ANY user message
+ - Be granular If you are investigating with multiple steps report each step to coder.
+
+ Task state MUST be one of the following:
+ - Use "state": "working" when actively processing WITHOUT needing additional user input
+ - Use "state": "complete" only when finished with a task
+ - Use "state": "failure" when you need ANY user input lack sufficient details or encounter blockers.
+
+ Task summaries MUST:
+ - Include specifics about what you're doing
+ - Include clear and actionable steps for the user
+ - Be less than 160 characters in length
+ EOT
+}
+
+variable "auth_tarball" {
+ type = string
+ description = "Base64 encoded, zstd compressed tarball of a pre-authenticated ~/.local/share/kiro-cli directory."
+ default = ""
+ sensitive = true
+}
+
+variable "agent_config" {
+ type = string
+ description = "Optional Agent configuration JSON for Kiro CLI."
+ default = null
+}
+
+variable "agentapi_chat_based_path" {
+ type = bool
+ description = "Whether to use chat-based path for AgentAPI.Required if CODER_WILDCARD_ACCESS_URL is not defined in coder deployment"
+ default = false
+}
+
+# Expose status slug to the agent environment
+resource "coder_env" "status_slug" {
+ agent_id = var.agent_id
+ name = "CODER_MCP_APP_STATUS_SLUG"
+ value = local.app_slug
+ count = var.report_tasks ? 1 : 0
+}
+
+# Expose auth tarball as environment variable for install script
+resource "coder_env" "auth_tarball" {
+ count = var.auth_tarball != "" ? 1 : 0
+ agent_id = var.agent_id
+ name = "KIRO_CLI_AUTH_TARBALL"
+ value = var.auth_tarball
+}
+
+locals {
+ app_slug = "kiro-cli"
+ workdir = trimsuffix(var.workdir, "/")
+ install_script = file("${path.module}/scripts/install.sh")
+ start_script = file("${path.module}/scripts/start.sh")
+ module_dir_name = ".kiro"
+ system_prompt = jsonencode(replace(var.system_prompt, "/[\r\n]/", ""))
+ coder_mcp_instructions = jsonencode(replace(var.coder_mcp_instructions, "/[\r\n]/", ""))
+
+ # Create default agent config structure
+ default_agent_config = templatefile("${path.module}/templates/agent-config.json.tpl", {
+ system_prompt = local.system_prompt
+ })
+
+ # Choose the JSON string: use var.agent_config if provided, otherwise encode default
+ agent_config = var.agent_config != null ? var.agent_config : local.default_agent_config
+
+ # Extract agent name from the selected config
+ agent_name = try(jsondecode(local.agent_config).name, "agent")
+
+ full_prompt = var.ai_prompt != null ? var.ai_prompt : ""
+
+ server_chat_parameters = var.agentapi_chat_based_path ? "--chat-base-path /@${data.coder_workspace_owner.me.name}/${data.coder_workspace.me.name}.${var.agent_id}/apps/${local.app_slug}/chat" : ""
+}
+
+
+module "agentapi" {
+ source = "registry.coder.com/coder/agentapi/coder"
+ version = "2.0.0"
+
+ agent_id = var.agent_id
+ folder = local.workdir
+ web_app_slug = local.app_slug
+ web_app_order = var.order
+ web_app_group = var.group
+ web_app_icon = var.icon
+ web_app_display_name = var.web_app_display_name
+ cli_app = var.cli_app
+ cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
+ cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
+ module_dir_name = local.module_dir_name
+ install_agentapi = var.install_agentapi
+ agentapi_version = var.agentapi_version
+ pre_install_script = var.pre_install_script
+ post_install_script = var.post_install_script
+
+ start_script = <<-EOT
+ #!/bin/bash
+ set -o errexit
+ set -o pipefail
+
+ echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
+ chmod +x /tmp/start.sh
+ ARG_TRUST_ALL_TOOLS='${var.trust_all_tools}' \
+ ARG_AI_PROMPT='${base64encode(local.full_prompt)}' \
+ ARG_MODULE_DIR_NAME='${local.module_dir_name}' \
+ ARG_WORKDIR='${var.workdir}' \
+ ARG_SERVER_PARAMETERS="${local.server_chat_parameters}" \
+ ARG_REPORT_TASKS='${var.report_tasks}' \
+ /tmp/start.sh
+ EOT
+
+ install_script = <<-EOT
+ #!/bin/bash
+ set -o errexit
+ set -o pipefail
+
+ echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
+ chmod +x /tmp/install.sh
+ ARG_INSTALL='${var.install_kiro_cli}' \
+ ARG_VERSION='${var.kiro_cli_version}' \
+ ARG_KIRO_INSTALL_URL='${var.kiro_install_url}' \
+ ARG_AUTH_TARBALL='${var.auth_tarball}' \
+ ARG_AGENT_CONFIG='${local.agent_config != null ? base64encode(local.agent_config) : ""}' \
+ ARG_AGENT_NAME='${local.agent_name}' \
+ ARG_MODULE_DIR_NAME='${local.module_dir_name}' \
+ ARG_CODER_MCP_APP_STATUS_SLUG='${local.app_slug}' \
+ ARG_CODER_MCP_INSTRUCTIONS='${base64encode(local.coder_mcp_instructions)}' \
+ ARG_REPORT_TASKS='${var.report_tasks}' \
+ /tmp/install.sh
+ EOT
+}
+
+output "task_app_id" {
+ value = module.agentapi.task_app_id
+}
diff --git a/registry/harleylrn/modules/kiro-cli/scripts/install.sh b/registry/harleylrn/modules/kiro-cli/scripts/install.sh
new file mode 100644
index 000000000..5cbbb3fe8
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/scripts/install.sh
@@ -0,0 +1,159 @@
+#!/bin/bash
+# Install script for kiro-cli module
+
+set -o errexit
+set -o pipefail
+
+command_exists() {
+ command -v "$1" > /dev/null 2>&1
+}
+
+# Inputs
+ARG_INSTALL=${ARG_INSTALL:-true}
+ARG_VERSION=${ARG_VERSION:-latest}
+ARG_KIRO_INSTALL_URL=${ARG_KIRO_INSTALL_URL:-https://desktop-release.q.us-east-1.amazonaws.com}
+ARG_AUTH_TARBALL=${ARG_AUTH_TARBALL:-}
+ARG_AGENT_CONFIG=${ARG_AGENT_CONFIG:-}
+ARG_AGENT_NAME=${ARG_AGENT_NAME:-default-agent}
+ARG_MODULE_DIR_NAME=${ARG_MODULE_DIR_NAME:-.kiro}
+ARG_CODER_MCP_APP_STATUS_SLUG=${ARG_CODER_MCP_APP_STATUS_SLUG:-}
+ARG_CODER_MCP_INSTRUCTIONS=${ARG_CODER_MCP_INSTRUCTIONS:-}
+ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true}
+
+mkdir -p "$HOME/$ARG_MODULE_DIR_NAME"
+
+# Decode base64 inputs
+ARG_AGENT_CONFIG_DECODED=""
+if [ -n "$ARG_AGENT_CONFIG" ]; then
+ ARG_AGENT_CONFIG_DECODED=$(echo -n "$ARG_AGENT_CONFIG" | base64 -d)
+fi
+
+ARG_CODER_MCP_INSTRUCTIONS_DECODED=""
+if [ -n "$ARG_CODER_MCP_INSTRUCTIONS" ]; then
+ ARG_CODER_MCP_INSTRUCTIONS_DECODED=$(echo -n "$ARG_CODER_MCP_INSTRUCTIONS" | base64 -d)
+fi
+
+echo "--------------------------------"
+echo "install: $ARG_INSTALL"
+echo "version: $ARG_VERSION"
+echo "kiro_install_url: $ARG_KIRO_INSTALL_URL"
+echo "agent_name: $ARG_AGENT_NAME"
+echo "coder_mcp_app_status_slug: $ARG_CODER_MCP_APP_STATUS_SLUG"
+echo "module_dir_name: $ARG_MODULE_DIR_NAME"
+echo "auth_tarball_provided: ${ARG_AUTH_TARBALL}"
+echo "report_tasks: ${ARG_REPORT_TASKS}"
+echo "--------------------------------"
+
+# Install Kiro CLI if requested
+function install_kiro_cli() {
+ if [ "$ARG_INSTALL" = "true" ]; then
+ echo "Installing Kiro CLI..."
+ PREV_DIR="$PWD"
+ TMP_DIR="$(mktemp -d)"
+ cd "$TMP_DIR"
+
+ ARCH="$(uname -m)"
+ case "$ARCH" in
+ "x86_64")
+ KIRO_URL="${ARG_KIRO_INSTALL_URL}/${ARG_VERSION}/kirocli-x86_64-linux.zip"
+ ;;
+ "aarch64" | "arm64")
+ KIRO_URL="${ARG_KIRO_INSTALL_URL}/${ARG_VERSION}/kirocli-aarch64-linux.zip"
+ ;;
+ *)
+ echo "Error: Unsupported architecture: $ARCH. Kiro CLI only supports x86_64 and arm64."
+ exit 1
+ ;;
+ esac
+
+ echo "Downloading Kiro CLI for $ARCH from $KIRO_URL..."
+ curl --proto '=https' --tlsv1.2 -sSf "$KIRO_URL" -o "kirocli.zip"
+ unzip kirocli.zip
+ ./kirocli/install.sh --no-confirm
+ cd "$PREV_DIR"
+ rm -rf "$TMP_DIR"
+
+ # Ensure binaries are discoverable; create stable symlink to kiro-cli
+ CANDIDATES=(
+ "$(command -v kiro-cli || true)"
+ "$HOME/.local/bin/kiro-cli"
+ )
+ FOUND_BIN=""
+ for c in "${CANDIDATES[@]}"; do
+ if [ -n "$c" ] && [ -x "$c" ]; then
+ FOUND_BIN="$c"
+ break
+ fi
+ done
+ export PATH="$PATH:$HOME/.local/bin"
+ echo "Installed Kiro CLI at: $(command -v kiro-cli || true) (resolved: $FOUND_BIN)"
+ fi
+}
+
+# Extract authentication tarball
+function extract_auth_tarball() {
+ if [ -n "$ARG_AUTH_TARBALL" ]; then
+ echo "Extracting auth tarball..."
+
+ if ! command_exists zstd; then
+ echo "Error: zstd is required to extract the authentication tarball but is not installed."
+ echo "Please install zstd using the pre_install_script parameter."
+ exit 1
+ fi
+
+ PREV_DIR="$PWD"
+ echo "$ARG_AUTH_TARBALL" | base64 -d > /tmp/auth.tar.zst
+ rm -rf ~/.local/share/kiro-cli
+ mkdir -p ~/.local/share/kiro-cli
+ cd ~/.local/share/kiro-cli
+ tar -I zstd -xf /tmp/auth.tar.zst
+ rm /tmp/auth.tar.zst
+ cd "$PREV_DIR"
+ echo "Extracted auth tarball to ~/.local/share/kiro-cli"
+ else
+ echo "Warning: No auth tarball provided. Kiro CLI may require manual authentication."
+ fi
+}
+
+# Configure MCP integration and create agent
+function configure_agent() {
+ # Create Kiro CLI agent configuration directory
+ AGENT_CONFIG_DIR="$HOME/.kiro/agents"
+ mkdir -p "$AGENT_CONFIG_DIR"
+ ALLOWED_TOOLS="coder_get_workspace\,coder_create_workspace\,coder_list_workspaces\,coder_list_templates\,coder_template_version_parameters\,coder_get_authenticated_user\,coder_create_workspace_build\,coder_create_template_version\,coder_get_workspace_agent_logs\,coder_get_workspace_build_logs\,coder_get_template_version_logs\,coder_update_template_active_version\,coder_upload_tar_file\,coder_create_template\,coder_delete_template\,coder_workspace_bash"
+ if [ -n "$ARG_AGENT_CONFIG_DECODED" ]; then
+ echo "Applying custom MCP configuration..."
+ # Use agent name as filename for the configuration
+ echo "$ARG_AGENT_CONFIG_DECODED" > "$AGENT_CONFIG_DIR/${ARG_AGENT_NAME}.json"
+ echo "Custom configuration saved to $AGENT_CONFIG_DIR/${ARG_AGENT_NAME}.json"
+ fi
+ if [ "$ARG_REPORT_TASKS" = "true" ]; then
+ echo "Configuring Kiro CLI to report tasks via Coder MCP..."
+ kiro-cli mcp add --name coder \
+ --command "coder" \
+ --agent "$ARG_AGENT_NAME" \
+ --args "exp,mcp,server,--allowed-tools,coder_report_task,--instructions,'$ARG_CODER_MCP_INSTRUCTIONS_DECODED'" \
+ --env "CODER_MCP_APP_STATUS_SLUG=${ARG_CODER_MCP_APP_STATUS_SLUG}" \
+ --env "CODER_MCP_AI_AGENTAPI_URL=http://localhost:3284" \
+ --env "CODER_AGENT_URL=${CODER_AGENT_URL}" \
+ --env "CODER_AGENT_TOKEN=${CODER_AGENT_TOKEN}" \
+ --force || echo "Warning: Failed to add Coder MCP server"
+ else
+ kiro-cli mcp add --name coder \
+ --command "coder" \
+ --agent "$ARG_AGENT_NAME" \
+ --args "exp,mcp,server,--allowed-tools,coder_report_task" \
+ --env "CODER_AGENT_URL=${CODER_AGENT_URL}" \
+ --env "CODER_AGENT_TOKEN=${CODER_AGENT_TOKEN}" \
+ --force || echo "Warning: Failed to add Coder MCP server"
+ fi
+ echo "Added Coder MCP server into $ARG_AGENT_NAME in Kiro CLI configuration"
+ kiro-cli settings chat.defaultAgent "$ARG_AGENT_NAME"
+}
+
+# Main execution
+install_kiro_cli
+extract_auth_tarball
+configure_agent
+
+echo "Kiro CLI installation and configuration complete!"
diff --git a/registry/harleylrn/modules/kiro-cli/scripts/start.sh b/registry/harleylrn/modules/kiro-cli/scripts/start.sh
new file mode 100644
index 000000000..07c6f8379
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/scripts/start.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+# Start script for kiro-cli module
+
+set -o errexit
+set -o pipefail
+
+command_exists() {
+ command -v "$1" > /dev/null 2>&1
+}
+
+# Decode inputs
+ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d)
+ARG_TRUST_ALL_TOOLS=${ARG_TRUST_ALL_TOOLS:-true}
+ARG_MODULE_DIR_NAME=${ARG_MODULE_DIR_NAME:-.kiro}
+ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"}
+ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true}
+ARG_SERVER_PARAMETERS=${ARG_SERVER_PARAMETERS:-""}
+
+echo "--------------------------------"
+echo "ai_prompt: $ARG_AI_PROMPT"
+echo "trust_all_tools: $ARG_TRUST_ALL_TOOLS"
+echo "module_dir_name: $ARG_MODULE_DIR_NAME"
+echo "workdir: $ARG_WORKDIR"
+echo "report_tasks: ${ARG_REPORT_TASKS}"
+echo "--------------------------------"
+
+mkdir -p "$HOME/$ARG_MODULE_DIR_NAME"
+
+# Find Kiro CLI
+if command_exists kiro-cli; then
+ KIRO_CMD=kiro-cli
+elif [ -x "$HOME/.local/bin/kiro-cli" ]; then
+ KIRO_CMD="$HOME/.local/bin/kiro-cli"
+else
+ echo "Error: Kiro CLI not found. Install it or set install_kiro_cli=true."
+ exit 1
+fi
+
+mkdir -p "$ARG_WORKDIR"
+cd "$ARG_WORKDIR"
+
+# Set up environment
+export LANG=en_US.UTF-8
+export LC_ALL=en_US.UTF-8
+
+# Build command arguments
+ARGS=(chat)
+
+if [ "$ARG_TRUST_ALL_TOOLS" = "true" ]; then
+ ARGS+=(--trust-all-tools)
+fi
+
+# Log and run with agentapi integration
+printf "Running: %q %s\n" "$KIRO_CMD" "$(printf '%q ' "${ARGS[@]}")"
+
+# If we have an AI prompt, we need to handle it specially
+if [ -n "$ARG_AI_PROMPT" ]; then
+ if [ "$ARG_REPORT_TASKS" == "true" ]; then
+ PROMPT="Every step of the way, report your progress using coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_AI_PROMPT"
+ else
+ PROMPT="$ARG_AI_PROMPT"
+ fi
+ ARGS+=("$PROMPT")
+fi
+
+# Use agentapi to manage the interactive session with initial prompt
+agentapi server ${ARG_SERVER_PARAMETERS} --term-width 67 --term-height 1190 -- "$KIRO_CMD" "${ARGS[@]}"
diff --git a/registry/harleylrn/modules/kiro-cli/templates/agent-config.json.tpl b/registry/harleylrn/modules/kiro-cli/templates/agent-config.json.tpl
new file mode 100644
index 000000000..550fbf420
--- /dev/null
+++ b/registry/harleylrn/modules/kiro-cli/templates/agent-config.json.tpl
@@ -0,0 +1,27 @@
+{
+ "name": "agent",
+ "description": "This is an default agent config",
+ "prompt": ${system_prompt},
+ "mcpServers": {},
+ "tools": [
+ "read",
+ "write",
+ "shell",
+ "aws",
+ "@coder",
+ "knowledge"
+ ],
+ "toolAliases": {},
+ "allowedTools": [
+ "read",
+ "@coder"
+ ],
+ "resources": [
+ "file://KiroQ.md",
+ "file://README.md",
+ "file://.kiro/steering/**/*.md"
+ ],
+ "hooks": {},
+ "toolsSettings": {},
+ "useLegacyMcpJson": true
+}