Your First Prompt: How to Give Claude Clear, Actionable Instructions

Learn how to write better Claude Code prompts by being specific, providing relevant file context, and keeping each request focused. This tutorial demonstrates these techniques by refactoring a React workout form with React Hook Form and Zod.

How to Write Better Claude Code Prompts: Be Specific, Add Context, and Stay Concise

Claude Code can generate a surprising amount of working code from a short prompt. However, the quality of its output depends heavily on the quality of the instructions you provide.

If your prompt is vague or open-ended, Claude has to fill in the missing details and make assumptions about what you want. Sometimes those assumptions produce a good starting point. Other times, the result works but does not follow your preferred architecture, libraries, or coding conventions.

In this tutorial, we’ll continue working with the React workout logger from the previous lesson. We’ll initialize a Git repository, save the current version of the project, and then improve one of the generated components with a focused Claude Code prompt.

Along the way, you’ll learn three practical prompting rules:

  1. Be specific.
  2. Give context up front.
  3. Be concise.

We’ll apply those rules by asking Claude Code to refactor the workout form to use React Hook Form and Zod.

Open the Project Directory

Start in the terminal and list the contents of your current directory:

ls

You should see the workout-log project created in the previous lesson. Move into it before running any project-specific commands:

cd workout-log

List the directory contents again to confirm that you are in the correct location:

ls

You should now see files such as package.json, vite.config.ts, and the src directory.

If you use Visual Studio Code and have its command-line launcher installed, open the current folder with:

code .

You can also open the folder manually from your preferred editor.

Always confirm your working directory before initializing Git, installing dependencies, or asking a coding agent to modify files. Running a command from the wrong directory can affect the wrong project.

Initialize a Git Repository

Before making more AI-generated changes, create a clean checkpoint with Git. This gives you a record of the current project and makes it much easier to inspect or undo future changes.

Run:

git init

If Claude Code is already open, you can run a one-off shell command through its Bash mode by prefixing the command with an exclamation point:

!git init

You can also use the integrated terminal normally. The result is the same: Git initializes a repository in the current project directory.

After initialization, Visual Studio Code’s Source Control panel should display the project’s untracked files. Review them before staging anything. In particular, confirm that generated dependencies, environment files, secrets, and editor-specific files are excluded through .gitignore when appropriate.

For a new Vite project, the generated .gitignore should already exclude common files such as node_modules.

Once you have reviewed the files, stage them from the Source Control panel or run:

git add .

Then create the first commit:

git commit -m "feat: add initial workout logger"

Some versions of Visual Studio Code can generate a proposed commit message from the staged changes. If you use that feature, read the message before accepting it. A good commit message should accurately summarize the change without adding claims that the code does not support.

At this point, you have a clean baseline. If the next refactor causes a problem, Git will show exactly what changed.

Why Prompt Quality Matters

In the previous lesson, we gave Claude Code a broad request to scaffold an entire workout logger. It produced a functional application in roughly ten minutes, including:

  • A workout table
  • An add-workout dialog
  • Reusable UI components
  • Tailwind CSS and shadcn/ui styling
  • Local state and basic workout-entry behavior

That was an impressive result, but the prompt left many implementation decisions unspecified. Claude therefore selected its own approach.

This is the central principle to remember:

The more ambiguity your prompt contains, the more decisions you delegate to the model.

Delegating decisions is not always bad. Plan mode is useful when you want Claude to explore options or help fill in missing details. But when you already have a technical preference, state it clearly instead of hoping the model chooses it.

Rule 1: Be Specific

Avoid prompts that describe only a general outcome.

A vague request might say:

Add a form.

Claude still has to determine:

  • Which file should contain the form
  • What fields it needs
  • Which values are required
  • How state should be managed
  • How validation should work
  • What should happen after submission
  • Which libraries should be used

A more useful prompt explains the behavior and constraints:

Update the add-workout dialog to use React Hook Form for form state
and Zod for validation. The form should include exercise name, sets,
reps, and weight. All fields are required. Sets and reps must be
positive integers, and weight must be a non-negative number. Preserve
the component's existing appearance and submission behavior.

This prompt reduces ambiguity without dictating every line of implementation.

When you know the libraries you want, name them. For this component, React Hook Form can manage the form state while Zod defines and validates the accepted data shape.

Rule 2: Give Context Up Front

Claude Code needs to understand where a change belongs and which existing code matters. Give that context at the beginning of the prompt.

One of the easiest ways to do this is to reference the relevant file with the @ symbol. In Claude Code, begin typing @ followed by the filename, then select the correct file from the suggestions.

For example:

@src/components/add-workout-dialog.tsx

Update this component to use React Hook Form for form state and Zod
for validation. Preserve its public props, styling, and existing
submission behavior.

The exact path in your project may be different, so select the real file rather than copying this example blindly.

Referencing a file has two advantages:

  1. Claude knows exactly which implementation you want it to inspect.
  2. It may spend less time and context searching unrelated parts of the project.

You can also provide other relevant context up front, such as:

  • The library or framework version
  • A related type or schema file
  • An existing component to imitate
  • A rule against changing the public API
  • A requirement to preserve styling
  • Project-specific validation conventions

The goal is to identify the boundaries of the task before asking Claude to act.

Rule 3: Be Concise

A good implementation prompt is focused. Include the information needed to complete the task, but avoid mixing several unrelated features into one request.

For example, do not combine a form refactor, database migration, visual redesign, authentication change, and test-suite rewrite in a single prompt. Large prompts produce larger diffs, which are harder to understand and review.

Instead, make one coherent change at a time:

@src/components/add-workout-dialog.tsx

Refactor this component to use React Hook Form and Zod. Keep the
existing UI and onSubmit contract unchanged. Add inline validation
messages and reset the form after a successful submission. Install
only the dependencies required for this refactor.

This task is specific enough that you generally do not need plan mode. Plan mode is more useful when a feature spans multiple systems or when important design decisions remain unresolved.

Inspect the Existing Workout Form

Before asking Claude to refactor the component, inspect the generated code yourself.

In the original version, the add-workout dialog uses React state and native form handling directly. It may contain:

  • Individual state variables for field values
  • A custom validation function
  • A manual submit handler
  • Repetitive parsing and error-handling logic

There is nothing inherently wrong with using the platform’s built-in form behavior. For a small form, that can be perfectly reasonable. However, if the rest of your application standardizes on React Hook Form and Zod, refactoring this component can make the code more consistent and easier to extend.

React Hook Form centralizes form state and submission handling. Zod lets you define validation rules in a schema that can also provide an inferred TypeScript type.

Ask Claude Code to Refactor the Component

Reference the add-workout dialog file and submit a focused prompt:

@src/components/add-workout-dialog.tsx

Update the add-workout dialog to use React Hook Form for form state
and Zod for validation. Use the Zod resolver to connect the schema to
React Hook Form. Preserve the existing component props, appearance,
and behavior. Show a validation message next to each invalid field,
and reset the form after a successful submission.

Claude may ask for permission to install packages such as:

npm install react-hook-form zod @hookform/resolvers

Review the command before approving it. Confirm that the package names are correct and that the dependencies are appropriate for your project.

Claude can then update the component by:

  • Defining a Zod schema for the workout fields
  • Inferring a TypeScript form type from the schema
  • Initializing useForm
  • Connecting the schema through zodResolver
  • Registering the form inputs
  • Displaying field-level validation errors
  • Replacing manual validation and redundant state
  • Resetting the form after a successful submission

Review Every Proposed Change

Claude Code shows the changes it wants to make and lets you accept or reject them. Do not approve a change merely because the generated application appears to work.

Review whether:

  • The schema matches your business rules
  • Numeric strings are converted safely
  • Sets and reps accept only positive integers
  • Weight permits the values your app supports, including bodyweight exercises if applicable
  • Existing props and callbacks remain compatible
  • The form resets only after a successful submission
  • Validation messages are accessible
  • No unrelated files were changed
  • The new dependencies were added correctly

If something is wrong, reject the change or provide a follow-up instruction. Claude Code also allows you to add more detail when responding to a proposed edit.

For example:

Keep the current UI, but change the weight rule so that zero is valid
for bodyweight exercises. Do not modify the workout table.

AI-assisted development works best as an iterative review process, not a single approval step.

Run and Test the Application

Start the Vite development server:

npm run dev

Open the local URL printed in the terminal. Vite supports hot module replacement, so the page should update automatically after the component changes. If the interface appears stale, perform a browser refresh.

Test a valid entry, such as:

  • Exercise: Push-ups
  • Sets: 4
  • Reps: 10
  • Weight: 160

Confirm that the entry is added to the workout table and can still be removed.

Then test invalid inputs:

  • Submit an empty exercise name
  • Enter zero or a negative value for sets
  • Enter a decimal value for reps
  • Enter invalid text in a numeric field

Verify that each invalid value produces the intended validation message and does not create a workout entry.

Finally, run the project’s quality checks:

npm run lint
npm run build

If the project includes automated tests, run those as well.

Functional Code vs. Maintainable Code

The original workout form already worked. The refactor was not intended to create a visible new feature; it was intended to improve the internal structure and enforce consistent validation.

That distinction matters. As an application grows, maintainability becomes increasingly important. Clean code, predictable patterns, and well-supported libraries can make future changes easier—but adding a library is not automatically an improvement. The benefit should justify the additional dependency and abstraction.

In this case, React Hook Form and Zod are useful when the application will contain multiple forms, shared validation rules, or more complex form behavior. For a tiny, permanent form, the native approach may remain sufficient.

The developer must make that judgment. Claude can implement the decision, but it should not make every architectural choice by default.

A Repeatable Prompting Formula

For focused implementation tasks, use this structure:

@[relevant file]

Change: [the exact outcome you want]
Requirements: [behavior, fields, and validation rules]
Constraints: [what must remain unchanged]
Tools: [required libraries or project patterns]
Verification: [how to prove the change works]

Applied to this lesson:

@src/components/add-workout-dialog.tsx

Change: Refactor the workout form to use React Hook Form and Zod.
Requirements: Validate exercise name, sets, reps, and weight; display
inline errors; reset after a successful submission.
Constraints: Preserve the current props, appearance, and submission
behavior. Do not change the workout table.
Tools: react-hook-form, zod, and @hookform/resolvers.
Verification: Run lint and build, then confirm valid submissions work
and invalid values display errors.

This format gives Claude enough direction to act while keeping the request compact and reviewable.

Final Takeaway

Effective Claude Code prompts do not need to be extremely long. They need to remove the ambiguity that matters.

Remember the three rules:

  1. Be specific: Describe the desired behavior, data, validation, and technical requirements.
  2. Give context up front: Reference the relevant files and state important constraints before asking for changes.
  3. Be concise: Keep each request focused so the resulting code is easier to understand, test, and review.

The focused form refactor took far less time than the original broad application scaffold because Claude knew exactly where to work and which tools to use. That is the real advantage of writing better prompts: not merely faster code generation, but smaller assumptions, cleaner diffs, and more control over the final codebase.