A survival guide for building software in the age of AI Agents.
If you've played with the latest AI coding tools, you know the feeling. It's intoxicating. You type "Build me a dashboard," and poof—code appears. You feel like a wizard. You are "Vibe Coding"—surfing on a wave of generated features, moving faster than you ever thought possible.
I know this feeling because I lived it. I spent Oct 2024 to June 2025 vibe-coding my way to a feature-rich management app called SMT (Software Management Tools). But then, the wave crashed. I decided the AI wasn't mature enough yet, and decided to take a break from vibe coding further. Until I woke up again in November '25, and in December '25 plunged right back in with the release of newer models and new tooling from Google, especially Antigravity got me hooked solid! Wow, the landscape is changing dramatically!
This is the story of how I went from a chaotic, AI-generated monolith to a nearly professional, engineered codebase. And more importantly, it's a guide on how you can avoid the trap of "Vibe Coding" and start using AI more effectively to build serious software, than just demos.
The Visual Journey: The "Model War" Timeline
The Industry Context: Riding the Wave
To understand why the code changed, you have to understand how the tools changed. The explosion of antigravity features coincided perfectly with the "Agentic Arms Race" of 2025.
Phase 1: The Trap of "Vibe Coding" & The Quota Shuffle (Winter 2025)
After a long summer working flat-out at Amazon, I found myself with a 3-month sabbatical in May 2025. It was a golden age for AI releases. Google had just dropped "Jules" (in Public Beta). Anthropic and OpenAI were trading blows with massive context windows.
I went fast. Recklessly fast.
I treated the AI models like a tag-team of interns.
- Morning: I'd burn through my Gemini quota building the Gantt chart.
- Afternoon: I'd switch to Claude for major technical debt refactoring, while using Gemini for UX refactoring and plumbing.
- Evening: I'd use OpenAI to debug the logic and provide a third-party review.
The "Tower of Babel" Problem:
Each model had a different "personality." Because I wasn't providing governance, the codebase became a schizophrenic mess. main.js was a mix of 3 different coding styles fighting for dominance.
The Agent Blame Game (Whack-a-Mole)
My frustration peaked just yesterday (Dec 14) during the Gantt refactor. I entered a cycle of "Agent Whack-a-Mole":
- I was working with Claude 3.5 Opus to stylize the complex SVG dependency arrows. It was working perfectly.
- CRASH: "Quota Exceeded."
- I swapped to Gemini 2.0 to keep the momentum going. "Gemini, continue styling these arrows."
- Gemini, eager to help, rewrote the
GanttRendererclass. It fixed the styling but deleted the logic for dependency calculation, breaking the core feature. - My quota reset. I went back to Claude: "Claude, Gemini deleted the logic. Fix what it broke."
I spent hours just mediating disputes between AI models that couldn't see each other's work. It was clear: without a shared "Constitution" (The Contract), they were just tagging over each other's graffiti.
The Structural Evolution (Visualized)
The transformation wasn't just in the code; it was in the very shape of the project.
Phase 1: Inception (Oct 2024)
(Simple, clean, but incapable)
/root
├── index.html
├── LICENSE
└── README.md
Phase 2: The Sprawl (June 2025)
(Features added by "Vibe Coding" with no plan)
/root
├── index.html
├── js/
│ ├── main.js (3000+ lines)
│ ├── utils.js (Everything basket)
│ ├── data.js (Hardcoded state)
│ ├── visualizations.js (D3 spaghetti)
│ └── ... (20+ flat files)
└── css/
├── style.css (Global conflict zone)
└── ...
Phase 3: The Engineered State (Dec 2025)
(Governed by Contract)
/root
├── ai/ (Agentic Controllers)
├── docs/ (The Contracts)
├── css/
│ ├── components/ (Scoped styles)
│ └── themes/ (Variables)
└── js/
├── services/ (Logic Layer)
├── components/ (View Layer)
├── managers/ (State Layer)
└── main.js (Bootstrapper only)
Phase 2: The Pivot to Engineering (Summer 2025)
I realized that if I wanted this project to survive, I had to stop acting like a "prompter" and start acting like a "Principal Engineer."
The shift happened on December 3rd. I didn't ask the AI to write code. I asked it to read a Contract.
The Agent Contracts: A Rule of Law
We didn't just write one prompt; we established a constitutional framework for the AI. This came in the form of two critical documents that every agent was required to ingest before writing a single line of code.
1. The Coding Contract (coding-agent-contract.md)
This document outlawed the bad habits the AI had picked up during the "Vibe Coding" era. It established zero-tolerance policies:
- "No Defensive Coding for Internal Code": Stop asking
if (typeof SystemService !== 'undefined'). Trust the architecture. - "The Singleton Rule": All logic resides in Services. No ad-hoc functions in files.
- "The Window Ban": Writing to
window.myVariablewas strictly prohibited. State must be encapsulated.
2. The Workspace Canvas Contract (workspace-canvas-contract.md)
This was the game-changer for UI. It stopped the AI from inventing new layouts for every page.
- "The Semantic Color Rule": Hardcoded hex values like
#fffor#000were banned. The AI had to use semantic variables likevar(--theme-bg-primary). This single rule made implementing Dark Mode instant. - "The Shell Protocol": Every view had to plug into a standard
WorkspaceShell. No more rogue sidebars or inconsistent headers.
Why this matters:
These contracts turned the AI from a chaotic creative into a disciplined engineer. When the AI encountered a problem, it didn't just "fix it"; it checked the Contract to see how it was allowed to fix it.
Pro Tip: The Self-Audit
I didn't just trust the AI to follow the rules. On Dec 11, I ran a "Compliance Report" task. I asked the AI: "Scan the entire codebase. List every file that violates the workspace-canvas-contract.md."
It found 15 violations I had missed. The AI became its own auditor.
Phase 3: The Payoff (The "Agentic Spike")
With the contract in place, I unleashed the new Antigravity agents in December.
In one weekend (Dec 7-8), we processed 47 commits that didn't add a single feature but completely re-wired the application.
- The "Junk Drawer" must die: We deleted
utils.js. In the "Vibe Coding" days, this file became a 2,000-line dumping ground for everything from date formatting to API calls. We exploded it into dedicated Services. - 117 spaghetti files became 169 modular classes.
- Global variables vanished.
- Theming became a single-line change.
The Discipline of Deferral
The hardest part wasn't the code; it was the patience.
I had a major feature ready to go: Year Planning. In the old "Vibe Coding" days, I would have just asked Gemini to "add it."
Instead, I deferred it.
I spent a week refactoring the Gantt view and the Org view to meet the new Contract first. Only when the architecture was solid did I allow the AI to touch YearPlanning.
- Result: When I finally asked the AI to refactor
YearPlanning(Commit392ffcd), it got it 90% right on the first shot. Because it had "learned" from the codebase and I had enforced the patterns elsewhere, the most complex feature in the app became the smoothest refactor.
The "Audit Loop" Struggle
It wasn't magic. It was a fight.
Enforcing the contract was a recursive nightmare at first. I would ask the AI to "Fix the compliance issues in GanttPlanning.js."
- Run 1: AI removes global variables. (Good)
- Run 1 Side Effect: AI introduces a new inline HTML template. (Violation!)
- Run 2: I scold the AI: "No inline HTML! Check the Contract!"
- Run 2: AI fixes HTML.
- Run 2 Side Effect: AI adds a defensive check
if (typeof SystemService...). (Violation!)
I often had to prompt the agent 5 or 6 times just to get one file clean. I had to explicitly remind it: "You are an expert engineer. Do not regress on the Contract. Check your own work against coding-agent-contract.md before submitting."
The 5 Deadly Blind Spots
Even with the contract, I learned that Agents have recurring "blind spots" you must watch for:
- Zombie Code: They love to write the new class
GanttMvc.jsbut forget to delete the oldganttPlanning.js, leaving you with two conflicting sources of truth. - The "Partial Success" Hallucination: An agent will refactor 3 out of 5 methods and happily announce, "I have completed the refactor!" You have to check the bottom of the file.
- The Compatibility Trap: When refactoring, agents often try to be "helpful" by keeping the old broken methods "just in case," creating a hybrid mess instead of a clean break.
- Phantom Functions: They assume
utils.formatDateexists because it feels right, even if you deletedutils.jsyesterday. - The Rename Reflex: Instead of finding the existing method
calculateDuration(), they will invent a new one calledgetTaskLength(), duplicating logic because they didn't index the context.
The "Sync": When It Just Clicks
To be fair, it wasn't all struggle. There were moments of absolute magic.
During the "Agentic Spike" (Dec 7-8), when the Contract was fresh and the Context was clean, I hit a Flow State with the AI that felt telepathic.
- I'd say: "Refactor the OrgView to use the new Service pattern."
- The Agent would output 4 perfect files.
- I'd say: "Excellent. Now do the same for the Gantt view."
- It would interpret "the same" correctly, applying complex patterns without needing them restated.
- "You Rock", "Awesome Job", "Perfect" — my chat logs from that weekend are full of these praises.
When you treat the AI as a partner with a shared mental model (the Contract), the friction disappears. You aren't prompting; you're just... building.
The New Metric: CW/H (Curse Words per Hour)
Waleed Kadous recently proposed a new metric for AI quality: Curse Words per Hour (CW/H).
My project logs are the perfect validation of this theory.
- High CW/H: During the "Blind Spots" and "Whack-a-Mole" phases, my prompts were full of CAPS and desperation: "STOP. YOU DELETED THE LOGIC AGAIN. REVERT. WHAT ARE YOU DOING??" This wasn't just anger; it was a signal of Context Drift. The model had lost the thread.
- Negative CW/H: During "The Sync," my CW/H went negative (praise acts as -1). "Perfect," "You nail it," "Go ahead."
The Lesson: Your emotional reaction is a debugging tool. If you find yourself swearing at the AI, stop. Do not prompt harder. The Context has drifted. Reset the chat, paste the Contract, and start fresh.
But once it learned? The velocity was unstoppable.
The "Gantt Odyssey": A Case Study in Persistence
If you want to know what "refactoring hell" looks like, look at the git history for the Gantt chart.
- Nov 23 (The False Start): I tried to "refactor" the monolithic
ganttPlanning.jswhile keeping the "vibe" intact. It failed. The code was too entangled. - Nov 25 (The Feature Trap): Instead of fixing the foundation, I asked the AI to add more features (Frappe renderer, toggles). This was a mistake. The
main.jsfile ballooned to 3,000 lines. - Dec 9 (The Realization): Commit
f4c4845"WIP - re-architect gantt to mvc." This was the moment I realized the old code had to die. - Dec 14 (The Victory): Commit
6c5b6f7"Complete refactor of gantt and delete legacy ganttPlanning.js."
It took 4 distinct attempts and over 20 commits just to clean up this one feature. The lesson? You cannot refactor spaghetti into lasagna one noodle at a time. Sometimes, you have to throw the bowl away and start fresh with a new recipe (the Contract).
The "Git Worktree" Trap: Parallel Agents & The Danger Zone "Git Merge Hell"
As I got comfortable with Antigravity, I got greedy. I thought: "Why wait for one agent to finish? I'll run TWO."
I used Git Worktrees to run multiple agents in parallel on different branches (feature/gantt and refactor/theming). Agents can make mistakes, some quite serious like messing up context about the branch they supposed to be working on!
- The Dream: Double the velocity.
- The Reality: "Merge Hell" and Corruption.
On Dec 8th, I nearly lost the entire Theming refactor. One agent overwrote the css/variables.css file while another was trying to read it. I spent 4 hours manually piecing together "lost" commits (see commit 2ac3f34: "fix: merge ALL missing theming changes from worktree").
The Warning: Antigravity is powerful, but it does not sandbox your agents. If you run them in parallel without strict discipline, they will step on each other's toes. Until we have automatic sandboxing, treat parallel execution like handling uranium: powerful, but deadly if mishandled.
Lessons for the AI-Augmented Developer
If you validly want to move from "Vibe Coding" to "AI Engineering," you need to fundamentally shift your mental model. What I've learnt so far:
1. Shift from "Writer" to "Architect"
The era of the "10x Developer" writing code alone in a basement is dead. We are now in the era of the "10x Architect."
AI generates code at near-zero cost. This means code is no longer an asset; it is a liability. Your job is not to produce more of it; your job is to curate it.
- The Trap: Asking "Write me a function that does X."
- The Fix: Asking "Given this architecture pattern, implement interface X for component Y."
Insight: You must have the entire system map in your head because the AI only has the context window.
2. Context Engineering > Prompt Engineering
Stop trying to find the "perfect prompt." It doesn't exist. Instead, focus on Context Engineering.
An AI agent is only as good as the files you feed it. If you feed it spaghetti utils.js, it will write more spaghetti.
- The Strategy: Create "Context Files" (like our Contracts) that exist solely to guide the AI.
- The Tactic: Before asking for a feature, pause. Ask yourself: "Does the AI have the current definition of our state management?" If not, paste the Contract first.
3. The Next Frontier: TDD as the Ultimate Spec
I'll be honest: SMT doesn't have a test suite yet. That is my next goal, but the refactoring was time consuming, laborious and very frustrating - either I introduce TDD or build some new features!
Why? Because looking back, I realize that Test-Driven Development (TDD) is the ultimate way to prompt an agent. A natural language prompt is ambiguous ("make it fast"). A failing test case is binary (Pass/Fail).
- The Plan: We are going to implement a unit testing framework with the help of AI agents.
- The Workflow: Write the test. Run it (Red). Feed the failure to the AI. Let it fix (Green).
4. Code Durability: Know What to Throw Away
Not all code deserves love. In an AI world, we must distinguish between Foundation Code and Disposable Code.
- Foundation Code: Core business logic, data models, contracts. This must be reviewed by a human, typed strictly, and protected.
- Disposable Code: UI prototypes, scripts, experimental features. Let the AI "vibe code" these. If they work, great. If not, delete them and regenerate. Do not fall in love with the prototype.
Final Words: The End of "Magic", The Beginning of Engineering
The journey of building SMT in 2025 taught me that AI is not a replacement for engineering; it is an amplifier of it. If you amplify chaos, you get "Vibe Coding"—a fast track to a tangled monolith. If you amplify structure, you get velocity.
We are entering a golden age of software development. Code is cheaper, faster, and more accessible than ever before. But let's not kid ourselves: this is not an easy journey. The "magic" of a one-shot prompt wears off the moment you need to maintain that code in production. The real work begins when the browser tab closes and the git commit hook runs.
Until AI agents evolve to possess the intuition of a Principal Engineer—knowing instinctively when to create a service vs. a utility, or when to refactor before building—human oversight remains critical. We are not just "prompters"; we are the guardians of the architecture. We provide the constraints (the Contracts) that allow the AI to be creative without being destructive.
My project SMT survived the "Model Wars" of 2025 not because I wrote better prompts, but because I stopped prioritizing speed and started prioritizing structure.
Don't just vibe. Build.



No comments:
Post a Comment