ikkachar.dev
All writing
6 min read

Write the done-condition, not the prompt

How I write prompts, audited against 138 of my own. Four habits, one rule, and the single edit that fixes most of them.

A wall of dark brushed-metal gauges, every dial unlit and unread, with a single gauge glowing electric violet as it registers an actual number.

This is how I write prompts, checked against five weeks of actually doing it. 138 goals, eleven projects. I pulled the logs before writing so the advice would have to survive contact with my own habits, and mostly it didn't: counting every "make sure" and "verify" as a done-condition, 73% of them never said what done meant. Read strictly, 86%.

So take the habits below as tested rather than recommended. Some survived. The rest need one edit, and it's the same edit every time.

Start with /goal, because it makes you write the ending first

/goal keeps an agent working until a condition holds. The real value sits upstream of the model: to write the condition you have to decide what finished looks like before you're invested in whatever the agent hands back. That's a thinking tool, not a prompting trick.

The Claude Code team's own framing, 6 July 2026. An evaluator model checks your condition, so you're not the one deciding when it's done.

It rewards a numbered definition of done. Three of my 138 goals have one, and all three hold up, because "builds, lints, and type-checks" are commands. The machine decides.

One caveat the docs are honest about, and it shapes everything below: the evaluator is a fresh model, but it cannot run your tests. It reads Claude's account of having run them. I wrote three thousand words about why that matters.

Put the standing rules in CLAUDE.md, not in the goal

Here is what the audit changed my mind about. I assumed the 86% were sloppy. They aren't. My median session-opening goal is 190 characters and it still lands, because the gates are already standing somewhere else: "Always type-check and lint the code." "Never use any types." Those apply to all 138 goals without appearing in one of them.

What I type

Always type-check and lint the code

Never use `any` types

Use `pnpm` only

Read the guide before writing code

let's add the newsletter double opt-in flow

Everything, every time.

CLAUDE.md

Always type-check and lint the code

Never use `any` types

Use `pnpm` only

Read the guide before writing code

Standing over every goal at once.

The done-conditions did not vanish. They moved somewhere they only had to be written once.

The done-condition didn't disappear, it got factored out, the way you'd factor a constant out of a loop. Write the standing gates once, in persistent context, and let each goal carry only what couldn't have been written yesterday. The obvious objection dies on the data: session-openers can't inherit anything, and 85 of 100 of them still name no done-condition.

Say /workflow only when you can name the number

26 of my goals reach for /workflow. Three pair it with a number, three hand it a list of links, and twenty name neither.

It helps to know what you're actually asking for. A workflow is a script, and this is the shape of the one I reach for most: paste some links, read them the same way, check what they claim.

export const meta = {
  name: 'research-links',
  description: 'Read a list of links, check what they claim',
  phases: [{ title: 'Read' }, { title: 'Check' }],
}
 
phase('Read')
 
const checked = await pipeline(
  args.links,
  link => agent(`Read ${link}. Quote every claim.`, { schema: CLAIMS }),
  claims => parallel(claims.map(c => () =>
    agent(`Try to refute: ${c.text}`, { phase: 'Check', schema: VERDICT }))),
)
 
log(`${checked.flat().length} claims checked`)
return checked.flat().filter(v => !v.refuted)

Look at the highlighted names. I define none of them. agent, pipeline, parallel, phase, args and log are nowhere in the file, because the file isn't the program. It gets dropped into a runtime that supplies them, and that runtime will happily run agent() a hundred times over, concurrently, against links I never enumerated.

It cuts the other way too. Date.now() and Math.random() are gone in here, because a workflow has to be resumable and those would make two runs disagree. The scope isn't yours in either direction.

Which is the appeal, and the trap. The harness hands you fan-out for free. It does not hand you a stopping condition, and twenty of my 26 took the free part and skipped the rest. That's like hiring an inspector and never telling them what passes. The tool was never the point. The number was.

Same shape in the newest toy. Anthropic's advisor tool pairs a fast executor with a smarter advisor, Fable 5 or Mythos 5, mid-task. As of mid-July 2026 it's an API beta rather than a slash command, and I haven't used it in anger, so take this as reading rather than experience. But watch the arrow.

An advisor injects a better plan. It never tells you you're done.

Reach for Chrome past a 403, and once for something better

Nine of my goals mention Chrome. Most are scraping, because the good primary sources 403 an agent and a real browser walks through. That habit earns its reputation, and it is the boring one.

The interesting one happened once: "test it out in chrome at http://localhost:2800/chat until it all works perfect". That is the only goal where I turned "looks right" into something a machine could look at. Then "works perfect" handed it straight back to the model.

use /workflow to validate the current level according your criteria and make sure we're at over 80%

  1. The goal names a number. 80%. It looks like a gate.
  2. according your criteria hands the model the ruler.
  3. The model decides what counts, then reports the score.

Over 80%. Nothing measured it.

Both goals end green. Both name 80. Only one of them was ever checked.

Which is the rule underneath all of it. Of my 138 goals, four name a number, and exactly one of those four names a number that exists before the model has an opinion.

138goals, five weeks, eleven projects

Every /goal I typed. One dot each.

  • 138 goals, five weeks, eleven projects
  • 20 said what done meant
  • 4 named an actual number
  • 1 let a tool produce the number

The one is "until we get 80% coverage". A test runner emits that figure whether or not anyone likes it. The other three only look like it: "more than 95% equality" has a model comparing screenshots, "98% or more for all" never says of what or counted by whom, and "over 80% according your criteria" names a number and hands over the ruler in three words.

The question that separates them

Not "does the done-condition have a number in it?" but "who produces the number?" If the answer is the model, you don't have a gate. You have a mood.

The contract fits in five lines

Objective:      what becomes true
Done-condition: until <X>
Grounded check: the command that produces X, and who runs it
Boundary:       what it may not touch
Stop:           the cap when X never arrives

Line three is the one everybody skips, including me, 137 times out of 138. It is the only line that asks a question you can get wrong.

So here are six of mine run against it. Two hold up, and they are the two I would have described if you had asked me cold: a numbered definition of done, and Chrome as a way past a 403. The other four are one edit away.

Six of my 138, scored against the contract.
  • /goal + definition of donegroundedexcerpt of 1943 chars

    Migrate the current Webflow-hosted juma.ai marketing site into the Juma monorepo [...] Definition of done: 1. `apps/website` builds, lints, type-checks, and runs locally via the monorepo's task runner [...]

    One of only three goals in 138 with a numbered definition of done, and it holds up. Builds, lints, and type-checks are commands. The machine decides.

    Rewrite: Nothing. This is the shape.

  • /goal + a number from a toolgrounded

    Bring the code coverage and unit tests for the whole web app and shared packages until we get 80% coverage.

    107 characters, and the only goal in the corpus whose number exists before the model has an opinion. The test runner emits it.

    Rewrite: Nothing. Short is not the same as unspecified.

  • /workflow + thresholdself-gradedexcerpt of 401 chars

    migrate juma.ai to @apps/website/ using a /workflow that will compare them with source/components/styles/screenshots and /loop until we've got more than 95% equality

    Names a number, names the inputs, and still never says who computes equality. A model comparing screenshots is a model with an opinion.

    Rewrite: Name the comparator: until a pixel-diff script reports under 5% differing pixels.

  • /workflow + criteriaself-graded

    create test cases and eval system to validate the correctness and ux of the kernel repl. use /workflow to validate the current level according your criteria and make sure we're at over 80%

    The sharpest failure in my logs. It names a number and a tool, and hands the model the ruler in three words.

    Rewrite: Delete "according your criteria". Say: until the eval suite scores over 80% and prints the score.

  • Chrome as the checkself-graded

    also add test cases how to trigger it and test it out in chrome at http://localhost:2800/chat until it all works perfect

    The only goal where Chrome turns "looks right" into something a machine can look at. Then "works perfect" hands it straight back to the model.

    Rewrite: Keep the browser, cut the vibe: until the chat renders a reply and the console logs no errors.

  • Chrome past a 403no done-conditionexcerpt of 889 chars

    let's scrape the webflow variables, fonts, components, radius, typography, colors, custom code, spacings, html structures and other styles from webflow [...]

    The habit I'd have told you about: the source blocks agents, a real browser walks through. Genuinely useful, and it names no stopping point at all.

    Rewrite: Add one: until every token in the list has a value written to tokens.json.

Five weeks, one person, eleven projects. Not a base rate, and half my until clauses are the same "fix findings until the review is happy" reflex copied around. But the direction is not subtle, and I'd bet your logs look like mine.

Write the ending first. Then name who checks it.

Did this resonate?

Get new essays by email

Field notes on AI-native products, straight to your inbox. No spam, unsubscribe any time.