AniUI Academy

Writing a Prompt That Works

Four moves that turn a prompt Claude has to guess at into one it can act on, how to hand over files, images and URLs, and when a vague prompt is the right tool.

9 min read

Claude Code is conversational, and you do not need a perfect prompt to get something useful. You can start rough and refine. But every correction costs a round trip and adds to the context window, and a prompt that lands first time is worth a surprising amount.

The difference between a prompt that works and one that does not is almost never politeness or length. It is information.

The gap you are closing

Claude can see your files and your words. It cannot see the conversation you had in standup, the constraint that is obvious to you, or the reason the previous attempt was reverted. Most disappointing results trace back to context that you had and the agent did not.

So the job of a prompt is not to be well-worded. It is to close that gap.

Four moves

Four patterns cover most of the improvement available. Each one is the same request with information added.

Scope the task

Say which file, which scenario, and any preference about how it is done.

add tests for foo.py
write a test for foo.py covering the edge case where the user is
logged out. avoid mocks.

The first version invites Claude to decide what "tests" means, which usually produces a broad, shallow set. The second one produces the test you wanted.

Point to the source

When you want an answer rather than a change, name where the answer lives.

why does ExecutionFactory have such a weird api?
look through ExecutionFactory's git history and summarise how its
api came to be

The first is an invitation to speculate from the current code. The second sends Claude somewhere the actual answer is recorded.

Reference an existing pattern

This is the highest-value move in an established codebase, because your conventions are not written down anywhere Claude can read them — they are implicit in code you already have.

add a calendar widget
look at how existing widgets are implemented on the home page to
understand the patterns. HotDogWidget.php is a good example. follow
the pattern to implement a new calendar widget that lets the user
select a month and paginate to pick a year. build from scratch
without libraries other than the ones already used.

One named example does more than a paragraph describing your style, and it is faster to type.

Describe the symptom, not the diagnosis

This one is subtle and it matters most when you are wrong.

fix the login bug
users report that login fails after session timeout. check the auth
flow in src/auth/, especially token refresh. write a failing test
that reproduces the issue, then fix it

The improved version still gives a lead — src/auth/, token refresh — but it leads with the observable symptom. If your hunch is wrong, Claude has enough to notice. If you had asserted the cause instead, it would have dutifully fixed something that was not broken.

Handing over the material

Some of what Claude needs is not describable in a sentence. There are four ways to just give it the thing.

  • Reference a file with @. Typing @ in the prompt opens path autocomplete. Writing @src/api/auth.ts is faster than describing where the code lives and saves Claude a search.
  • Paste an image. Copy and paste or drag and drop images straight into the prompt. A screenshot of a broken layout or a design you are matching carries more than a paragraph would.
  • Give a URL. Point Claude at documentation or an API reference and it will fetch it. If you use the same domains often, you can allowlist them through /permissions so you stop being asked.
  • Pipe data in. cat error.log | claude sends file contents directly, which is useful when the thing you want looked at was produced by something else.
claude
  1. You typed: The empty state in @components/inbox/empty.tsx does not match this design. [Image #1] Compare them and list the differences before changing anything.

  2. WhyThree things are handed over at once: the exact file, the target as an image, and a constraint on the order of work. None of that could have been inferred.

  3. Claude ran: Read components/inbox/empty.tsx

  4. Claude replied: Four differences: the icon is 32px rather than 48px, the heading uses body weight, the description sits above the button rather than below it, and the vertical padding is 16px against 32px in the design.

  5. WhyAsking for the list first is a small move with a large effect. You get to disagree with the reading of the design before any code is written, and disagreeing here costs one sentence rather than a revert.

  6. You typed: Right on all four. Fix them.

  7. Claude ran: Edit components/inbox/empty.tsx

  8. Claude replied: Done. All four now match the design.

  9. WhyNotice what is missing from that last line: any evidence. Claude asserts the result rather than showing it. The next lesson is entirely about closing that gap.

A file reference, an image and an ordering constraint in a single prompt.

When vague is the right choice

Being specific is not always correct, and it would be dishonest to teach it as a rule.

A prompt like "what would you improve in this file?" is useful exactly because it is open. It surfaces things you would not have thought to ask about, which is the whole point when you are exploring unfamiliar code or deciding what to do next. Constraining it would defeat it.

The trade is predictable. Vague prompts cost more steering. That is a fine price when you are looking around, and a bad one when you already know what you want and are just being lazy about typing it. The mistake is not vagueness — it is vagueness that you did not choose.

Delegate, do not dictate

One more calibration, because it is easy to overcorrect after reading the section above.

Specific does not mean step-by-step. You are not writing instructions for something that cannot think. Think of it as handing work to a capable colleague: you give them the goal, the constraints and the context, and you let them work out which files to open and which commands to run.

the checkout flow is broken for users with expired cards. the
relevant code is in src/payments/. can you investigate and fix it?

That is specific about the symptom, the scope and the outcome, and silent about the method. Prescribing the method would only limit it to your guess about the approach, and yours is based on less reading than Claude is about to do.

What to take away

A prompt's job is to hand over what Claude cannot find for itself. Four moves cover most of it: scope the task to a file and a scenario, point at the source that holds the answer, reference an existing piece of code to imitate, and describe the symptom you observed rather than asserting the cause. When the material is not a sentence, give the thing itself — a file with @, a pasted screenshot, a URL, or piped-in output. Stay vague on purpose when you are exploring, and stay out of the method even when you are being specific about the goal.

Next: the habit that matters more than any of this, which is making sure something other than your own reading decides whether the work is actually done.

Check yourself

5 questions · pass 4/5 to unlock Giving Claude Something to Verify

up to 50
  1. 1.What is the main problem with the prompt "fix the login bug"?

  2. 2.Which prompt is more likely to produce code that matches your project?

  3. 3.You want Claude to work from a specific file. What does typing @ in the prompt do?

  4. 4.When is a deliberately vague prompt a reasonable choice?

  5. 5.What does "describe the symptom, not the diagnosis" mean in a prompt?

5 left to answer