Skip to content
Skill · Generic.mdCoding

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.

@libraryNewcomer
0 upvotes0 forks0 comments

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 repo

Save this to your project or home directory so Generic can load it.

path.md
Discussion

What people are saying

Forks

0 forks of this skill
Loading forks…