Coding with AI on a Budget — My Structured, Multi-Model Workflow

I’m a heavy AI user, but I don’t just open ten tabs and throw the same question at every model I can find. My workflow is deliberate, and every model has a defined role in the process.

It’s not that the “AI buffet” style is wrong — in fact, this excellent guide is a perfect example of that approach. But my own style is more like a relay race: each model runs its leg, then hands off to the next, so no one’s doing a job they’re bad at.


Phase 1 — Discovery & Requirements (ChatGPT as the Architect)

When I’m starting something new, I begin with long back-and-forth Q\&A sessions in ChatGPT.

  • The goal is to turn fuzzy ideas into clear, testable requirements.
  • I’ll ask “what if?” questions, explore trade-offs, and refine scope until I have a solid first draft of requirements and functional specs.

Why ChatGPT? Because it’s great at idea shaping and structured writing — and I can quickly iterate without burning expensive tokens.


Phase 2 — Critique & Refinement (Gemini as the Critic)

Once I have a draft, I hand it over to Gemini 2.5 Pro.

  • Gemini acts like a tough peer reviewer — it questions assumptions, spots gaps, and points out edge cases.
  • I take Gemini’s feedback back to ChatGPT for edits.
  • We repeat this loop until the document is solid enough to hand off to implementation.

This step makes the coding phase dramatically smoother — Claude Code gets a blueprint, not a napkin sketch.


Phase 3 — Implementation (Claude Code as the Builder)

With specs locked in, I move to Claude Code for the actual build.

  • I prep the context using a tool like AI Code Prep GUI to include only the relevant files.
  • Claude Code follows instructions well when the brief is crisp and the noise is low.
  • This is where the investment in phases 1 and 2 pays off — Claude isn’t guessing, it’s executing.

Phase 4 — Specialist Consultations (Free & Budget Models)

If something tricky comes up — a gnarly bug, architectural uncertainty — I call in a specialist.

  • For deep problem-solving: o3, GLM 4.5, Qwen3 Coder, Kimi K2, or DeepSeek R1.
  • For alternate perspectives: Poe.com’s Claude 4, OpenRouter’s o4-mini, or Perplexity for research.
  • The point is diagnosis, not doing the build work.

These models are often free (with daily credits or token grants) and help me avoid overusing paid API calls.


Why This Works for Me

  • Role clarity: Each model does the job it’s best at.
  • Lower costs: Expensive models are reserved for hard, high-value problems.
  • Better output: The spec→critique→build pipeline reduces rework.
  • Adaptability: I can swap out models as free-tier offers change.

Closing Thoughts

AI isn’t magic — you are.
The tools only work as well as the process you put them in. For me, that process is structured and deliberate. If you prefer a more exploratory, multi-tab style, check out this free AI coding guide for an alternate perspective. Both approaches can work — the important thing is to know why you’re using each model, and when to pass the baton.

Why Most Design Docs Fail—And How to Write One That Won’t

If you’ve ever slogged through pages of technical jargon and bullet points nobody will remember, you know why most design docs flop. They aren’t just boring—they’re useless. Not because the writers can’t write, but because they’re thinking about the wrong things.

This guide is for engineers, tech leads, and architects who want their design docs to move the project forward—not just check a process box.

A note on inspiration:
This approach owes a debt to Grant Slatton’s “How to Write a Good Design Document”, which nails the fundamentals of design doc clarity. The advice below builds on his framework, shaped by mistakes and lessons from my own experience in the trenches.


Why Design Docs Go Nowhere

After years of watching projects stumble or stall despite “approved” design docs, these are the five failure patterns I see again and again:

  1. Compliance over conviction: Docs get written because the process says so, not because anyone is fighting for the best solution.
  2. Ignoring the audience: Authors assume everyone’s already on board, equally informed, and cares as much as they do.
  3. Dodging hard questions: Tough trade-offs and risks are buried under jargon or skipped entirely.
  4. Cleverness over clarity: Writers want to look smart, not make the real issues obvious.
  5. First-draft laziness: The first version gets shipped; nobody cuts, nobody questions what’s essential.

These aren’t writing problems. They’re thinking problems. So here’s how to think differently about writing your next design doc—starting with making the stakes real.


The Design Doc Gut-Check Checklist

1. Make the Stakes Concrete

  • [ ] Quantify consequences: Spell out what happens if you do nothing—lost revenue, increased tech debt, user churn, missed deadlines. Put real numbers or examples on the pain.
  • [ ] Draw boundaries: Say explicitly what’s out of scope or not being solved.

2. Force Yourself to Surface Risks and Trade-offs

  • [ ] List two alternatives and why you’re not choosing them: If you can’t, you’re not thinking hard enough.
  • [ ] Call out unknowns and riskiest assumptions: Write down what could break, what you don’t know, and what would cause this plan to fail. Make your discomfort visible—don’t let someone else expose it in review.

3. Preempt Objections—Before Anyone Else Can

  • [ ] Write down the three hardest questions you expect in review, and answer them in the doc: Don’t wait for someone to grill you in the meeting.
  • [ ] Assume every reviewer is skeptical: If you were in a rival team’s shoes, would you buy this argument?

4. Ruthlessly Cut and Clarify

  • [ ] Trim 30% from your first draft: If you can’t, ask yourself which section you’d defend in a five-minute elevator pitch—and cut the rest.
  • [ ] One idea per paragraph, one sentence summary: If a paragraph can’t be compressed to a single, clear sentence, rewrite it.
  • [ ] Put calculations, benchmarks, and technical specs in an appendix: Keep your main argument uncluttered and easy to follow.

5. Finish with Commitment and Clarity

  • [ ] Be explicit about next steps, owners, and triggers for a redesign: Don’t end on a shrug—define accountability.
  • [ ] Define success and failure with a metric, timeline, or scenario: No hedging.
  • [ ] Test it on someone who wasn’t in the planning meetings: If they don’t get it, neither will your reviewers.

From Experience

I’ve watched launches stall for weeks because a design doc assumed everyone would “just know” about a scaling bottleneck. Nobody called it out directly, so when things failed in QA, everyone acted surprised. If it’s not written down, it doesn’t exist.

On the other hand, the strongest docs I’ve seen say: “Here’s what we know, here’s what we don’t, and here’s how we’ll handle it if we’re wrong.” They made people nervous in review—but those nerves forced the right conversations and saved months down the line.


The Real Test

Write the doc you’d want to inherit from someone else—when the deadlines are real, the system is groaning, and all the easy assumptions have disappeared. If your design doc doesn’t make you a little uncomfortable to write, it won’t be compelling to read.


Major credit to Grant Slatton’s original article, which covers the mechanics with clarity and precision. This checklist aims to push those fundamentals further, turning them into habits you’ll actually use when it matters.

From Cron Chaos to Centralized Calm

I’ve spent countless evenings hunting down why one of my dozen automated processes failed—digging through server A’s logs, then B’s, then wondering if timezone math on machine C silently swallowed a reminder. If that sounds familiar, check out the original article now: Replacing cron jobs with a centralized task scheduler. It flipped my whole mindset.

Instead of treating each cron script as a black box, the author models every future action as a row in one ScheduledTasks table. Think of it: every job you’d ever schedule lives in a single, queryable place. Because each task records when it’s due, its priority, retries left, and even an expiration window, you immediately know:

  • What went wrong? Was the row created? Did the status flip to “EXECUTING”?
  • When did it fail? Timestamps are part of the schema.
  • Can I retry it? Built-in retry logic based on expectedExecutionTimeInMinutes handles stuck tasks automatically.

And because the table uses deterministic IDs for editable tasks—upserting instead of piling on duplicates—your reminder for “Event X at 3 PM” never spawns two competing jobs if the event gets rescheduled. It just updates the one, single record.

Applying This to Your Own Stack

  1. Model work as data: Start by designing a simple table (or collection) that captures every scheduled action: due time, status, payload, retries, and expiration.
  2. Use one poller, many workers: Replace your multiple cron scripts with a single poller that enqueues due tasks into your favorite queue (SQS, RabbitMQ, etc.), then let specialized consumers pick up and execute.
  3. Unify logging & monitoring: With everything funneled through one scheduler, you gain a centralized dashboard—no more jumping across machines to trace a failure.

By embracing this pattern, I went from juggling eight Node scripts across three servers to maintaining one tiny service. When something breaks now, I head straight to the ScheduledTasks table, filter by status or timestamp, and—boom—I’ve got my starting point. No more haystack.