Beyond Vibe Coding Patterns for Building Real Software with Claude Code

Correct by Design

On this page

Draft v0. A candidate spine for the book — captured from recent LinkedIn discussions. Living collection; anecdotes go at the bottom.


The commodity insight (start here, then leave it behind)

“Validate the AI’s output.” Everyone is saying this. It is necessary and it is true — but it is table stakes, not a contribution. A book whose headline insight is “check the output” has said nothing the reader couldn’t get anywhere.

The novel thesis

Wherever a task can be expressed as deterministic code, convert it — so the AI no longer performs that task at runtime, and the result is correct by design. There is then nothing to validate, because there is no non-deterministic step left to go wrong.

The reflex to teach is not “trust less, check more.” It is: look for the parts of the work that don’t need a model at all, and design the model out of them.

This applies to every use-case, not just your own dev workflow:

  • The product you ship — don’t call an LLM at run time to decide what a parser, rule, lookup, or function could compute.
  • Your dev/automation workflow — the same: a script that always works beats a prompt that usually does.

It is one principle applied everywhere, not two separate tricks.

Two orthogonal axes — don’t fuse them

  1. Deterministic vs. non-deterministicis the task done by code or by an agent? This is the axis this chapter is about. Moving a task from the agent to code removes the uncertainty at the source.
  2. Gates vs. guidelinesfor an agent you’ve chosen to keep, how do you constrain it? Gates are binding (tests, type checks, schema validation, a CLI that refuses bad input); guidelines are advisory (a prompt, a CLAUDE.md “please always…”) and the model can ignore them. This axis belongs to the Control Stack (the managing-your-AI part), not here.

The point of separating them: deterministic code needs neither a gate nor a guideline — it just runs. Gates only matter in the residual zone you couldn’t make deterministic. Confusing “force determinism with gates” (constraining an agent) with “it’s already deterministic code” (no agent involved) muddles the whole idea.

The maturity ladder (“how you level up”)

This is framed as how you get really good at building with AI, not a mandate:

  1. Naive — AI does everything; you trust the output.
  2. Gated non-determinism — AI still does the work, but you wrap it in deterministic gates that validate or force-correct. This is the next level after naive, and it deserves thorough teaching (it’s where most readers should get to first).
  3. Maximal determinism — you keep finding tasks that don’t need the model and convert them to deterministic code. Correct by design; the non-deterministic surface keeps shrinking. This is the north star.

Most of the practical teaching lives at level 2 (gates — see the Control Stack chapter). The distinctive argument of the book is to keep climbing toward level 3.

Drafting note — forward reference. This chapter comes before the gates mechanics (Control Stack, Ch 7), so it states level 3 as the aspiration before the reader has built level 2. That’s intentional (principle first, mechanics after), but it can read backwards if unsignposted. When drafting prose, signpost it explicitly — e.g. “the practical work of constraining what you couldn’t design out comes next, in the Control Stack chapter.” Watch while writing: if the naive → gated → deterministic ladder turns out to be the book’s actual spine rather than a device inside this chapter, revisit ordering across the whole middle.

The unit move: get Claude to write the code, not do the task

This is the building block the whole chapter rests on, and it comes before the CLI chapter (Ch 8) because a CLI is just what these accrete into. Teach this first; the CLI is the reuse story layered on top.

The atomic action behind “design the model out” is small and repeatable: when a task can be expressed as a rule, ask Claude to write code that performs it — then run the code — instead of asking Claude to perform the task directly in the conversation.

The distinction is easy to miss because both start with a prompt. The difference is what you ask for:

  • Just do the thing: “Rename these 300 photos to YYYY-MM-DD-###.jpg based on when they were taken.” Claude works through them in-context — reading, deciding, calling a tool per file. The work is a string of individual non-deterministic judgments.
  • Write the code that does the thing: “Write a script that reads each photo’s EXIF date and renames it to YYYY-MM-DD-###.jpg.” Claude produces a script; the script renames all 300 identically. The judgment happened once, in code you can read, and the execution is deterministic.

Why this is worth it even for a one-off. The instinct is “it’s just this once, why bother with a script?” But the payoff isn’t only reuse — it’s two things reuse is separate from:

  1. Correct by construction across all items. A script applies the same rule to item 1 and item 300. In-context handling drifts, silently skips, or mis-handles the awkward ones in the middle — and you often can’t tell which. Over many items, the script is more correct the first time, not just the second.
  2. The rule becomes inspectable. You (or a developer you hand it to) can see the transformation — regex, sort order, the date format — instead of trusting Claude’s private reading of the input. You review the rule once instead of spot-checking 300 outputs.

Reuse is a third reason, and it’s what tips borderline cases: if you suspect you’ll do it again, that settles it. But it isn’t required — volume and inspectability alone often justify code for a genuine one-off.

A moving target worth naming. Newer Claude models increasingly reach for code instinctively on straightforward cases — asked to dedupe a list, they’ll often write the one-liner unprompted. But on more elaborate tasks they still default to doing the work in-context. So the reader’s job isn’t to police every task; it’s to notice the elaborate cases where Claude didn’t reach for code and nudge it to — “write a script for this instead.” That noticing is the trained-eye skill this book is about; the model handles the easy calls, you catch the ones it doesn’t.

When it makes sense (and when to just prompt)

The dividing line is the same determinism axis this chapter opened with: code is for the part that’s a rule; the prompt is for the part that’s judgment.

Ask Claude to write code when the task is —

  • Rule-expressible — you can state the transformation (“rename by date,” “extract every email,” “flag rows over $500”). If you can say the rule, code can encode it.
  • Repeated across many items — the per-item cost of in-context handling (tokens, drift, silent skips) multiplies; a script pays that cost once.
  • Exactly repeatable — same input must give the same output (audits, reports you’ll compare over time, anything a difference would matter in).
  • Over a large input — bigger than fits comfortably in context, or where having Claude read all of it is wasteful or lossy.

Just prompt Claude directly when the task —

  • Needs judgment that isn’t a rule — “rewrite this to sound warmer,” “is this bug a duplicate of that one,” “summarize this thread.” No script captures it; this is exactly the residual the model is for.
  • Is a true one-off over just a few items — writing and debugging a script has fixed overhead; below some small N, just doing it is cheaper.
  • Has a fuzzy or still-being-discovered rule — you don’t yet know the transformation precisely, or you’re exploring what you even want. (Once the rule firms up, then convert it.)

Three worked examples

  1. Bulk file operation (non-dev, one-off, high volume). “Organize my Downloads folder: move every file into a subfolder named for its year and month based on when it was created.” Just do it → Claude churns file-by-file, may miss some, can’t be re-run cleanly if interrupted. Write the code → a script sorts all of them by the same rule, you can dry-run it first, and re-running it is safe. Worth a script even though you’ll (claim to) do it once.

  2. Data extraction/transformation (both audiences, correctness-critical). “Pull every email address out of this 5,000-row CSV export, drop duplicates, and give me a clean mailing list.” Just do it → Claude reads the file into context (token cost, truncation risk) and eyeballs the extraction — it may miss malformed rows or invent plausible-looking addresses. Write the code → a regex-plus-dedupe script extracts exactly what’s there, on any file size, and you can see the matching rule instead of trusting a reading you can’t audit.

  3. Repeatable check/report (the “I’ll do it again” case). “Check all the markdown files in my book repo for internal links that point to files that don’t exist.” Just do it → Claude reads files and guesses; on 40 files it will plausibly miss one, and next month it’ll count differently. Write the code → a link-checker parses every link and verifies each target, gives the same answer every run, and becomes something you run before every commit. This is the example that most obviously wants to graduate into the CLI (Ch 8) — which is the bridge: the scripts you keep asking Claude to write are exactly the ones that accrete into a CLI command.


Why this is durable

It doesn’t depend on any model’s current quirks. Models improve; non-determinism doesn’t disappear. “Move work out of the model and into deterministic code wherever you can” stays true regardless of model or year.

Open questions

  • How hard to push the product-architecture half for a non-dev audience who may want AI in their product? Verdict so far: not super hard — present it as leveling up, not as a rule. Teach gates well first; hold up determinism as the aspiration.
  • Worked example pair: a feature built the gated-agent way vs. the designed-out-to-code way.

Anecdotes / sources

  • (LinkedIn discussions, 2026-06 — capture the specific threads and exchanges here.)

Found something wrong, unclear, or plainly disagreeable? Open an issue