Terraform module development patterns and best practices. Provides structure, versioning, and output scaffolds. Use when creating reusable modules.
/plugin marketplace add lgbarn/terraform-aws-eks/plugin install lgbarn-terraform-aws-eks-plugins-terraform-aws-eks@lgbarn/terraform-aws-eksThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Terraform module development patterns and conventions.
modules/
└── <module-name>/
├── main.tf # Primary resources
├── variables.tf # Input variables
├── outputs.tf # Module outputs
├── versions.tf # Version constraints
├── locals.tf # Local values
├── data.tf # Data sources (optional)
├── README.md # Documentation
├── examples/
│ ├── basic/
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── README.md
│ └── complete/
│ ├── main.tf
│ ├── outputs.tf
│ └── README.md
└── tests/
├── basic.tftest.hcl
└── complete.tftest.hcl
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
variable "project" {
description = "Project name used in resource naming"
type = string
validation {
condition = can(regex("^[a-z][a-z0-9-]*$", var.project))
error_message = "Project name must start with a letter and contain only lowercase letters, numbers, and hyphens."
}
}
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_type" {
description = "EC2 instance type for compute resources"
type = string
default = "t3.medium"
}
variable "enable_encryption" {
description = "Enable encryption at rest for all supported resources"
type = bool
default = true
}
variable "node_groups" {
description = "Map of EKS managed node group definitions"
type = map(object({
instance_types = list(string)
min_size = number
max_size = number
desired_size = number
disk_size = optional(number, 100)
disk_type = optional(string, "gp3")
capacity_type = optional(string, "ON_DEMAND")
labels = optional(map(string), {})
taints = optional(list(object({
key = string
value = string
effect = string
})), [])
}))
default = {}
}
variable "database_password" {
description = "Database master password"
type = string
sensitive = true
validation {
condition = length(var.database_password) >= 16
error_message = "Database password must be at least 16 characters."
}
}
variable "tags" {
description = "Additional tags to apply to all resources"
type = map(string)
default = {}
}
output "id" {
description = "The ID of the primary resource"
value = aws_resource.this.id
}
output "arn" {
description = "The ARN of the primary resource"
value = aws_resource.this.arn
}
output "endpoint" {
description = "Endpoint for connecting to the resource"
value = aws_resource.this.endpoint
}
output "security_group_id" {
description = "ID of the associated security group"
value = aws_security_group.this.id
}
output "connection_string" {
description = "Database connection string"
value = "postgres://${var.username}:${random_password.db.result}@${aws_db_instance.this.endpoint}/${var.database_name}"
sensitive = true
}
output "cluster_endpoint" {
description = "EKS cluster endpoint (null if cluster not created)"
value = var.create_cluster ? module.eks[0].cluster_endpoint : null
}
output "private_subnets" {
description = "List of private subnet IDs"
value = var.create_vpc ? module.vpc[0].private_subnets : var.private_subnet_ids
}
locals {
name_prefix = "${var.project}-${var.environment}"
resource_names = {
cluster = "${local.name_prefix}-eks"
vpc = "${local.name_prefix}-vpc"
rds = "${local.name_prefix}-db"
}
}
locals {
default_tags = {
Project = var.project
Environment = var.environment
Terraform = "true"
Module = "module-name"
}
tags = merge(local.default_tags, var.tags)
}
locals {
node_group_defaults = {
instance_types = ["m6i.large", "m5.large"]
disk_size = 100
disk_type = "gp3"
capacity_type = "ON_DEMAND"
}
node_groups = {
for k, v in var.node_groups : k => merge(local.node_group_defaults, v)
}
}
locals {
create_kms_key = var.kms_key_arn == null
kms_key_arn = local.create_kms_key ? aws_kms_key.this[0].arn : var.kms_key_arn
azs = var.azs != null ? var.azs : slice(data.aws_availability_zones.available.names, 0, 3)
}
resource "aws_kms_key" "this" {
count = var.create_kms_key ? 1 : 0
description = "KMS key for ${local.name_prefix}"
deletion_window_in_days = 7
enable_key_rotation = true
tags = local.tags
}
resource "aws_subnet" "private" {
for_each = var.private_subnets
vpc_id = aws_vpc.this.id
availability_zone = each.value.az
cidr_block = each.value.cidr
tags = merge(local.tags, {
Name = "${local.name_prefix}-private-${each.key}"
Type = "private"
})
}
resource "aws_rds_cluster" "this" {
cluster_identifier = local.resource_names.rds
# ... configuration ...
lifecycle {
prevent_destroy = true
ignore_changes = [master_password]
}
}
resource "aws_eks_cluster" "this" {
name = local.resource_names.cluster
# ... configuration ...
timeouts {
create = "45m"
update = "60m"
delete = "30m"
}
}
# tests/basic.tftest.hcl
provider "aws" {
region = "us-east-1"
}
variables {
project = "test"
environment = "dev"
}
run "validate_resources" {
command = plan
assert {
condition = aws_s3_bucket.this.bucket != null
error_message = "S3 bucket should be created"
}
assert {
condition = aws_s3_bucket.this.tags["Environment"] == "dev"
error_message = "Environment tag should be 'dev'"
}
}
run "validate_naming" {
command = plan
assert {
condition = can(regex("^test-dev-", aws_s3_bucket.this.bucket))
error_message = "Bucket name should follow naming convention"
}
}
run "validate_encryption" {
command = plan
variables {
enable_encryption = true
}
assert {
condition = length(aws_s3_bucket_server_side_encryption_configuration.this) > 0
error_message = "Encryption should be enabled"
}
}
# Module Name
Brief description of what this module creates.
## Usage
```hcl
module "example" {
source = "path/to/module"
project = "myapp"
environment = "prod"
# Additional configuration
}
| Name | Version |
|---|---|
| terraform | >= 1.5.0 |
| aws | >= 5.0 |
| Name | Version |
|---|---|
| aws | >= 5.0 |
| Name | Type |
|---|---|
| aws_resource.name | resource |
| aws_data.name | data source |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| project | Project name | string | n/a | yes |
| environment | Environment | string | n/a | yes |
| tags | Additional tags | map(string) | {} | no |
| Name | Description |
|---|---|
| id | Resource ID |
| arn | Resource ARN |
Apache 2.0 Licensed.
## Example basic/main.tf
```hcl
provider "aws" {
region = "us-east-1"
}
module "example" {
source = "../../"
project = "myapp"
environment = "dev"
}
output "id" {
value = module.example.id
}
# moves.tf - Use when renaming resources
moved {
from = aws_instance.web
to = aws_instance.application
}
moved {
from = aws_s3_bucket.data
to = module.storage.aws_s3_bucket.main
}
moved {
from = module.old_name
to = module.new_name
}
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.