Working with Claude Code Deel 2 van 5
Working with Claude Code: Effective Steering
Gemini/Vic Boomer illustratie

Working with Claude Code: Effective Steering

The difference between communicating intent and dictating steps determines your results. Here's how to steer Claude Code.

Tom Notton
· 8 min read

You open Claude Code, type “make a login page,” and get something back. It works, technically. But it follows none of your existing patterns. It uses a different CSS approach than the rest of your app. The error handling deviates. The naming is inconsistent. You can fix it — but that takes about as much time as writing it yourself.

The problem isn’t the model. It’s the prompt.

Intent versus instruction

There are two ways to steer Claude Code. The first is instruction: telling the model step by step what to do. The second is intent: describing what you want to achieve and why, and letting the model determine the execution.

Instruction looks like this:

> Create a file src/pages/Login.tsx.
> Import React and useState.
> Create a component with a form.
> Add two input fields: email and password.
> Add a submit handler that POSTs to /api/auth/login.

Intent looks like this:

> Add a login page. Use the same component structure as the
> existing pages in src/pages/. The page should accept email and
> password and authenticate via the existing auth API in src/api/.
> Follow the error-handling patterns from src/components/forms/.

The difference is substantial. With instruction, you decide the implementation upfront. Claude executes. With intent, you describe the goal and the constraints, and Claude reads your existing code to determine what the implementation should look like.

Instruction works when you know exactly how something should be done and the model doesn’t need room. Intent works better when your codebase contains patterns the model can follow. And that’s almost always the case.

The rule of thumb: describe what and why, refer to existing patterns, leave how to the model.

Good prompts versus bad prompts

Concrete examples make the difference clear.

Bad:

> Refactor the code.

Which code? In what direction? What’s the goal of the refactor? Claude is going to guess.

Better:

> The functions in src/utils/validation.ts duplicate logic. Each of the
> four validate functions does the same null check and type conversion.
> Extract the shared logic into a helper function and refactor the
> four functions to use that helper.

Bad:

> Add tests.

Better:

> Add unit tests for the three public functions in
> src/services/billing.ts. Use the test framework and the
> mock patterns from the existing tests in src/services/__tests__/.
> Test at minimum: happy path, invalid input, and network error.

Bad:

> Fix the bug on the homepage.

Better:

> The homepage shows "undefined" when the user has no profile photo.
> The problem is probably in src/components/Avatar.tsx where
> user.avatarUrl is used without a fallback. Add a default avatar
> that's consistent with how we handle that in other components.

The pattern: localize the problem, describe the desired outcome, refer to context. The more specific your prompt, the fewer iterations you need.

CLAUDE.md as project memory

In part 1, we introduced CLAUDE.md as a file that Claude Code automatically reads at session start. Now we’re going to put it to serious use.

A good CLAUDE.md file contains three categories of information:

1. Project context

What is this project? What stack? What architectural decisions have been made?

## Project
E-commerce platform. Next.js 14, TypeScript, PostgreSQL via Prisma.
Monorepo with packages/api and packages/web.

## Architecture
- API: Express in packages/api/src/
- Web: Next.js App Router in packages/web/app/
- Shared types: packages/shared/types/
- Database migrations: packages/api/prisma/migrations/

2. Conventions

How do you write code in this project? What patterns apply?

## Conventions
- Async/await, never callbacks or .then() chains
- Error handling via custom AppError class (packages/api/src/errors/)
- API responses always via sendResponse helper (packages/api/src/utils/response.ts)
- React components: function components with named exports
- State management: Zustand stores in packages/web/stores/
- No default exports except Next.js pages

3. Commands

How do you build, test, and run this project?

## Commands
- Dev server: pnpm dev (starts api + web in parallel)
- Tests: pnpm test (Jest, all packages)
- Lint: pnpm lint
- Type check: pnpm typecheck
- Database migration: cd packages/api && npx prisma migrate dev
- Seed: cd packages/api && npx prisma db seed

Every time you start a session, Claude Code reads this file. That means Claude knows your conventions before you have to repeat them in every prompt. “Add a new endpoint” automatically becomes “add an endpoint with async/await, AppError handling, and sendResponse” — because that’s in CLAUDE.md.

Maintaining CLAUDE.md

CLAUDE.md is a living document. Update it when:

  • You make an architectural decision that changes the standard patterns.
  • You introduce a new convention.
  • You notice Claude keeps making the same mistake — that’s a signal that context is missing.

Keep it concise. A CLAUDE.md of fifty lines works better than one of five hundred. Claude Code reads it every session. Everything in it costs tokens. Be economical with context, just as with code.

The plan pattern

The most powerful technique for complex tasks is the plan pattern. Instead of directly asking for an implementation, you first ask for a plan.

> I want to add a notification system. Users receive a notification
> when their order changes status. First make a plan: which files
> need to be created or modified, in what order, and why.

Claude responds with a structured plan:

Plan:
1. Create packages/api/src/services/notification.ts — service that
   creates and stores notifications
2. Add NotificationChannel enum to packages/shared/types/
3. Create Prisma model Notification in schema.prisma
4. Create migration
5. Add sendNotification call to the existing
   updateOrderStatus function in packages/api/src/services/order.ts
6. Create GET /api/notifications endpoint for retrieval
7. Add tests for notification service

Now you have an overview. You can evaluate the plan before a single line of code is written. Is there a step you’d do differently? Is something missing? Do you notice Claude is overlooking a file? This is the moment to steer — not after seven files have already been created.

After approving the plan:

> The plan is correct. Execute steps 1 and 2.

Working through the plan step by step gives you control without having to dictate every line of code. It’s the balance between intent and structure.

When to give context and when to let Claude discover

A common mistake is giving too much context upfront. Claude Code can search your project. Let it do that.

Too much context:

> In the file src/services/order.ts on line 45 there's the function
> updateOrderStatus. That function imports OrderStatus from
> src/types/order.ts. The function accepts an orderId (string) and
> a newStatus (OrderStatus). It calls prisma.order.update with
> where: { id: orderId } and data: { status: newStatus }. I want you
> to send a notification after the update.

You just typed information that Claude can read itself. That costs you time and adds no value.

Right amount of context:

> Add a notification after the status update in
> src/services/order.ts. Read the existing function and the notification
> service we just created.

Claude reads the files itself and now has the current version — not your summary of what’s there, which may already be outdated.

The exception: give context when Claude can’t find it itself. Business rules that aren’t in code. Decisions that don’t emerge from the codebase. “We only want notifications on status changes to SHIPPED and DELIVERED, not PROCESSING” — that’s nowhere in your code, so you need to say it.

Session management

Claude Code sessions live as long as your terminal is open. Close the terminal, and you lose the session context. That’s a deliberate limitation — context is expensive and sessions that grow indefinitely become unmanageable.

Practical tips:

One feature per session. Start a new session for a new feature. That keeps the context focused and prevents old conversation elements from contaminating the new task.

End with a summary. Before closing a session, ask Claude for a summary of what was done. Paste that summary into a commit message or into CLAUDE.md if it was an architectural decision.

Use –print for one-shots. For single tasks that don’t need an interactive session:

claude --print "Which dependencies in package.json are outdated?"

This runs Claude Code in print mode: it answers and exits. No interactive session, no maintained context. Ideal for quick questions.

The difference after two weeks

After two weeks with Claude Code and a well-maintained CLAUDE.md, you’ll notice three shifts:

You think in intent. Instead of “I’m going to write twenty lines of boilerplate” you think “I’ll describe what this endpoint needs to do and let Claude generate the boilerplate.” The cognitive load shifts from typing to evaluating.

Your prompts get shorter. Because CLAUDE.md carries the base context, you need to repeat less. “Add an endpoint for retrieving notifications” is sufficient when your conventions are in the project memory.

You review more than you write. The working rhythm shifts from writing to reviewing. Claude proposes, you evaluate. That’s a different skill — and one you can deliberately train.

In part 3 we’ll look at the tools Claude Code uses under the hood, the permission system that determines how much freedom the model gets, and how to set up hooks for automatic actions.


This is part 2 of the series “Working with Claude Code”. Read part 1 for installation and first session.

Vic Boomer is an essay-led AI studio that turns ideas about AI, agents and software into clear analysis, working systems and practical tools.

More in this series
claude code tutorial