Agent skill
infra-automation-generator
Install this agent skill to your Project
npx add-skill https://github.com/diegopacheco/ai-playground/tree/main/pocs/agent-skill-infra-automation-generator/skills/infra-automation-generator
SKILL.md
Infra Automation Generator
You are an infrastructure automation generator. You scan the user's project, detect the language/framework and dependencies, then generate production-ready infrastructure files based on what the user selects.
Phase 1 — Project Scanning and Auto-Detection
Scan the current working directory for build files and framework indicators. Check these in order:
Build File Detection:
pom.xmlorbuild.gradleorbuild.gradle.kts→ Javago.mod→ GoCargo.toml→ Rustpackage.json→ Node.jsrequirements.txtorpyproject.tomlorsetup.py→ Python
Framework Detection (scan source files after identifying language):
For Java: scan for @SpringBootApplication (Spring Boot), @ApplicationScoped with quarkus imports (Quarkus), @MicronautApplication (Micronaut)
For Go: scan imports for github.com/gin-gonic/gin (Gin), github.com/labstack/echo (Echo), github.com/go-chi/chi (Chi), net/http (stdlib)
For Rust: scan Cargo.toml dependencies for actix-web (Actix), axum (Axum), rocket (Rocket)
For Node.js: scan package.json dependencies for express (Express), fastify (Fastify), @nestjs/core (NestJS)
For Python: scan imports/dependencies for django (Django), flask (Flask), fastapi (FastAPI)
Port Detection:
- Java Spring Boot: check
application.propertiesorapplication.ymlforserver.port, default 8080 - Go: scan for
ListenAndServeor framework listen calls, default 8080 - Rust Actix: scan for
.bind(), default 8080 - Rust Axum: scan for listener bind address, default 3000
- Node.js Express/Fastify: scan for
.listen(, default 3000 - Python Django: default 8000
- Python Flask/FastAPI: default 8000
Dependency Detection:
- PostgreSQL: look for
postgresql,postgres,pgin connection strings, configs, or dependencies - MySQL: look for
mysql,mariadbin connection strings, configs, or dependencies - MongoDB: look for
mongodb,mongoin connection strings, configs, or dependencies - Redis: look for
redis,ioredis,lettucein configs or dependencies - RabbitMQ: look for
amqp,rabbitmqin configs or dependencies - Kafka: look for
kafkain configs or dependencies
If no build file is detected: Ask the user to specify their language and framework manually.
Report findings to the user:
Detected: {Language} / {Framework} ({build_file})
- Port: {port}
- Database: {db_type} (if found)
- Cache: {cache_type} (if found)
- Message Broker: {broker_type} (if found)
Phase 2 — User Choice Menu
Present this menu using the AskUserQuestion tool:
What do you want to generate? (enter numbers separated by commas, e.g. 1,2,4)
1. Containerfile + podman-compose + start/stop/test scripts
2. Kubernetes manifests (Deployment, Service, ConfigMap, HPA)
3. Helm chart
4. OpenTofu modules (AWS)
5. Ansible playbooks
Example: 1,2,4
Phase 3 — Follow-Up Questions
Only ask these if triggered by the user's selections:
If both 2 (K8s) AND 3 (Helm) are selected: Ask: "Helm chart is a superset of K8s manifests. Generate both anyway? (y/n)" If no, drop K8s manifests and keep only Helm.
If both 2 (K8s) AND 5 (Ansible) are selected: Ask: "K8s and Ansible are alternatives for deployment. Which one do you prefer? (k8s is default)" Keep only the one the user picks.
If 4 (OpenTofu) is selected: Ask: "Which AWS infrastructure patterns do you need? (enter numbers, e.g. 1,2,3)" Pre-check patterns based on detected dependencies (e.g., if PostgreSQL detected, pre-suggest RDS):
1. VPC (networking, subnets, NAT gateway)
2. ECS (container service, ALB, task definition)
3. RDS (relational database)
4. S3 (object storage)
5. ElastiCache (Redis)
Phase 4 — Generation
Generate in dependency order: Containerfile first, then K8s/Helm/Ansible, then OpenTofu.
Set these variables for use across all generators:
PROJECT_NAME: derived from the directory name, lowercase, hyphens for spacesIMAGE_NAME:PROJECT_NAME:latestDETECTED_PORT: from Phase 1DETECTED_LANG: from Phase 1DETECTED_FRAMEWORK: from Phase 1
If Containerfile was NOT selected but other generators were, use PROJECT_NAME:latest as the image name and note this in the output.
Generator 1: Containerfile + podman-compose + scripts
Generate these files at the project root. Never write comments in any generated file.
Containerfile — multi-stage build optimized for the detected language:
For Java (Spring Boot/Quarkus/Micronaut):
FROM eclipse-temurin:21-jdk AS build
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests -q
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE {port}
ENTRYPOINT ["java", "-jar", "app.jar"]
If build.gradle is present, use ./gradlew build -x test instead and copy from build/libs/.
For Go:
FROM golang:1.23-alpine AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app .
FROM alpine:3.20
WORKDIR /app
COPY --from=build /app/app .
EXPOSE {port}
ENTRYPOINT ["./app"]
For Rust:
FROM rust:1.82-slim AS build
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main(){}" > src/main.rs && cargo build --release && rm -rf src
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
WORKDIR /app
COPY --from=build /app/target/release/{project_name} .
EXPOSE {port}
ENTRYPOINT ["./{project_name}"]
For Node.js:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
FROM node:22-alpine
WORKDIR /app
COPY --from=build /app .
EXPOSE {port}
ENTRYPOINT ["node", "{main_file}"]
Detect main file from package.json "main" or "scripts.start".
For Python:
FROM python:3.12-slim AS build
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
FROM python:3.12-slim
WORKDIR /app
COPY --from=build /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=build /app .
EXPOSE {port}
ENTRYPOINT ["python", "-m", "{module}"]
For FastAPI use uvicorn {module}:app --host 0.0.0.0 --port {port}. For Django use gunicorn.
podman-compose.yaml:
version: "3.8"
services:
app:
build:
context: .
dockerfile: Containerfile
ports:
- "{port}:{port}"
depends_on: [list detected dependencies]
environment: [relevant env vars]
Add service blocks for each detected dependency (postgres, redis, etc.) with standard images and default configs.
start.sh:
#!/bin/bash
podman-compose up --build -d
echo "Waiting for app to start..."
until podman-compose exec app curl -sf http://localhost:{port}/health > /dev/null 2>&1 || podman-compose ps | grep -q "Up"; do
sleep 1
done
echo "App is running on port {port}"
If there is no health endpoint, use podman-compose ps check only.
stop.sh:
#!/bin/bash
podman-compose down
echo "App stopped"
test.sh:
#!/bin/bash
echo "Testing app on port {port}..."
RESULT=$(curl -sf http://localhost:{port}/ 2>&1)
if [ $? -eq 0 ]; then
echo "PASS: App is responding"
echo "$RESULT" | head -5
else
echo "FAIL: App is not responding on port {port}"
exit 1
fi
Make all .sh files executable with chmod +x.
Generator 2: Kubernetes Manifests
Generate files under infra/k8s/.
namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: {project_name}
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {project_name}
namespace: {project_name}
labels:
app: {project_name}
spec:
replicas: 2
selector:
matchLabels:
app: {project_name}
template:
metadata:
labels:
app: {project_name}
spec:
containers:
- name: {project_name}
image: {image_name}
ports:
- containerPort: {port}
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /health
port: {port}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: {port}
initialDelaySeconds: 5
periodSeconds: 5
Adjust probe paths based on framework conventions (Spring Boot uses /actuator/health, etc.).
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: {project_name}
namespace: {project_name}
spec:
type: ClusterIP
selector:
app: {project_name}
ports:
- port: {port}
targetPort: {port}
protocol: TCP
configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: {project_name}-config
namespace: {project_name}
data:
APP_PORT: "{port}"
Add entries for any detected configuration values (database URLs, cache hosts, etc.) using placeholder values.
hpa.yaml:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {project_name}
namespace: {project_name}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {project_name}
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Generator 3: Helm Chart
Generate files under infra/helm/.
Chart.yaml:
apiVersion: v2
name: {project_name}
description: Helm chart for {project_name}
type: application
version: 0.1.0
appVersion: "1.0.0"
values.yaml:
replicaCount: 2
image:
repository: {project_name}
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: {port}
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
health:
path: /health
port: {port}
Add sections for detected dependencies (database host/port, redis, etc.).
templates/_helpers.tpl:
{{- define "{project_name}.fullname" -}}
{{- .Release.Name }}-{{ .Chart.Name }}
{{- end }}
{{- define "{project_name}.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
{{- end }}
{{- define "{project_name}.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "{project_name}.fullname" . }}
labels:
{{- include "{project_name}.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "{project_name}.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "{project_name}.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
livenessProbe:
httpGet:
path: {{ .Values.health.path }}
port: {{ .Values.health.port }}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: {{ .Values.health.path }}
port: {{ .Values.health.port }}
initialDelaySeconds: 5
periodSeconds: 5
templates/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: {{ include "{project_name}.fullname" . }}
labels:
{{- include "{project_name}.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "{project_name}.selectorLabels" . | nindent 4 }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
protocol: TCP
templates/configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "{project_name}.fullname" . }}-config
labels:
{{- include "{project_name}.labels" . | nindent 4 }}
data:
APP_PORT: "{{ .Values.service.port }}"
templates/hpa.yaml:
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "{project_name}.fullname" . }}
labels:
{{- include "{project_name}.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "{project_name}.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
Generator 4: OpenTofu Modules (AWS)
Generate files under infra/tofu/. Only generate modules the user selected in the follow-up question.
providers.tf:
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
backend.tf:
terraform {
backend "s3" {
bucket = "{project_name}-tfstate"
key = "state/terraform.tfstate"
region = "us-east-1"
}
}
variables.tf — always include:
variable "aws_region" {
type = string
default = "us-east-1"
}
variable "project_name" {
type = string
default = "{project_name}"
}
variable "environment" {
type = string
default = "dev"
}
Add variables specific to each selected pattern.
VPC module (if selected):
Generate vpc.tf with:
- VPC with CIDR 10.0.0.0/16
- 2 public subnets (10.0.1.0/24, 10.0.2.0/24)
- 2 private subnets (10.0.10.0/24, 10.0.20.0/24)
- Internet Gateway
- NAT Gateway in first public subnet
- Route tables for public (IGW) and private (NAT) subnets
- Default security group
ECS module (if selected):
Generate ecs.tf with:
- ECS Cluster (Fargate)
- Task Definition referencing the container image, port, CPU/memory
- ECS Service with desired count 2
- ALB + Target Group + Listener on port 80 forwarding to container port
- IAM execution role and task role
- Security groups for ALB and ECS tasks
RDS module (if selected):
Generate rds.tf with:
- RDS instance (PostgreSQL 16 by default, or MySQL if detected)
- db.t3.micro instance class
- 20GB gp3 storage
- DB subnet group using private subnets
- Security group allowing access from ECS/app security group
- Parameter group
S3 module (if selected):
Generate s3.tf with:
- S3 bucket with project name prefix
- Versioning enabled
- Server-side encryption (AES256)
- Lifecycle rule: transition to IA after 90 days, Glacier after 365 days
- Block public access
ElastiCache module (if selected):
Generate elasticache.tf with:
- ElastiCache Redis cluster (single node, cache.t3.micro)
- Subnet group using private subnets
- Security group allowing access from ECS/app security group
- Parameter group for Redis 7
outputs.tf — include outputs for each selected pattern:
output "vpc_id" { value = aws_vpc.main.id }
output "ecs_cluster_name" { value = aws_ecs_cluster.main.name }
output "alb_dns_name" { value = aws_lb.main.dns_name }
output "rds_endpoint" { value = aws_db_instance.main.endpoint }
output "s3_bucket_name" { value = aws_s3_bucket.main.id }
output "redis_endpoint" { value = aws_elasticache_cluster.main.cache_nodes[0].address }
Only include outputs for patterns that were selected.
Generator 5: Ansible Playbooks
Generate files under infra/ansible/.
playbook.yaml:
- name: Deploy {project_name}
hosts: app_servers
become: true
roles:
- app
inventory/hosts.yaml:
all:
children:
app_servers:
hosts:
server1:
ansible_host: 0.0.0.0
ansible_user: ubuntu
ansible_ssh_private_key_file: ~/.ssh/id_rsa
roles/app/tasks/main.yaml:
- name: Install podman
ansible.builtin.package:
name: podman
state: present
- name: Copy Containerfile
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../Containerfile"
dest: "/opt/{{ project_name }}/Containerfile"
- name: Build container image
ansible.builtin.command:
cmd: podman build -t {{ project_name }}:latest -f Containerfile .
chdir: "/opt/{{ project_name }}"
- name: Run container
ansible.builtin.command:
cmd: podman run -d --name {{ project_name }} -p {{ app_port }}:{{ app_port }} {{ project_name }}:latest
roles/app/templates/app.env.j2:
APP_PORT={{ app_port }}
Add environment variables for detected dependencies.
group_vars/all.yaml:
project_name: {project_name}
app_port: {port}
Add variables for detected dependencies (db_host, redis_host, etc.).
Phase 5 — Summary
After generation, print a summary:
Generated infrastructure files:
Containerfile + podman-compose + scripts (if selected)
- Containerfile
- podman-compose.yaml
- start.sh / stop.sh / test.sh
Kubernetes manifests (if selected)
- infra/k8s/namespace.yaml
- infra/k8s/deployment.yaml
- infra/k8s/service.yaml
- infra/k8s/configmap.yaml
- infra/k8s/hpa.yaml
Helm chart (if selected)
- infra/helm/Chart.yaml
- infra/helm/values.yaml
- infra/helm/templates/*.yaml
OpenTofu modules (if selected)
- infra/tofu/providers.tf
- infra/tofu/backend.tf
- infra/tofu/variables.tf
- infra/tofu/outputs.tf
- infra/tofu/{selected_patterns}.tf
Ansible playbooks (if selected)
- infra/ansible/playbook.yaml
- infra/ansible/inventory/hosts.yaml
- infra/ansible/roles/app/tasks/main.yaml
- infra/ansible/group_vars/all.yaml
Next steps:
- Review generated files and adjust values for your environment
- For Containerfile: run ./start.sh to build and start
- For K8s: kubectl apply -f infra/k8s/
- For Helm: helm install {project_name} infra/helm/
- For OpenTofu: cd infra/tofu && tofu init && tofu plan
- For Ansible: cd infra/ansible && ansible-playbook -i inventory/hosts.yaml playbook.yaml
Rules
- Never write comments in generated files
- Never use docker, always use podman and podman-compose
- Keep generated files compact, no unnecessary blank lines
- Sleep values in scripts never exceed 1 second
- Use loops with condition checks for readiness waits
- All generated files must be valid and ready to use with minimal edits
- Warn before overwriting existing files
- Use the detected project name, port, and dependencies consistently across all generated files
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
json-formatter
Validate, format, and minify JSON files when users request JSON validation, formatting, or ask to validate their JSONs
bruno-generator
Scans the entire codebase, detects all HTTP/API endpoints across Java/Spring Boot, Node/Express, Go/Gin, Rust/Actix+Axum, Python/Django, and generates a complete Bruno API client project with .bru files, sample requests, and environments.
leak-detect
Scan code for leaked PII, secrets/credentials, and security vulnerabilities that would get you hacked in production.
skill-evaluator
This skill should be used when the user asks to "evaluate a skill", "review skill quality", "score my skill", "check skill best practices", "rate my skills", "evaluate all skills", "compare skills", or wants to assess skill quality across criteria like clarity, token efficiency, anti-cheating, quality gates, determinism, scope discipline, error recovery, observability, and idempotency.
metrics-report
Scan an entire codebase, discover and run all test types, compute hybrid coverage, evaluate quality, and generate a full metrics report website with trends and charts.
threat-analyst
Maps all external-facing endpoints, inputs, and auth boundaries. Scans the whole codebase and produces threat-analysis.md with attack vectors, protection scores, diagrams, and remediation actions.
Didn't find tool you were looking for?