plugin/skills/terraform-procedures/SKILL.md
Use this skill when authoring or running a Terraform plan/apply, refactoring modules, performing state surgery, importing existing cloud resources, or working in repos that use OpenTofu instead of HashiCorp Terraform — Terraform and OpenTofu procedures covering state operations (state list/show/mv/rm/pull/push), plan/apply lifecycle, OpenTofu fork compatibility, state-surgery safety warnings, and workspace handling. Loaded by `/infra-change` and other infrastructure workflows; not a workflow itself.
npx skillsauth add avav25/ai-assets terraform-proceduresInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Knowledge reference for Terraform/OpenTofu operations used by infrastructure-change workflows. Covers the plan/apply lifecycle, state-management commands, refactoring patterns, and fork-compatibility notes. Designed to be loaded as background context when a workflow encounters Terraform configs.
If .terraform-version or tofu.lock.hcl indicates OpenTofu (HashiCorp BSL fork, 2023+), substitute tofu for terraform in all commands below. Flag semantics are identical for the operations covered in this skill.
Other indicators of an OpenTofu repo:
tofu binary referenced in CI configs instead of terraform.tofu/ directory or tofu.tf filesterraform validate
terraform fmt -check -recursive
Modern pre-plan suite (run when configs are present):
tflint # if .tflint.hcl present
tfsec . --soft-fail # if tfsec.yml or .tfsec/ present
checkov -d . --soft-fail # if .checkov.yml present
terraform-docs markdown table . # regenerate docs if terraform-docs.yml present
terraform plan -out=tfplan -detailed-exitcode
# Exit codes:
# 0 = no changes
# 1 = error
# 2 = changes proposed
The -detailed-exitcode form is the standard oracle for iterative reconciliation loops (RALF): success = 0 (no diff).
terraform apply tfplan
Always apply a saved plan file, never re-plan during apply. Re-planning at apply time can introduce drift between what was reviewed and what is executed.
When presenting a plan for review, summarise as:
## Terraform Plan Summary
| Action | Count | Resources |
|---------|-------|-----------|
| Add | X | [list] |
| Change | X | [list] |
| Destroy | X | [list] |
WARNING — DESTROY/REPLACE resources:
- [resource] — [reason]
Data loss risk: [yes/no]
Estimated cost impact: [if applicable]
State surgery is the second-most-fragile area after destroy. Always back up state before any of these operations (terraform state pull > backup.tfstate).
terraform state list # enumerate resources
terraform state show <addr> # inspect a resource
terraform state mv <src> <dst> # rename / refactor
terraform state rm <addr> # remove from state (resource still exists in cloud)
terraform import <addr> <id> # adopt an existing cloud resource
terraform state pull > backup.tfstate # snapshot state
terraform state push backup.tfstate # restore (DANGEROUS)
For module refactoring, prefer moved {} blocks (TF v1.1+) and removed {} blocks (TF v1.7+) — they encode the rename inside .tf files instead of imperative state ops, which means:
Example moved block:
moved {
from = aws_instance.old_name
to = aws_instance.new_name
}
-target=<resource> for partial-apply is an anti-pattern except in emergencies. State drift between resources causes surprising future plans and breaks the invariant that the state file matches the configuration.
If -target becomes necessary (e.g., breaking a cyclic dependency during initial bootstrap), follow up immediately with a full plan/apply to reconcile.
Terraform workspaces partition state within a single backend:
terraform workspace list
terraform workspace new <name>
terraform workspace select <name>
terraform workspace show
Workspaces are appropriate for per-environment state (dev/staging/prod) when the configuration is identical and only variable values differ. For divergent configurations, prefer separate root modules.
If .conftest/ (Conftest), .opa/ (raw OPA Rego), .tflint.hcl (TFLint), or tfsec.yml (tfsec) / .checkov.yml (Checkov) configs are present, run them as a pre-plan gate. A plan that violates policy never advances to apply.
# Revert the .tf file changes and re-apply
terraform plan -out=tfplan-rollback
terraform apply tfplan-rollback
For state-only rollback (after a botched state mv or state rm):
terraform state push backup.tfstate
State rollback overwrites the backend state and should be coordinated with whoever holds the workspace lock.
| Phase | Apply this knowledge |
|---|---|
| Step 3 — Review current state | terraform validate, fmt -check, plan -detailed-exitcode |
| Step 3a-bis — State operations | state list/show/mv/rm/import, moved {} / removed {} blocks |
| Step 4 — Implement | terraform fmt -recursive, terraform validate |
| Step 5 — Plan review | terraform plan -out=tfplan and plan-summary format |
| Step 6 — Apply | terraform apply tfplan |
| Step 8 — Rollback | Revert .tf files and re-apply, or push backup state |
/infra-change (Steps 3, 4, 5, 6, 8 — Terraform plan/apply lifecycle)@gitops-detection (HCP Terraform / Terraform Cloud / Atlantis / Spacelift / env0 controllers that own the apply gate)development
Use this skill when running the recurring (daily) knowledge-base rescan for a repo that already has knowledge/.knowledge-sync.yml — the main-thread dispatcher that reads the config, computes the git delta since last_scanned_sha, maps changed paths to affected doc areas, early-exits cheaply when nothing changed, then fans out one Agent(content-writer) per affected area, applies the propose/direct update policy, advances the baseline only on success, and writes an L4 run log — all with the G1 untrusted-content choke-point, secret-scan, deny-list, and budget controls woven in. For first-time setup use /knowledge-sync-init.
development
Use this skill when bootstrapping scheduled knowledge-base sync for a repo that has no knowledge/.knowledge-sync.yml yet — to run one-time setup that detects the knowledge_root from CLAUDE.md/AGENTS.md, maps doc areas to source globs, records opt-in external sources (Linear/Notion/WebFetch, all disabled by default), captures a baseline last_scanned_sha, sets the per-area update policy, generates or seeds knowledge/CONVENTIONS.md, provisions the L4 memory dir, and offers to register the daily routine. Routes ongoing recurring sync operations to /knowledge-sync.
tools
Use this skill when bootstrapping a target repository to be ai-skills-aware — on the first run of any ai-skills workflow in a fresh repo, when adopting the ai-skills plugin in an existing repo, or after upgrading to a plugin version that adds new memory paths or templates, including when the user does not say "init" but asks to "set up" or "onboard" the repo — to detect codebase type, create CLAUDE.md + AGENTS.md scaffolding, initialize the .ai-skills-memory/ directory tree from L1 templates, and configure .gitignore. Idempotent — safe to re-run. Accepts `--codebase-type <type>` and `--overwrite`. Not for re-initializing only memory — use `/memory-init` instead.
tools
Use this skill when extending, repairing, or improving plugin assets, when ingesting a `/feedback` report as a fix-cycle backlog, or when you do not remember which lower-level command is right for the job — the umbrella workflow for ai-skills plugin-asset authoring and maintenance: creating, auditing, fixing, improving, refactoring, and migrating skills, agents, rules, hooks, prompts, schemas, and rubrics inside the plugin. Auto-classifies the request, loads the right knowledge skills (`@prompt-engineering`, `@context-engineering`, `@team-protocols`), and spawns the right subagents (`prompt-engineer`, `system-architect`, `python-engineer`, `software-engineer`, `qa-engineer`, `eval-judge`) via the `Agent` tool.