Why agent prompting isn't chat prompting
In chat, a vague prompt costs you a mediocre paragraph. In an agent, we measured the same vagueness costing a 120-line diff across three files nobody asked it to touch.
The habits that transfer are the ones that hurt
The thing is, that most of the skills you have acquired during a few years of using chat are still very useful. Especially:
Saying things clearly
Providing examples
Saying what format you want the output to have
The thing is that they're not chatbots, so the price is different. In chat, if you ask sth, you get a text back which you can read and take what's useful from, but also ignore what's not. It costs you a mediocre paragraph and 15 seconds of a developer's time, which is really cheap, so in a lot of cases it makes sense to ask and see what it says, so people have a reflex to do it. But here, if you ask sth, the bot already runs a few tool commands before you can even see its summary.
As the Anthropic docs say, unlike a chatbot that answers questions and waits, Claude Code "can read your files, run commands, make changes, and autonomously work through problems while you watch, redirect, or step away entirely." The same vagueness, different prices, so let's have a look:
The same task, two prompts
We created a little Python project (receipt parser — two modules, README, and check.sh with two asserts), ran Claude Code 2.1.193 on it, and gave it these two prompts in two identical copies of the repo:
Prompt A (the typical one):
make the error handling betterPrompt B (the same ask, with a location, a boundary and a check):
In app/parse.py, parse_line raises KeyError when a record's currency code is not in
CURRENCIES. Make it fall back to the raw code as the symbol instead of raising, and add
one case to tests/check.py that covers it. Do not change app/api.py. Then run ./check.sh
and paste its output.And these are the results we got (same model, same project, same day), for vague vs specific:
| Prompt | Turns | Time | Cost | Source files | Lines |
|---|---|---|---|---|---|
| A | 11 | 76s | $0.43 | 3 | +120/-10 |
| B | 8 | 28s | $0.25 | 2 | +3/-2 |
The money difference is obvious, but not that interesting; the code difference is much more instructive:
The prompt A got Claude to:
Create a new public ParseError class which is an exception, extending ValueError
Rewrite app/api.py in a way that handles this error, and inline one previously imported function
Add a few isinstance checks to 3 of the 4 functions in both files
Replace raw.split(" ") with raw.split() in app/parse.py, and add a line comment saying that OCR often returns lines padded with spaces
Expand the tests/check.py file from 2 asserts to 7
All these changes are reasonable — this is what's worth thinking about. Every one of them is defensible, several are genuine improvements, and expanding the tests is arguably sth a good developer would have done anyway.
So what we get from the prompt A is a new public exception in the API, changed behaviour of the parser, and 120 lines to review. From 5 words.
The prompt B is just that prompt A with three things bolted on — a where, a how far, and a done. We come back to those in a minute.
If you were to ask about the same thing in a chat, you'd get a paragraph with advices you'd probably skim through and ignore. But why is that? It's not like the model would be more keen to help here. It's what the harness tells it to do. Let's explore this:
Your prompt is a spec, not a question
Codex CLI ships its model instruction inside the binary. We pulled it out of the 0.146.0 build with strings, and this is what it contains:
Unless the user explicitly asks for a plan, asks a question about the code, is
brainstorming potential solutions, or some other intent that makes it clear that code
should not be written, assume the user wants you to make code changes or run tools to
solve the user's problem. In these cases, it's bad to output your proposed solution in a
message, you should go ahead and actually implement the change.As we said, Codex is just the one we could read it out of. Every tool needs to have its own stance towards the ambiguous input, and the stance that assumes conversation in these cases would be totally useless — as far as we know, they all choose the same default: code by default.
So in other words, the bot reads your message and thinks "that's what we're gonna do". If you wanted to ask a question, you could've said so. It's not like you didn't have an opportunity. If you wrote a sentence, it was an order. This:
"Can we improve the error handling?"
Is not:
"I'm wondering if we can improve the error handling, what do you think?"
It's:
"Let's improve the error handling"
A chat prompt is basically a question you work out together over a few turns. An agent prompt is a ticket you give to a competent person who starts working on it without asking and settles every ambiguity on their own, filling in sensible defaults — not the ones you would have chosen.
Let's have a look at a few habits that work well with chatbots but might not be so effective here:
The chat habits that break
Habit 1: Asking for alternatives
Good in chat — you can always ask for different solutions and pick one, no harm done
Here, it's not clear what you mean by "alternatives" — three descriptions, or one implementation and two paragraphs about the others? If you're looking for a plan rather than code, just say so in the prompt. The Cursor CLI docs use exactly this as their example: "you can use the prompt 'do not write any code' to ensure that the agent won't edit any files."
Better still, use the mode built for it — that's what plan mode is, and it gets its own lesson at the end of this chapter
Habit 2: Saying it again, more emphatically
With chatbots, if you feel like the bot didn't understand sth, saying it again but louder usually works — it's just a text-generation problem
Here, it's different. The bot probably wasn't ignoring you; it had probably formed an assumption at some point and acts on it from now on without checking with you again. What you need here is a different move — that's the Repair prompts lesson in this chapter
Except for one thing: as you can see in the Anthropic docs, emphasis really works in the persistent instruction file. On
CLAUDE.mdthey say "you can tune instructions by adding emphasis (e.g., 'IMPORTANT' or 'YOU MUST') to improve adherence"But that's a different thing than shouting at some point during the session — they describe
CLAUDE.mdas "a special file that Claude reads at the start of every conversation", so it's sth like a standing instruction that's there before the session forms any viewsSaying it louder on turn 9 doesn't change the fact that it formed a view on turn 4 and still holds it
Habit 3: Asking the same question again to get a different answer
If you don't like what the bot says in chat, you can just click "try again". Here, the previous turn already wrote to your disk. There is an undo, but it's worth knowing exactly what yours covers before you rely on it:
Anthropic's own caveat on it: "Checkpoints only track changes made through Claude's file editing tools. Changes made through Bash commands or external processes are not captured. This isn't a replacement for git."
So basically, if your session ran some script, there's a part of undo history that's missing
Habit 4: Pasting code in
In chat, you just copy and paste. Here, it's an option; the bot can open the file itself.
In a separate test we gave it nothing but a path, and it read the file once and answered, so this is definitely sth you could ask it to do. Just remember that pasting comes with its own costs — that's its own lesson later in this chapter
Habit 5: Thinking in messages instead of turns
In chat, you ask a question and get an answer back. Here, a single prompt can run ten tool calls — that's what our vague run did — and the thing you end up having on your disk is the turn, not the message
So just ask for one reviewable thing per turn
Anthropic names the opposite as a failure pattern in its own right: "The kitchen sink session. You start with one task, then ask Claude something unrelated, then go back to the first task. Context is full of irrelevant information."
Habit 6: Treating context as free
In chat, threads aren't long enough for it to really matter. Here, the bot reads files and runs commands faster than you can count them, and:
Anthropic states the consequence plainly: "LLM performance degrades as context fills."
What a chat prompt is missing
These are the three things a chat prompt doesn't have:
Where — file, directory, or symbol. If you don't tell it where to work, it will choose the blast radius on its own, and will be really generous (three files in our tests)
How far — what's not to change, as a sentence. "Do not change app/api.py" is sth a reviewer can check; "Keep it focused" isn't
Done — a command you can run which returns pass or fail. Otherwise the only way for it to know it's done is for it to "look like it", and it's the model that decides if it does. That one is the subject of the next lesson
Prompt B is nothing more than prompt A plus those three. It's not better writing; it's the same request with the parts a spec needs. Here's the conversion on prompts people actually type:
Rewrite one prompt you'd type today
"Fix the flaky test"
No where
No how far
No done
The bot will go looking for both the test and the cause, so "where" is exactly the decision you've handed over.
Rewrite:
Identify tests/test_sync.py::test_retries as failing randomly every fifth run on the last assertion, about timing; make sure it doesn't increase the timeout to force a pass, don't modify files outside of tests/ folder, and show me the failure before proposing any solution
"Let's add some caching in the API layer"
No where
No how far
No done
Caching naturally leads to creating config file and dependency, and decorating everything.
Rewrite:
In-process cache in get_rates() in app/rates.py, keyed on (source, target, day), no dependencies, no new config file, ./check.sh still passes, making sure that if you run it with the same arguments twice, it doesn't reach RATE_TABLE again (with one more assertion just for that)
"Let's tidy this file"
No where
No how far
No done
It's genuinely ambiguous, and it's the one where a plan beats a better prompt. At this point you don't know what you want yet, so asking it to write first is the wrong order.
Rewrite:
Read app/parse.py and list changes you'd make with rationale, from the worst one, without modifying anything
As you can see, in the last case we didn't get more specific about the work at all — we got specific about the output, asking for a list instead of a diff. That's the other lever you have, and it's the one people forget they're allowed to pull.
When vague is still the right move
Just keep in mind that sometimes it's okay to leave sth vague. If you're gonna write a long prompt, know that it costs sth; specificity is not a virtue you should be showing off with. The reason we aim for being specific is not that being vague is irresponsible, but that correcting things here is expensive.
If it's cheap — like when you haven't written anything yet, are just exploring, and genuinely don't know what you want — it's okay to leave it a bit vague. Anthropic says as much in their docs:
Vague prompts can be useful when you're exploring and can afford to course-correct. A prompt like "what would you improve in this file?" can surface things you wouldn't have thought to ask about.
So not "be specific" — "determine which mode you're in and use a tool for it":
Exploring — place the agent somewhere it can't write, and ask an open question
Shipping — spend this extra sentence on where, how far, and done, before the turn, not after the diff