Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Define and manage cloud infrastructure with code. Use when writing Terraform, CloudFormation, or Pulumi configs, managing state, planning deployments, setting up networking/compute/storage resources, or debugging infrastructure drift.
.claude/skills/leoyeai-infra-as-code/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 150% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 1093% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 135% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 260% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 586% | 0% |
Define, deploy, and manage cloud infrastructure using declarative configuration. Covers Terraform (multi-cloud), AWS CloudFormation, and Pulumi (code-first), with patterns for compute, networking, storage, databases, and state management.
bash# Install: https://developer.hashicorp.com/terraform/install # Initialize a project mkdir infra && cd infra terraform init # Core workflow terraform plan # Preview changes (safe, read-only) terraform apply # Apply changes (creates/modifies resources) terraform destroy # Tear down all resources # Format and validate terraform fmt -recursive # Auto-format all .tf files terraform validate # Check syntax and config validity
infra/
main.tf # Primary resources
variables.tf # Input variable declarations
outputs.tf # Output values
providers.tf # Provider configuration
terraform.tfvars # Variable values (don't commit secrets)
backend.tf # Remote state configuration
modules/
vpc/
main.tf
variables.tf
outputs.tf
compute/
main.tf
variables.tf
outputs.tfhcl# providers.tf terraform { required_version = ">= 1.5" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = var.aws_region default_tags { tags = { Project = var.project_name Environment = var.environment ManagedBy = "terraform" } } }
hcl# variables.tf variable "aws_region" { type = string default = "us-east-1" description = "AWS region for all resources" } variable "environment" { type = string description = "Deployment environment" validation { condition = contains(["dev", "staging", "prod"], var.environment) error_message = "Environment must be dev, staging, or prod." } } variable "instance_type" { type = string default = "t3.micro" } variable "db_password" { type = string sensitive = true description = "Database password (pass via TF_VAR_db_password env var)" } # outputs.tf output "vpc_id" { value = aws_vpc.main.id description = "VPC ID" } output "api_endpoint" { value = aws_lb.api.dns_name }
hcl# Networking module resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "${var.project_name}-vpc" } } resource "aws_subnet" "public" { count = 2 vpc_id = aws_vpc.main.id cidr_block = "10.0.${count.index + 1}.0/24" availability_zone = data.aws_availability_zones.available.names[count.index] map_public_ip_on_launch = true tags = { Name = "${var.project_name}-public-${count.index + 1}" } } resource "aws_subnet" "private" { count = 2 vpc_id = aws_vpc.main.id cidr_block = "10.0.${count.index + 10}.0/24" availability_zone = data.aws_availability_zones.available.names[count.index] tags = { Name = "${var.project_name}-private-${count.index + 1}" } } resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id } resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.main.id } } resource "aws_route_table_association" "public" { count = 2 subnet_id = aws_subnet.public[count.index].id route_table_id = aws_route_table.public.id } resource "aws_security_group" "web" { name_prefix = "${var.project_name}-web-" vpc_id = aws_vpc.main.id ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } data "aws_availability_zones" "available" { state = "available" }
hclresource "aws_instance" "app" { ami = data.aws_ami.ubuntu.id instance_type = var.instance_type subnet_id = aws_subnet.public[0].id vpc_security_group_ids = [aws_security_group.web.id] key_name = var.key_pair_name user_data = <<-EOF #!/bin/bash apt-get update apt-get install -y docker.io systemctl start docker docker run -d -p 80:8080 ${var.docker_image} EOF tags = { Name = "${var.project_name}-app" } } data "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-*-24.04-amd64-server-*"] } }
hclresource "aws_s3_bucket" "website" { bucket = "${var.project_name}-website" } resource "aws_s3_bucket_website_configuration" "website" { bucket = aws_s3_bucket.website.id index_document { suffix = "index.html" } error_document { key = "error.html" } } resource "aws_s3_bucket_public_access_block" "website" { bucket = aws_s3_bucket.website.id block_public_acls = false block_public_policy = false ignore_public_acls = false restrict_public_buckets = false } resource "aws_s3_bucket_policy" "website" { bucket = aws_s3_bucket.website.id policy = jsonencode({ Version = "2012-10-17" Statement = [{ Sid = "PublicRead" Effect = "Allow" Principal = "*" Action = "s3:GetObject" Resource = "${aws_s3_bucket.website.arn}/*" }] }) depends_on = [aws_s3_bucket_public_access_block.website] }
hclresource "aws_db_subnet_group" "main" { name = "${var.project_name}-db" subnet_ids = aws_subnet.private[*].id } resource "aws_security_group" "db" { name_prefix = "${var.project_name}-db-" vpc_id = aws_vpc.main.id ingress { from_port = 5432 to_port = 5432 protocol = "tcp" security_groups = [aws_security_group.web.id] } } resource "aws_db_instance" "main" { identifier = "${var.project_name}-db" engine = "postgres" engine_version = "16.1" instance_class = "db.t3.micro" allocated_storage = 20 db_name = var.db_name username = var.db_username password = var.db_password db_subnet_group_name = aws_db_subnet_group.main.name vpc_security_group_ids = [aws_security_group.db.id] backup_retention_period = 7 skip_final_snapshot = var.environment != "prod" deletion_protection = var.environment == "prod" }
hcldata "archive_file" "lambda_zip" { type = "zip" source_dir = "${path.module}/lambda" output_path = "${path.module}/lambda.zip" } resource "aws_lambda_function" "api" { function_name = "${var.project_name}-api" filename = data.archive_file.lambda_zip.output_path source_code_hash = data.archive_file.lambda_zip.output_base64sha256 handler = "index.handler" runtime = "nodejs20.x" timeout = 30 role = aws_iam_role.lambda_exec.arn environment { variables = { DB_HOST = aws_db_instance.main.endpoint ENVIRONMENT = var.environment } } } resource "aws_iam_role" "lambda_exec" { name = "${var.project_name}-lambda-exec" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } }] }) } resource "aws_iam_role_policy_attachment" "lambda_basic" { role = aws_iam_role.lambda_exec.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" }
hcl# backend.tf - Remote state in S3 terraform { backend "s3" { bucket = "my-terraform-state" key = "project/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } }
bash# State operations terraform state list # List all resources in state terraform state show aws_instance.app # Show resource details terraform state mv aws_instance.app aws_instance.web # Rename resource terraform state rm aws_instance.old # Remove from state (doesn't destroy) # Import existing resource into Terraform terraform import aws_instance.app i-1234567890abcdef0 # Workspaces (multiple environments, same config) terraform workspace new dev terraform workspace new staging terraform workspace new prod terraform workspace select dev terraform workspace list
hcl# Use workspaces + tfvars files # terraform.tfvars (default) # env/dev.tfvars # env/staging.tfvars # env/prod.tfvars # Apply for specific environment # terraform apply -var-file=env/prod.tfvars
bash# Environment-specific apply ENV=${1:-dev} terraform workspace select "$ENV" || terraform workspace new "$ENV" terraform apply -var-file="env/$ENV.tfvars"
yaml# cloudformation.yaml AWSTemplateFormatVersion: '2010-09-09' Description: My application stack Parameters: Environment: Type: String AllowedValues: [dev, staging, prod] Default: dev InstanceType: Type: String Default: t3.micro Conditions: IsProd: !Equals [!Ref Environment, prod] Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub "${AWS::StackName}-vpc" PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub "${AWS::StackName}-public" AppInstance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType SubnetId: !Ref PublicSubnet ImageId: !FindInMap [RegionAMI, !Ref "AWS::Region", ubuntu] Database: Type: AWS::RDS::DBInstance Condition: IsProd DeletionPolicy: Snapshot Properties: Engine: postgres DBInstanceClass: db.t3.micro AllocatedStorage: 20 MasterUsername: admin MasterUserPassword: !Ref DBPassword Outputs: VpcId: Value: !Ref VPC Export: Name: !Sub "${AWS::StackName}-VpcId" InstanceIP: Value: !GetAtt AppInstance.PublicIp
bash# Validate template aws cloudformation validate-template --template-body file://cloudformation.yaml # Create stack aws cloudformation create-stack \ --stack-name myapp-dev \ --template-body file://cloudformation.yaml \ --parameters ParameterKey=Environment,ParameterValue=dev \ --capabilities CAPABILITY_IAM # Update stack aws cloudformation update-stack \ --stack-name myapp-dev \ --template-body file://cloudformation.yaml \ --parameters ParameterKey=Environment,ParameterValue=dev # Preview changes (changeset) aws cloudformation create-change-set \ --stack-name myapp-dev \ --change-set-name update-1 \ --template-body file://cloudformation.yaml aws cloudformation describe-change-set \ --stack-name myapp-dev \ --change-set-name update-1 # Delete stack aws cloudformation delete-stack --stack-name myapp-dev # List stacks aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE # Stack events (debugging) aws cloudformation describe-stack-events --stack-name myapp-dev | head -50
bash# Install: https://www.pulumi.com/docs/install/ pulumi new aws-typescript # Core workflow pulumi preview # Preview changes pulumi up # Apply changes pulumi destroy # Tear down pulumi stack ls # List stacks
typescript// index.ts import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; const config = new pulumi.Config(); const environment = config.require("environment"); // VPC const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16", enableDnsSupport: true, enableDnsHostnames: true, tags: { Name: `myapp-${environment}-vpc` }, }); // Public subnet const publicSubnet = new aws.ec2.Subnet("public", { vpcId: vpc.id, cidrBlock: "10.0.1.0/24", mapPublicIpOnLaunch: true, tags: { Name: `myapp-${environment}-public` }, }); // S3 bucket const bucket = new aws.s3.Bucket("data", { bucket: `myapp-${environment}-data`, versioning: { enabled: true }, }); // Lambda function const lambdaRole = new aws.iam.Role("lambda-role", { assumeRolePolicy: JSON.stringify({ Version: "2012-10-17", Statement: [{ Action: "sts:AssumeRole", Effect: "Allow", Principal: { Service: "lambda.amazonaws.com" }, }], }), }); const lambdaFunc = new aws.lambda.Function("api", { runtime: "nodejs20.x", handler: "index.handler", role: lambdaRole.arn, code: new pulumi.asset.FileArchive("./lambda"), environment: { variables: { BUCKET_NAME: bucket.id, ENVIRONMENT: environment, }, }, }); // Outputs export const vpcId = vpc.id; export const bucketName = bucket.id; export const lambdaArn = lambdaFunc.arn;
python# __main__.py import pulumi import pulumi_aws as aws config = pulumi.Config() environment = config.require("environment") vpc = aws.ec2.Vpc("main", cidr_block="10.0.0.0/16", enable_dns_support=True, enable_dns_hostnames=True, tags={"Name": f"myapp-{environment}-vpc"}) bucket = aws.s3.Bucket("data", bucket=f"myapp-{environment}-data", versioning=aws.s3.BucketVersioningArgs(enabled=True)) pulumi.export("vpc_id", vpc.id) pulumi.export("bucket_name", bucket.id)
bash# Create per-environment stacks pulumi stack init dev pulumi stack init staging pulumi stack init prod # Switch stack pulumi stack select dev # Set config per stack pulumi config set environment dev pulumi config set aws:region us-east-1 pulumi config set --secret dbPassword 'my-secret-pass' # Stack references (cross-stack) # In consuming stack: const infra = new pulumi.StackReference("org/infra/prod"); const vpcId = infra.getOutput("vpcId");
bash# Detailed plan output terraform plan -out=plan.tfplan terraform show plan.tfplan terraform show -json plan.tfplan | jq '.resource_changes[] | {address, change: .change.actions}' # Debug mode TF_LOG=DEBUG terraform plan 2> debug.log # Check for drift terraform plan -refresh-only # Force refresh state terraform apply -refresh-only
bash# Resource stuck in "tainted" state terraform untaint aws_instance.app # State locked (another apply running or crashed) terraform force-unlock LOCK_ID # Provider version conflict terraform providers lock # Generate lock file terraform init -upgrade # Upgrade providers # Circular dependency # Error: "Cycle" in terraform plan # Fix: use depends_on explicitly, or break the cycle with data sources
bash# Infracost (estimates monthly cost from Terraform plans) # Install: https://www.infracost.io/docs/ infracost breakdown --path . infracost diff --path . --compare-to infracost-base.json
terraform plan before apply. Read the plan output carefully — especially lines showing destroy or replace..tf files or terraform.tfvars. Use environment variables (TF_VAR_name), secrets managers, or Vault.prevent_destroy lifecycle rules on stateful resources (databases, S3 buckets with data) to prevent accidental deletion.~> 5.0 not >= 5.0) to avoid surprise breaking changes.terraform plan — always create one before updating a stack.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-06 | pass→pass | 2,368 | 2,086 | -12% | 1 | 1 | 0% | 471 | 5,617 | +1093% | 0 | 0 | — |
case-01 | pass→pass | 15,828 | 12,566 | -21% | 1 | 1 | 0% | 3,397 | 7,978 | +135% | 0 | 0 | — |
case-02 | pass→pass | 9,525 | 7,415 | -22% | 1 | 1 | 0% | 1,895 | 6,815 | +260% | 0 | 0 | — |
case-03 | fail→pass | 16,129 | 52,617 | +226% | 1 | 1 | 0% | 3,424 | 8,570 | +150% | 0 | 0 | — |
case-04 | pass→pass | 39,094 | 43,639 | +12% | 1 | 1 | 0% | 884 | 6,062 | +586% | 0 | 0 | — |
case-05 | pass→pass | 2,368 | 2,528 | +7% | 1 | 1 | 0% | 413 | 5,697 | +1279% | 0 | 0 | — |
case-07 | pass→pass | 3,098 | 4,767 | +54% | 1 | 1 | 0% | 604 | 5,620 | +830% | 0 | 0 | — |
case-08 | pass→pass | 5,306 | 5,402 | +2% | 1 | 1 | 0% | 1,117 | 6,485 | +481% | 0 | 0 | — |
case-09 | pass→pass | 5,162 | 3,577 | -31% | 1 | 1 | 0% | 1,127 | 5,974 | +430% | 0 | 0 | — |
case-10 | pass→pass | 5,340 | 3,768 | -29% | 1 | 1 | 0% | 1,108 | 6,064 | +447% | 0 | 0 | — |
case-11 | pass→pass | 4,680 | 18,419 | +294% | 1 | 1 | 0% | 1,039 | 6,175 | +494% | 0 | 0 | — |
case-12 | pass→pass | 3,050 | 3,934 | +29% | 1 | 1 | 0% | 634 | 5,990 | +845% | 0 | 0 | — |
case-13 | pass→pass | 3,441 | 4,405 | +28% | 1 | 1 | 0% | 605 | 6,070 | +903% | 0 | 0 | — |
case-14 | pass→pass | 2,850 | 2,866 | +1% | 1 | 1 | 0% | 555 | 5,804 | +946% | 0 | 0 | — |
case-15 | pass→pass | 5,388 | 4,801 | -11% | 1 | 1 | 0% | 1,155 | 6,163 | +434% | 0 | 0 | — |
case-16 | pass→pass | 5,422 | 3,963 | -27% | 1 | 1 | 0% | 1,061 | 5,933 | +459% | 0 | 0 | — |
case-17 | pass→pass | 2,853 | 3,112 | +9% | 1 | 1 | 0% | 524 | 5,760 | +999% | 0 | 0 | — |
case-18 | pass→pass | 2,099 | 2,245 | +7% | 1 | 1 | 0% | 389 | 5,613 | +1343% | 0 | 0 | — |
case-19 | pass→pass | 2,176 | 7,196 | +231% | 1 | 1 | 0% | 354 | 5,564 | +1472% | 0 | 0 | — |
case-20 | pass→pass | 3,486 | 3,778 | +8% | 1 | 1 | 0% | 739 | 5,997 | +712% | 0 | 0 | — |
case-21 | pass→pass | 4,461 | 3,583 | -20% | 1 | 1 | 0% | 871 | 5,971 | +586% | 0 | 0 | — |
case-22 | pass→pass | 4,991 | 4,404 | -12% | 1 | 1 | 0% | 971 | 6,049 | +523% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.