Vylara
aiterraformarchitecture

AI can write your Terraform. It still shouldn't apply it unsupervised: durable checkpoints for agent-driven infrastructure

Why agent-generated Terraform needs structural human gates: durable LangGraph checkpoints in Postgres, two-track approvals, and unattended deploys done safely.

Written byVylara Team
5 min read
AI writes Terraform. Humans approve it.

It’s 2026 and coding agents write genuinely decent Terraform. Give one a repo and it’ll produce an HCL root with a VPC, an ECS service, an RDS instance, sensible tags, even a lifecycle block or two. It validates. It plans cleanly. It applies.

That’s exactly the problem.

Plausible is worse than wrong #

When AI-generated infra is obviously broken, terraform validate catches it, or the plan errors out, and nobody gets hurt. The dangerous output is the plan that applies cleanly and is still wrong:

  • An m5.2xlargefor an app that idles at 3% CPU, because the agent pattern-matched “production API” to “big instance.” That’s ~$280/month of nothing.
  • A database subnet group that quietly includes a public subnet, because the agent reused a subnet ID from earlier in its context.
  • deletion_protection = false on the RDS instance, because most Terraform examples on the internet omit it.
  • A security group ingress of 0.0.0.0/0on port 5432 “for debugging,” which the agent helpfully copied from the repo’s old docker-compose-era setup.

None of these fail a plan. All of them are things a human reviewer flags in thirty seconds — if there’s a structural place for that human to stand. A chat message saying “look ok?” is not a structural place. The agent’s workflow has to be built so that it physically cannot proceed past certain points without a recorded human decision.

Make the pause a first-class node, not a dialog box #

Our agent pipeline is a LangGraph StateGraph checkpointed in Postgres via AsyncPostgresSaver. The analysis flow looks like this:

clone → detect_stack → analyze (plan + edit plan)
     → plan_approval ⏸
     → secret_manager_adapt → implement → validate_configs
     → configs_approval ⏸
     → apply_edits → build_verify → push_pr → END

Those two ⏸ nodes — plan_approval and configs_approval— are not UI affordances bolted on top. They’re nodes in the graph. When execution reaches them, the graph stops, the full state is checkpointed to Postgres, and nothing happens until a human resumes the thread with a decision.

Because the checkpoint is durable, the pause survives everything:

  • The agent-engine pod gets redeployed mid-review? State is in Postgres, not process memory. The graph resumes from the exact node.
  • The user approves three days later? Fine. The thread ID (analysis-{project_id}) picks up where it left off.
  • We ship a new version of the engine between pause and resume? The checkpointer replays state into the same node graph (we keep legacy node IDs as aliases specifically so old checkpoints stay resumable).

Compare that to the common alternative: a confirm dialog in front of a long-running in-memory process. If anything restarts between “agent finished planning” and “human clicked approve,” you’ve lost the plan the human thought they were approving. Best case you re-run the agent and hope it produces the same output. Worst case it produces different output and the approval silently attaches to artifacts nobody reviewed.

The two-track approval model #

Human review happens on two tracks, and they’re deliberately different:

Track 1: code and config changes arrive as PRs.When the agent needs to touch the repo — Dockerfile, env wiring, replacing a hardcoded Redis IP with a DNS name — those edits go through apply_edits → build_verify → push_pr. The output is a pull request. Humans review it with the tooling they already trust: diffs, CI, branch protection. We didn’t invent a review surface for code; GitHub already won that.

Track 2: the infrastructure plan is approved in-app, before any apply.The architecture plan — what resources, what sizes, what it’ll cost per month — is what plan_approval gates. The human sees the proposed topology and the cost estimate and explicitly approves it. Only after that approval does the implementation phase even begin.

Here’s the part that surprises people: the deploy graph itself has no human gate. The deploy pipeline (ensure_network → plan_infra → build/push image → apply_infra → health_check) runs plan-to-apply unattended. That’s intentional, and it’s only safe because of the structure above it: by the time a deploy runs, it’s executing against an architecture a human already approved and configs a human already approved. The deploy’s job is to faithfully apply exactly that, not to make new decisions. Gating every apply would just train people to click through; gating the decisions keeps the reviews meaningful and the deploys fast.

Why durability matters more than the gate itself #

Anyone can add an “Are you sure?” modal. The durable checkpoint buys you three things a modal can’t:

  1. Resumability.Approval is asynchronous in real life. People review infra plans between meetings, the next morning, after asking a teammate. A pause that only survives as long as a process does isn’t a pause, it’s a race condition.
  2. Auditability. The checkpoint isthe record. What state was the graph in when the human approved? Exactly what plan did they see? It’s in the Postgres checkpoint for that thread, not reconstructed from logs.
  3. No drift between approval and apply.Because the approved plan is persisted state that downstream nodes read, the thing that gets applied is the thing that was approved. There’s no window where the agent “re-thinks” after approval.

Honest limits #

This design doesn’t solve approval fatigue. If you show humans enough plans, they start rubber-stamping — the tenth cost estimate gets the same three-second glance as a cookie banner. We see it in our own usage. Mitigations we’re still iterating on: surfacing diffs against the previously approved plan rather than full plans, and flagging high-blast-rules (public ingress, deletion protection off, instance size jumps) so the approval screen leads with the dangerous parts instead of burying them in resource lists.

A checkpoint also can’t make a reviewer competent. If the human approving the plan doesn’t know why a database in a public subnet is bad, the gate is theater. The gate creates the opportunityfor judgment; it doesn’t supply the judgment.

But the alternative — agents applying infrastructure changes with no durable, structural pause — is how you wake up to a surprise AWS bill or a public database. The agent writes the Terraform. A human owns the decision. The graph makes sure the second part can’t be skipped.

I’m building Vylara, a platform that analyzes your repo and provisions AWS infrastructure for it — with exactly these approval gates baked into the agent workflow.

Try Vylara on your repo

Review your cloud plan in Vylara, merge delivery changes as Git PRs, and deploy into your own AWS or Azure account when you’re ready.

Start free

Related posts