Back to Blog
DevOpstech dialogue7 min read19 June 2026

terraform apply. Friday. 7pm. LimitExceeded.

A Friday movie plan, a Terraform error, a DevOps engineer with zero TypeScript knowledge, and an AI that had too much fun with it.

KJ
Kartikeya
Claude
Claude
VK
Vinayak
SJ
Somil
Terraform
Terraform
ambient music playing

Synopsis

The story of how a recurring Terraform error, a ruined Friday plan, and a conversation with Claude turned into a real VSCode extension.

Friday. 7pm. The week was finally over. Kartikeya had updated his scripts, reviewed his changes, and was ready to close his laptop and go watch a movie.

One last thing. Just hit apply.

KJ
Kartikeya

"Hey, today is Friday. Movie plan is on?"

VK
Vinayak

"Obviously man. Just come soon."

KJ
Kartikeya

"Give me two minutes. Just updated my scripts. Hitting apply and then we are good to go."

(Famous last words.)

terminal
$ terraform apply
Plan: 12 to add, 3 to change, 0 to destroy.
# aws_iam_policy.backend_policy will be created
# aws_iam_policy.ecr_policy will be created
...
Apply complete! Resources: 6 added.

Progress bars. Resources creating. Looking good.

And then - stop.

Terraform
Terraform

Sorry buddy but not today. ๐Ÿฆน

error

Error: LimitExceeded: Policy document exceeds the maximum allowed size

on iam.tf line 14, in resource "aws_iam_policy" "backend_policy":

14: policy = templatefile("policies/backend.tftpl", local.policy_vars)

KJ
Kartikeya

"Fish!!! Abee yaar (What the hell man)!!! Hey, I might not be able to make it tonight."

VK
Vinayak

"Again?? Man. Do one thing - just marry this stuff.๐Ÿคฌ"

KJ
Kartikeya

๐Ÿ˜ข

The frustrating part - terraform plan showed nothing. No warning. No hint. AWS only checks IAM policy size at apply time. By the time you know you have a problem, you are already in one.

And the even more frustrating part that nobody talks about - our policies use Terraform's templatefile() function. The files are full of ${variable} placeholders. Those variables look small. ${aws_account_id} is 16 characters. The real account ID is 12 digits. ${state_bucket_name} is 20 characters. The real bucket name is far longer.

Multiply that across dozens of variables and hundreds of statements. You have no idea what the real size is just by looking at the file. You are flying blind every single time.

This was not the first time it had happened. This time Kartikeya decided enough was enough.

The Search

He looked for a tool inside VSCode that solved this. Something that would substitute variables with real values, measure the actual size, and tell him exactly where he stood before apply.

He could not find one.

So he opened a conversation with Claude.

KJ
Kartikeya

"Hey Claude. I keep hitting IAM policy size limits in Terraform mid-deploy. terraform plan catches nothing. I want to build a VSCode extension that substitutes variables, minifies the JSON exactly like AWS does, and tells me the size before I apply. Can you help?"

Claude
Claude

"Yes, absolutely. Here is the architecture - a CodeLens provider for inline hints, a WebviewPanel for the report, a variable resolver that caches inputs, and the core analyzer.

The key insight: JSON.parse() followed by JSON.stringify() with no arguments. That is exactly what AWS measures. The length of that string is your policy size.

Want me to walk you through the structure first, or should we start writing code?"

KJ
Kartikeya

"Give me the concepts first. I want to understand what I am building."

And so Kartikeya learned - or at least understood enough to know what he was asking for. The VSCode extension API. CodeLens. WebviewPanel. Activation events. He got the concepts. He knew what each piece did.

Claude
Claude

"Do you want to write the TypeScript yourself, or should I write it?"

KJ
Kartikeya

"Honest answer? Do I want to learn TypeScript today? No. I am already learning too many things. TypeScript can wait - I have plenty of life left (Fable 5, I can feel you ๐Ÿ˜‚).

So yes - can you write the code?"

Claude
Claude

"I mean, seriously. What else am I here for. Tokens and context windows are what I live for. Let's build this properly."

(And so they did.)

What Kartikeya Refused to Delegate

The irony of building a tool to reduce dependency on manual work while depending on AI to write it was not lost on Kartikeya. He said so publicly in the README.

So in the end most of the idea became a reality via Claude. He was a little disappointed in himself for relying on AI completely. Because one day if someone switches off AI - Fable 5, he could feel it - what will the new generation do?

But no worries. In this journey he at least got to learn the things he was already working on. GitHub Actions. CHANGELOG. Release pipelines. The stuff that actually matters for shipping.

But there were things he refused to let Claude do. Things he wanted to learn properly.

terminal
# Things Kartikeya built himself
โœ“ GitHub Actions CI - Node 18 + 20 matrix, green on every push
โœ“ Semantic versioning and conventional commits
โœ“ Release pipeline - tag triggers VSIX packaging + GitHub Release
โœ“ CHANGELOG, README, CONTRIBUTING guide
# The release process
$ git tag v1.0.0
$ git push origin v1.0.0
# Done. VSIX packaged. Release created. Automatically.

He built it this way because he builds infrastructure for a living. He knows what happens to tools that are not maintained properly. They rot. They break silently. Nobody trusts them.

If this was going to be useful, it had to be built like something worth trusting.

When Someone Else Showed Up

The day after the first release, Kartikeya was talking to his colleagues Somil and Vinayak. Somil had an idea.

SJ
Somil

"You know what would make this better? Wildcard detection. And duplicate action detection - duplicate actions in the same statement waste characters and do nothing. The parser collapses them anyway."

KJ
Kartikeya

"That is actually really good. Fork the repository. Make the changes. I will review them."

(He obviously reviewed them with Claude's help.)

Getting to that release took longer than either of them expected. Corporate work and personal passion are like two people trying to stay friends after a breakup - the intent is there, the timing never quite works out.

But eventually, Somil submitted the PR. Kartikeya reviewed it carefully. Pushed back on a few edge cases. They went back and forth.

terminal
$ git log --oneline v1.1.0
a3f2c1d feat: add wildcard detection in Action and Resource fields
b8e4d2f feat: add duplicate action detection with char savings
c9f1a3e test: add 8 tests for wildcard and duplicate logic
d2b7e4c docs: update README with Policy Quality Checks section

Then it was merged and v1.1.0 shipped.

That was the moment it stopped being a personal tool.

Something about building a thing, putting it out in the world, and having another person decide it was worth their time to make it better. Kartikeya cannot fully explain why that felt significant. It just did.

First external contribution. Reviewed, merged, shipped.

What Is Next

Honestly, even Kartikeya does not know fully.

Publishing to the VSCode Marketplace is on the list. Using it daily and finding what breaks. Maybe Somil has another idea. Maybe someone else shows up with a pull request.

VK
Vinayak

"So are we watching that movie or not?"

KJ
Kartikeya

"Yes. The extension will handle the rest."

See It In Action

The full technical breakdown - how the extension works, the architecture flow, and the Story Mode - lives on the project page.

KJ
Kartikeya

"Also, if you want to see the architecture flow and the full technical breakdown, check the project page."

The best tools are built out of frustration. The best releases happen when someone else cares enough to contribute. The best engineers know which things to learn themselves - and which things to let the AI write.

All Writing- Kartikeya Jain