Skip to content

How to Ask and Give Instructions: Speaking to Claude's Heart

📚 Series Navigation: The previous article [14 Interactive Interface and Shortcuts] taught you where to put your fingers—you are familiar with the cursor, Enter, Esc, and slash commands. This article changes the level: your hands know where to press, but your mouth also needs to know how to speak. For the exact same requirement, whether you say it well or not makes a world of difference in what Claude produces.

To be honest, it might not sound pleasant: when many people first started using Claude Code, they treated it like a search engine.

Imagine this scenario: a function in the project throws an error, and you snap a sentence at it, "Fix this bug," without mentioning which file or what error it is, press Enter, and wait for the show. As a result, it "guesses" a bug it thinks exists, modifies three files, and none of them is the place you actually wanted to fix. You stare at the screen full of diffs, totally confused, and mutter to yourself, "This AI is no good."

Thinking back, you'll understand—it's not the AI that's no good. The problem is not with Claude at all; it's that the sentence was too terrible: the amount of information was almost zero, and it could only rely on its imagination. If it guesses wrong, who can you blame?

Let me put it this way: Claude Code's ceiling is largely locked by your way of asking questions. With the same model and the same project, a person who knows how to ask can get it done in three sentences, while someone who doesn't will redo it five times and get full of anger. Today I will thoroughly explain the universal speaking rule of "how to explain a one-sentence requirement clearly"—I am not teaching you to memorize templates, but teaching you to think clearly about "what exactly Claude needs to know so it doesn't go off track".

After reading this article, you will get:

  • A comparison table of "Bad Question vs Good Question", follow it to modify, and the rework rate will drop immediately
  • Four hardcore mindsets for giving requirements: be specific, provide context, provide acceptance criteria, and make a plan first for complex tasks
  • The correct posture of using @ to reference files and accurately enclose the scope
  • A replicable experiment of "two ways to express the same requirement", seeing the difference with your own eyes

01 Where Exactly Does a Bad Question Fail

Let's unfold the overturning incident above. "Fix this bug"—from Claude's perspective, this sentence is outrageously lacking in information:

  • Which bug? It has to guess which part you are talking about.
  • Which file? It has to search all over the project.
  • What is the expected correct behavior? It doesn't know at all, and can only guess based on "how it generally should be".

Analogy: Guiding a newcomer. If you tell an intern who just joined the company, "Fix that thing," it would be a miracle if he gets it right. Change it to, "Change the color of the login button in the upper right corner of the homepage from gray to brand blue #1A73E8," and he can get it right with his eyes closed. The more specific the instruction, the less the newcomer will deviate; the more vague a sentence you throw, the more he has to guess, and the greater the probability of guessing wrong. Claude is exactly the same.

Look at this set of comparisons repeatedly emphasized in the official documentation (translated into Chinese according to the official meaning):

Scenario❌ Bad Question✅ Good Question
Fix a bug"Fix the login error""User reports login failure after session timeout. Check the authentication flow in src/auth/, focus on token refresh. First write a failing test that can reproduce the problem, then fix it"
Write tests"Add tests for foo.py""Write tests for foo.py, covering the edge cases where the user has logged out, don't use mock"
Ask about code"Why is this crappy api ExecutionFactory designed like this?""Go through the git history of ExecutionFactory, and summarize how its api gradually evolved into what it is today"
Add a feature"Add a calendar component""First see how the existing components on the homepage are implemented, HotDogWidget.php is a good example. Implement a calendar component following this pattern, allowing the user to select months and flip years back and forth. Don't introduce new libraries other than those already in the codebase"

See the trick? Good questions are all doing one thing: feeding the things Claude originally had to guess to it in advance.

💡 One-sentence summary: A bad question fails because "the information gap relies entirely on Claude's imagination", a good question is to explain what it has to guess in advance.

Bad Question vs Good Question: Two ways of asking the exact same requirement

This Before/After picture puts two ways of asking the same requirement side by side: on the left is a vague question, Claude can only guess and ask a bunch of questions back; on the right, the three-piece set of scope, context (@file), and acceptance criteria are fully provided, it hits the target in one go, directly passing the test. The difference is not in Claude, but in how you say it.


02 Mindset 1: Specific > Vague

This is the most important of the four mindsets, bar none.

There is a sentence in the official documentation that is particularly worth remembering, the original text is:

The more precise your instructions, the fewer corrections you will need.

Translated into plain words: Say one more sentence up front, and save three rounds of rework later. You think "saving trouble" is typing a few fewer characters, but the few characters you didn't type will eventually double back as the cost of going back and forth.

How specific should it be? Stuff things in from three dimensions:

First, delineate the scope—which file, which function, which scenario. Don't let it search for a needle in a haystack across the whole project.

Second, clarify the constraints—"don't introduce new libraries", "keep backward compatibility", "don't touch test files". If you don't say it, it will act according to its own preferences, and looking back, it may not suit your wishes.

Third, point out a reference—"follow the pattern of HotDogWidget.php". This trick is the most worry-free in practice: Rather than using language to describe the style you want, it's better to just throw it a ready-made example you are already satisfied with, it will copy it, and it will be pretty close.

There is a counter-intuitive exception here that must be clarified: Vague questioning is not absolutely wrong. When you are in the "exploration stage" and haven't figured out the direction yourself, an open-ended "What do you think can be improved in this file?" can actually bring out some things you completely didn't think of asking. The official original words are "When you are exploring and able to course-correct, vague prompts can be useful". The rule is: Be specific to death when asking for results, and deliberately leave blanks when looking for inspiration.

It's easy to step on this boundary when making a small tool—at first, I just wanted to see how Claude understood that messy code, so I intentionally asked very broadly, and the few improvement points it gave were indeed inspiring; but once I had a clear goal in mind, using vague questions again was purely a waste of rounds, it had to re-guess exactly what you wanted every time.

💡 One-sentence summary: When you want a definite result, be specific to death (scope + constraints + reference), only deliberately leave blanks when actively looking for inspiration.


03 Mindset 2: Provide Context, Don't Let it Guess Blindly

Besides being specific, the second trick is to feed the "materials" directly to its mouth, rather than using your mouth to describe where the "materials" are.

The two highest-frequency actions, remembering them is enough for most cases:

First, use @ to reference files. Type @ in the input box, file path completion will pop up, and after selecting it, the complete contents of this file will be directly stuffed into the conversation—Claude doesn't need to go find it first and then read it, saving a step and avoiding finding the wrong one.

text
Refer to the type definition in @src/types/user.ts, add type annotations to UserService

This is ten thousand times more reliable than "There is a user type file in the project, go find it". The official documentation explicitly states that @ references "read the entire content of the file before responding".

Analogy: USB interface. @ is like plugging a "file USB drive" directly into Claude's workbench—plug and play, the data it wants arrives in one second; if you just say "the data is in the second cabinet of the archives room on the third floor", it still has to run there itself, and running to the wrong place will delay things even more.

Second, paste the error exactly as a whole paragraph. This one is worth developing into muscle memory—when you encounter a traceback, don't summarize "it reported a null pointer", paste the complete stack trace verbatim:

text
Got this error at runtime, help me locate the cause:
TypeError: Cannot read properties of null (reading 'userId')
    at getUserProfile (src/services/user.ts:42:18)
    at async ProfileController.getProfile (src/controllers/profile.ts:15:20)

Why paste the whole paragraph? Because the stack has file names, line numbers, and call chains all over it, Claude can pinpoint it following user.ts:42. If you summarize it, it's equivalent to deleting all these key coordinates, and it has to guess from the beginning again.

The material you want to provide❌ Describe with mouth✅ Feed directly
The contents of a certain file"There is a file handling authentication in the project"@src/auth/session.ts
An error trace"It reported an undefined error"Paste the complete traceback verbatim
A UI issue"The button position is wrong"Directly paste a screenshot (Claude supports reading images)
An API specification"Follow our API specification"@docs/api-spec.md

In a word: Whenever you can "paste", never use "say". Claude reading raw materials is always more accurate than reading your second-hand retelling of the materials.

💡 One-sentence summary: Use @ to push files, and use paste to push errors and screenshots directly to its face, don't let it follow your description to guess.


04 Mindset 3: Give a "Verifiable" Standard of Success

This one is the easiest to overlook, but it's hugely powerful: You have to let Claude know "what it takes to be considered a success", and this standard is best if it can verify it itself.

Why is it crucial? The official documentation hits the underlying logic—

Claude will stop when the work looks done. Without checks it can run, "looks done" is the only available signal, and you become the verification loop: every bug is waiting for you to notice it.

What does this mean? If you don't give a standard, Claude will stop work relying on "it feels about right", the person who really backs up the acceptance is you, and you have to catch every loophole yourself. But once you give it a check that can run a "pass / fail", this loop closes on its own: it finishes the work → runs the check → looks at the results → if it fails, it continues to fix it, you don't need to stare at it at all.

Compare and you will understand:

Task❌ No acceptance criteria✅ Gave verifiable standard
Write function"Implement a function to validate email""Write a validateEmail function. Example cases: user@example.com is true, invalid is false, user@.com is false. Run tests after writing"
Modify UI"Make this dashboard look better""[Paste design mockup] Implement following this, then take a screenshot of the result, compare it with the original mockup, list the differences and fix them"
Fix build"Build failed""The build throws this error: [Paste error]. Fix it and verify the build passes. Solve the root cause, don't suppress the error"

Pay attention to the sentence in the last row, "Solve the root cause, don't suppress the error"—this is a sentence learned after suffering a loss. If you don't write this sentence, it sometimes will just wrap a try/except for convenience, or add a @ts-ignore to eliminate the red line, the error is gone, but the root of the disease is still there.

Advanced gameplay: /goal turns the acceptance standard into "do not finish work until the standard is met". (Requires Claude Code v2.1.139 or higher) Writing the acceptance standard in a normal question is "run this round"; while /goal is to pin the standard as the goal of the whole session—after every round, a small model (Haiku by default) will re-check it according to your conditions, if not achieved, it automatically starts the next round, without returning control to you, until the conditions are met before it stops.

text
/goal all tests in test/auth pass, and the lint step is clean

There is a key detail about using /goal to avoid pitfalls: that small evaluation model only looks at what Claude "displays" in the conversation, it won't run commands or read files itself. So your conditions must be verifiable by Claude's own output—"all test/auth tests pass" is valid because Claude will actually run the tests, and the results are printed in the conversation, so the evaluation model can read them. If you write something like "high code quality" which cannot be seen from the output, it cannot judge it.

💡 One-sentence summary: Give it a check that can run a pass/fail (tests, screenshot comparison, build exit code), the loop closes on its own; if you want it to "not let go until the standard is met", use /goal.


05 Mindset 4: For Complex Tasks, Let It Make a Plan Before Coding

The last one, specifically for "big tasks": When encountering tasks that involve massive changes, spanning multiple files, or you yourself are unsure of the direction, don't let it jump right in and code—let it make a plan first, you glance over it, and then give the green light.

This matter was foreshadowed in Chapter 06 (Plans and Billing), and here we thoroughly explain why. The official documentation's judgment is very crisp:

Letting Claude jump straight to coding can result in code that solves the wrong problem.

To put it plainly, explore first, then plan, finally code—separate "thinking clearly" and "doing it", so as to prevent it from rushing wildly in the wrong direction, and by the time you discover it, a bunch has already been changed.

Analogy: Renovation requires a blueprint before smashing walls. No reliable worker would just grab a hammer and smash a load-bearing wall without a word. He has to confirm with you first "this wall is demolished, wiring goes here, water pipes reroute", and only starts work after you nod. The plan is the blueprint Claude hands you before smashing the wall—if you find something wrong on the blueprint, the cost of changing a few strokes is much lower than reworking after the wall is smashed.

How to let it produce a blueprint first? Two ways:

Method 1, explicitly state "don't modify yet" in words. Just add a limitation in a normal conversation:

text
I want to add a dark mode toggle to the settings page. First tell me which files need to be touched and what the idea of the changes is,
don't modify any code in this step.

Method 2, switch to Plan Mode. This is Claude Code's dedicated "read-only planning" gear—it will read files, propose solutions, but it won't land a single word before you approve. How to enter: press Shift + Tab in the conversation (press once or twice to cycle to Plan Mode), the mode will rotate among default → acceptEdits → plan. If you just want a certain prompt to run in Plan Mode without switching the whole session, add the /plan prefix before that message.

However, the official guide also gives a very practical reminder, don't go to extremes and plan everything:

For well-defined tasks with small fixes (like fixing a typo, adding a log line, or renaming a variable), ask Claude to execute directly. Planning is most useful when you are unsure about the approach, the change modifies multiple files, or you are unfamiliar with the code being modified. If you can describe the diff in one sentence, skip planning.

The most practical native method is just this last half-sentence: "Can you explain in one sentence what it looks like after the change?" If yes, just do it; if you get stuck, it means the job is complex enough, let it make a plan first. Going through Plan Mode even to fix a typo is purely making extra drama for yourself.

💡 One-sentence summary: Not sure / spanning multiple files / unfamiliar code → let it make a plan first (a sentence "don't modify yet" or Shift+Tab to enter Plan Mode); for small jobs where you can explain the diff in one sentence, just do it.


06 Hands-on: Same Requirement, Two Ways of Saying It Show the Truth

Just listening to theories doesn't quench your thirst, let's do a small experiment where you can see the gap with your own eyes. Just prepare a three-line toy file, it doesn't depend on any of your existing projects.

Step 1: Build a toy file with a "pitfall" (Mac / Linux)

bash
mkdir prompt-demo
cd prompt-demo
echo 'def average(nums):
    return sum(nums) / len(nums)' > stats.py

Windows users: Type mkdir prompt-demo, cd prompt-demo as usual, create stats.py with Notepad and paste those two lines in.

This function has a pitfall: when passing an empty list [], len(nums) is 0, which triggers a "division by zero" crash. We will use it as our testbed.

Step 2: Start Claude in the project directory

bash
claude

Expectation: The welcome screen appears, with an input box at the bottom.

Step 3: Use a "bad question" first to feel how it guesses

text
@stats.py help me tweak this function

Expectation: Claude will most likely "guess" what you want to do—maybe add type annotations, maybe add docstrings, but it doesn't know you really care about that empty list crash, the direction depends purely on luck. This is the cost of vague questioning: It is making decisions for you.

Step 4: Change to a "good question" — specific + context + acceptance standard, all three on

text
There is a bug in the average function in @stats.py: it crashes due to division by zero when an empty list is passed in.
The expected behavior is to return 0 for an empty list.
Help me fix it, and add a test: average([]) should return 0, average([2, 4]) should return 3.
Run the test once after writing it to confirm it passes.

Expectation: This time Claude's action chain is crystal clear—locate the empty list branch → add the logic to check for empty and return 0 → write out the two test cases you named → actually go run the tests → display the passed result to you. It no longer guesses what you want, because you have completely nailed down "where to fix, how to change it, and what counts as success."

Step 5: Exit, and see if the changes have landed

bash
cat stats.py

(Windows PowerShell uses type stats.py)

Expectation: Logic to check for an empty list (similar to if not nums: return 0) appears in stats.py. It matches your requirement from step 4 = you have caught the feel of "explaining things clearly".

Putting the two questions side by side, the gap is obvious at a glance:

Step 3 ❌ Bad QuestionStep 4 ✅ Good Question
Where to changeDidn't say, it guessed across the fileNamed the average function
What to change toDidn't say, let it improviseEmpty list returns 0, nailed it down
What counts as successNo standard, it stops when it "feels" doneTwo test cases + run once to verify
Your experienceStaring at diff wondering "this isn't what I wanted"It acts according to your script, gets it right the first time

💡 One-sentence summary: Same file, same bug, a bad question lets Claude make decisions for you, a good question nails down "where to fix, how to change it, what counts as success"—running these two steps yourself, the gap is more intuitive than reading theories ten times.


07 Summary

This article talked about one thing: How to phrase a one-sentence requirement so Claude can catch it accurately.

Wrap up with the four mindsets, if you can't memorize them, remember this table:

MindsetOne SentenceHow to Implement
Specific > VagueState scope + constraints + reference clearly"Modify average, don't use new libraries, follow the pattern of xxx"
Provide ContextNever use your mouth if you can paste@file, paste entire tracebacks, paste screenshots
Give Acceptance StandardLet it verify "if it succeeded" itselfGive test cases, ask it to run them; use /goal for tougher ones
Plan FirstLook at the blueprint before smashing walls for big tasksOne sentence "don't modify yet" or Shift+Tab into Plan Mode

You should now be able to: Translate a vague "help me tweak this" into a requirement Claude can truly catch—delineate the scope accurately, feed sufficient context, give a verifiable standard of success, and let it make a plan first for complex ones. This set of speaking rules is your "internal strength" for all future operations using Claude Code—no matter how fancy the features, if the input question is terrible, the output work won't be good either.

Thinking backward, I'll leave you a question: Since "explaining things clearly" is so important, for some rules (like "never introduce new libraries in this project", "tests always go in tests/ directory"), do you have to repeat them every time? Is there a way to let Claude "remember", to save repeating every day?


The next article is 16 "Common Workflows"—this article taught the universal rules of "how to explain a sentence clearly", and the next one lands it on the four highest-frequency specific jobs: exploring unfamiliar codebases, fixing bugs, refactoring, and writing tests. For each category, I'll give you a standard playbook you can copy. You have the rules, now it's time to see the moves.