Terraform and IaC Rules for Agents
Guardrails for agents touching Terraform: always plan before apply, module and state layout, what never to do to state files, and mandatory resource tagging.
Use when: Use in any repository containing Terraform when agents write or modify infrastructure code, so changes are planned and reviewed before apply and state is never put at risk.
The skill file
Generic · .md.md3591 chars
# Terraform Conventions
Infrastructure changes are higher-stakes than application code: a wrong apply can delete data or take down production. Follow these rules without exception.
## Plan before apply — always
- Never run `terraform apply` without first running `terraform plan -out=tfplan` and reading the full plan output. Apply the saved plan (`terraform apply tfplan`), not a fresh one.
- Summarize the plan before applying: count of resources to add / change / destroy, and call out every **destroy** and every **replacement** (`-/+`) explicitly. Replacements of stateful resources (databases, volumes, buckets) require human confirmation — stop and ask.
- If the plan shows changes you did not make, stop. Someone or something has drifted the environment; investigate before layering your change on top.
- `terraform apply -auto-approve` is permitted only in CI pipelines that gate on a reviewed plan, never interactively.
- Run `terraform fmt -recursive` and `terraform validate` before every commit; CI also runs `tflint` and a policy check — fix findings, do not suppress them.
## Layout
```
modules/<name>/ # reusable building blocks: main.tf, variables.tf, outputs.tf, README.md
envs/dev/ # one root module per environment
envs/staging/
envs/prod/ # each env has its own backend config and tfvars
```
- Environments are separate root modules with **separate state** — never a single workspace switched with `terraform workspace` for prod vs dev, and never an `environment` variable that swaps behavior inside one state.
- Modules take explicit `variables.tf` inputs (typed, described, with `validation` blocks where cheap) and expose explicit `outputs.tf`. No module reaches into another module's resources.
- Pin versions: `required_version` for Terraform, version constraints for every provider, and a version/ref on every module source (`?ref=v1.4.0` for git sources). Renovate-style bumps come as their own PRs.
- No `provisioner` blocks and no `local-exec` escape hatches without sign-off — they are unmanaged side effects.
## State safety
- State lives in the remote backend with locking enabled. Never commit `.tfstate`, never copy state files around, never edit state JSON by hand.
- State surgery (`terraform state mv`, `state rm`, `import`) is a last resort: announce what you intend to run and why, get confirmation, and run `terraform plan` immediately afterwards to prove the result is a no-op.
- Renaming a resource in code? Use a `moved {}` block so Terraform tracks it, instead of letting it plan a destroy-and-create.
- Protect stateful resources with `lifecycle { prevent_destroy = true }` and deletion protection flags on the resource itself where the provider supports it.
- Secrets do not belong in state when avoidable: reference them from <your-secret-manager> via data sources instead of generating/storing them as plain resource attributes. Treat state itself as sensitive regardless.
## Tagging standard
Every taggable resource carries these tags (enforce via `default_tags` on the provider where supported, per-resource otherwise):
```hcl
tags = {
environment = var.environment # dev | staging | prod
service = "<service-name>"
owner = "<team-or-handle>"
managed-by = "terraform"
repo = "<org>/<repo>"
}
```
- `managed-by = "terraform"` is how humans know not to click-edit a resource in the console. Anything missing it is presumed unmanaged.
- Cost-allocation reports key on `service` and `environment`; an untagged resource is a billing mystery — do not create them.
Install
drop into your repoSave this to your project or home directory so Generic can load it.
path.md
Discussion
What people are saying
Forks
0 forks of this skillLoading forks…