explain-plan
Skill1 starsChanged 26 days agoApache-2.0View on GitHub
Explain a Terraform plan in plain language that cuts straight to what matters - verdict first, then what changes, then what could hurt. Use this whenever the user pastes or points at plan output (`terraform show -json plan.out`, a plan JSON export, or a plan file that can be rendered that way) and wants to know what it will do, whether it is safe to apply, what will be destroyed or replaced, or a summary for a reviewer or non-Terraform stakeholder. Trigger even when they just say "what does this do", "is this safe", "summarize this plan", or "tl;dr this" with a plan in front of them. Do not use for writing or refactoring Terraform code, state surgery, or provider errors that are not plan output.
4 other projects use a version of this.
Adopted by
Most recently taken up by
- mdaneshjoo/skillstheir own version, first seen Nov 8, 2026
- jocarrd/crux-agentstheir own version, first seen Nov 8, 2026
- hass-energy/haeotheir own version, first seen Oct 8, 2026
- datafusion-contrib/datafusion-skillstheir own version, first seen Mar 21, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- hass-energy/haeo★ 77same name
- datafusion-contrib/datafusion-skills★ 14same name
- jocarrd/crux-agents★ 4same name
- mdaneshjoo/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository8 other files it gives its agents.
- .claude/CLAUDE.mdCLAUDE.md
- check-moduleSkill
- fix-review-findingsSkill
- look-up-schemaSkill
- onboard-toolchainSkill
- review-moduleSkill
- trace-change-impactSkill
- writing-terraformSkill
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 5 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 18
Call the plan_digest tool with path set to the JSON file.
- Distinctive: line 26
Write the explanation in the format below.
- Distinctive: line 58
Do not narrate every resource.
- Very specific: line 59
Do not hedge with "may" and "could" when the plan is definite.
- Distinctive: line 60
No praise, no preamble, no "Here's a breakdown of your plan".
- Distinctive: line 61
When the plan is clean, the whole explanation can be three lines.
- Distinctive: line 62
Never invent values the plan does not contain.
- Very specific: line 63
When you tell the reader how to apply, name the saved plan file the JSON came from (terraform apply plan.out).
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Terraform plan explainer
A plan is the only honest preview of what apply will do, and almost nobody reads the whole thing. Reviewers skim for the Plan: line, miss the one # forces replacement buried in 400 lines of tag diffs, and find out about the database rebuild during the maintenance window. This skill exists to make the one paragraph that matters impossible to miss.
The reader might be the SRE approving the apply, the engineer who wrote the change, or a manager who has never seen HCL. Write so the first two lines serve all three and the rest rewards whoever keeps reading.
Workflow
- Get the plan as JSON in a file inside the project root.
plan_digestreads onlyterraform show -jsonoutput and refuses any path outside the project root, so a file under/tmpcannot be digested. If the user has a binary plan file (plan.out,tfplan), render it withterraform show -json plan.out > plan.jsonin the module directory. If they pasted JSON, write it to a file in the project. Plan text is not supported: when that is all you have, ask for the plan file or the JSON rendering, and do not guess values from text. Call the
plan_digesttool withpathset to the JSON file. It does the counting so you don't miscount by eye.The result carries
countsper action, every changed resource inresource_changeswith itsactions, the attributes that forced a replacement (forced_by), the names of itssensitive_attributesand itsflags, theoutput_changes, and the top levelmoves,imports,driftedaddresses andplan_flags(mass-destroy,drift,unsupported-action). The flags are described inreferences/risk-heuristics.md. Trust its counts over your own reading of the plan. A refused path or an unreadable document is the first line of your explanation, not a footnote.- Read the digest, then read the plan itself for anything it flagged. The tool finds the risk; you explain it. For a large plan, dispatch one
terraform-researcherper flagged resource or per module address in parallel, each asked what the plan says about that address and what in the configuration explains it; they are cheap and disposable, and their reports give you the before/after facts and the declaring file without pulling the whole plan into your context. - Check what the plan does besides create, update and destroy.
movesare renames in state with no infrastructure change, unlesswith_changesays the resource also changes. For each move, check in the plan that the identifying attributes (name, identifier, ARN) are the same before and after: a move to the wrong object shows no replacement while state now tracks a different resource.importsbring existing resources under management, anddriftedlists resources someone changed outside Terraform, which the plan may be reverting. Say each in one line. - Write the explanation in the format below.
Output format
Lead with the worst thing. If the plan is boring, say so in one line and stop early. Length scales with risk, not with the number of resources.
**Verdict:** <one sentence: safe to apply / needs a look / do not apply as-is, plus the counts that matter>
**What it does**
- 2-6 bullets, grouped by intent, not by resource. "Adds a read replica for the orders database in us-west-2", not "creates aws_db_instance.orders_replica".
- Collapse noise into one bullet: "Tag and description updates on 14 resources, no behavior change."
**Watch out** (omit the section entirely when there is nothing here)
- Destroys, replacements and what forced them, downtime, data loss, public exposure, IAM widening, cost jumps. One bullet each, concrete: "`aws_db_instance.main` is replaced because `engine_version` changed 14 -> 16. Replacement is delete-then-create: the database is gone until the new one is up, and the data goes with it unless a snapshot exists."
**Details** (only when the reader wants them, or the plan has more than ~10 changes; wrap in <details> for PR comments)
| Resource | Action | Why |Verdict wording:
- Safe to apply - creates and in-place updates only, nothing in the watch-out list.
- Needs a look - replacements, destroys of stateless things, security-adjacent changes, or anything the digest flagged.
- Do not apply as-is - destroys or replaces a stateful resource without evidence of a backup, opens something to the internet, grants wildcard IAM (
*actions, resources or principals), strips deletion protection, or the plan destroys a large share of the workspace.
Writing rules and why
- Translate resource types into what they are.
aws_db_instanceis a database,google_compute_firewallis a firewall rule,kubernetes_deploymentis a running workload. The manager does not know the type names and the SRE does not need them repeated. - Name the attribute that forced a replacement and the direction of the change. "Replaced" alone is useless; "replaced because
subnet_idchanged" tells the engineer whether that was intended. - Distinguish delete-then-create from create-before-destroy. One is an outage window, the other usually is not. The digest tells you which (
replace-delete-firstorreplace-create-first). - Say what is lost. Destroying a bucket, database, queue, disk, KMS key or secret loses data or the ability to decrypt it. Say that plainly instead of "resource will be destroyed".
- Do not narrate every resource. If 30 security group rules are being recreated because a module was refactored, that is one bullet: "The module refactor recreates all 30 ingress rules; brief window where rules are absent."
- Do not hedge with "may" and "could" when the plan is definite. The plan says what will happen. Uncertainty only belongs where Terraform itself says
(known after apply). - No praise, no preamble, no "Here's a breakdown of your plan". Start with the verdict.
- When the plan is clean, the whole explanation can be three lines. Padding a safe plan to look thorough trains readers to skim, which is the problem this skill exists to fix.
- Never invent values the plan does not contain. Sensitive attributes appear in the digest by name only; say that they changed, not what they changed to.
- When you tell the reader how to apply, name the saved plan file the JSON came from (
terraform apply plan.out). Never suggestterraform apply -auto-approve: it plans again and can apply something other than what you explained.
Reading the digest
references/risk-heuristics.md lists the resource-type patterns and attribute patterns plan_digest flags and explains why each matters. Read it when a flag fires that you don't immediately understand, or when a plan contains a provider the heuristics don't cover and you need to judge stateful-vs-stateless yourself.
The heuristics are deliberately conservative: a flag means "look here", not "this is wrong". Downgrade a flag in your explanation when the plan itself shows it is fine (for example a destroy of an aws_s3_bucket whose force_destroy is false will fail rather than lose data, and a create_before_destroy replacement of a stateless resource is routine).
Examples
Boring plan, engineer asked "what does this do":
Verdict: Safe to apply. 3 in-place updates, nothing destroyed or replaced.
What it does
- Bumps the
apiECS service from 2 to 4 tasks and raises its CPU reservation.- Tag updates on the ALB and target group, no behavior change.
Dangerous plan, SRE asked "is this safe":
Verdict: Do not apply as-is. 1 replacement of a production database and 1 security group opened to the internet, alongside 6 routine updates.
What it does
- Upgrades the main Postgres database from engine 14 to 16 and moves it to the new private subnets.
- Opens port 5432 on the database security group to
0.0.0.0/0.- Adjusts autoscaling limits and tags on the app tier.
Watch out
aws_db_instance.mainis replaced becausesubnet_group_namechanged; the engine bump alone would have been in-place. Replacement is delete-then-create, so the database and its data are gone until the new instance finishes, and the plan shows no snapshot. Confirm a snapshot exists or setskip_final_snapshot = falsefirst.- Ingress rule on
aws_security_group.dbchanges from the app subnet CIDR to0.0.0.0/0on 5432. That exposes the database to the internet. Almost certainly a mistake.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

