Chapter 3Intermediate12 min read

Context Engineering: Getting More from Claude Code

Context Engineering: Getting More from Claude Code

Part of the series: Claude Code: From Zero to Swarm

What is context engineering?

If you have used Claude Code on a few projects by now, you have probably noticed something. Sometimes it gives you exactly what you want on the first try. Other times, the result is generic, off-target, or just mediocre. Same tool, same model, wildly different output.

The difference is almost never capability. Claude can write complex TypeScript, refactor entire modules, debug gnarly async issues. The difference is context — what Claude knew about your project, your preferences, and your intent at the moment it generated its response.

Context engineering is the practice of deliberately shaping the information an AI has access to so that its output matches what you actually need. It is not a Claude Code feature. It is a skill. And it is the skill that separates "this is okay, I guess" from "how did it know exactly what I wanted?"

Here is the mental model: AI output quality is a function of context quality. Better context in, better output out. Every time. There is no trick, no secret prompt, no magic phrase. There is just the quality of the information you provide and how well it maps to the task at hand.

Every feature covered in this article — CLAUDE.md, slash commands, memory, permissions, extended thinking — is a mechanism for engineering better context. Some shape what Claude knows before a conversation starts. Some help you manage context during a conversation. Some carry knowledge across sessions so you do not repeat yourself.

The good news is that this skill transfers. Once you learn to think about context engineering in Claude Code, you will apply the same thinking to every AI tool you use. It is the meta-skill of AI-assisted development.

The CLAUDE.md file

Every time Claude Code starts a conversation in your project, it looks for a file called CLAUDE.md in the root of your project directory. If it finds one, it reads the entire thing before you say a word. Think of it as a briefing document — the onboarding packet you would hand a new developer on their first day.

To generate one, run this in your project:

/init

Claude will scan your codebase — the file structure, the dependencies, the configuration files — and generate a CLAUDE.md that captures the key facts about your project. It is a starting point, not a final product.

Here is what a realistic CLAUDE.md looks like for a small web application:

# Project: Recipe Tracker

A Next.js 14 app for saving and organizing recipes.

## Stack
- Next.js 14 with App Router
- TypeScript (strict mode)
- Tailwind CSS for all styling
- Prisma with PostgreSQL
- Deployed on Vercel

## Conventions
- All components use functional style with TypeScript interfaces for props
- API routes live in app/api/ and return JSON
- Database queries go through lib/db/ — never call Prisma directly in routes
- Use named exports, not default exports
- Error handling: always return proper HTTP status codes, never swallow errors

## Key files
- prisma/schema.prisma — database schema, source of truth for data model
- lib/db/recipes.ts — all recipe CRUD operations
- app/api/ — API route handlers

## Testing
- Vitest for unit tests, Playwright for e2e
- Run tests with: npm run test

That is about twenty lines. Nothing fancy. But the effect is significant. Without this file, Claude makes generic assumptions. It might use JavaScript instead of TypeScript. It might put database calls directly in your route handlers. It might use CSS modules instead of Tailwind. Every assumption it gets wrong is something you have to correct, and every correction burns context and time.

With a good CLAUDE.md, Claude matches your project's patterns from the first interaction. It already knows the stack, the conventions, the file organization. It writes code that looks like your code.

The analogy is straightforward: it is the difference between hiring a contractor with no briefing versus giving them a thorough onboarding document. The contractor's skills are identical in both cases. The quality of their first day's work is not.

Edit your CLAUDE.md after it is generated. Add anything Claude should always know. "We never use inline styles." "The auth middleware lives in lib/auth.ts and must be used on all protected routes." "All dates are stored in UTC." The more specific you are, the fewer corrections you will make later.

Slash commands as context tools

Claude Code has a set of built-in slash commands. You have probably used a few already. What you might not have noticed is that most of them are context management tools — they give you control over what Claude is holding in its working memory during your conversation.

/help shows you everything available. Think of it as your map. If you are ever unsure what commands exist or what a particular feature does, start here. It is the fastest way to orient yourself.

/help

/clear resets the conversation entirely. Claude forgets everything you discussed and starts fresh, with only your CLAUDE.md as context.

/clear

Use this when you are switching topics. If you just spent twenty minutes debugging an authentication issue and now want to build a new feature, clear the conversation. All that debugging context — the error messages, the stack traces, the dead ends — is now noise. It will actively make Claude's responses worse for the new task because it is trying to maintain coherence with information that is no longer relevant.

/compact compresses the conversation. Instead of throwing everything away like /clear, Claude summarizes what happened so far and continues with a condensed version of the context.

/compact

Use this when the conversation is long but you want to keep the thread. Maybe you have been building a feature across several steps and do not want to re-explain the requirements. Compacting keeps the essential information while freeing up space for new work.

/cost shows your token usage — how much context you have consumed so far.

/cost

This is your gauge. When you see the numbers climbing, you know the context is getting full. A full context means Claude has less room to reason about your current request. If you notice quality dropping late in a long session, check your cost. It might be time for a /compact or a /clear.

The key insight behind all of these commands: a focused context produces better results than a cluttered one. It is counterintuitive — you might think more information is always better. It is not. Information that is irrelevant to the current task is not neutral. It is negative. It competes for attention with the information that matters.

You are not just having a conversation. You are managing a context window. These commands are how you keep it clean.

Permission modes

Claude Code has three permission modes that control how much autonomy Claude has during a session. They seem like a safety feature — and they are — but they are also a context engineering tool in a subtler way.

Suggest mode is the default. Claude asks permission before every file change and every terminal command. You see what it wants to do, you approve or reject, and then it proceeds.

Auto-edit mode lets Claude make file changes without asking, but it still asks before running terminal commands. You trust it with code, but not with your shell.

Full trust mode lets Claude do everything — edit files, run commands, install packages — without asking permission for anything.

To change modes, use the permission controls in Claude Code or set them when you start a session. You can also configure permissions per-project in your settings.

The obvious consideration is safety. Start with suggest mode until you are comfortable. Move to auto-edit when you have seen enough of Claude's work to trust its judgment with your files. Use full trust for well-scoped tasks where you have given clear, specific instructions.

But there is a less obvious consideration: flow. Every permission prompt interrupts your thinking. When Claude stops to ask "Can I edit this file?" and you say yes, and then it stops again to ask "Can I edit this other file?" and you say yes again — each interruption breaks your rhythm. You lose the thread of what you were thinking about the bigger picture because you are micro-managing individual file edits.

The right permission mode is not just about safety. It is about maintaining the pace at which you can think alongside Claude. If you are doing exploratory work where you want to review every change, suggest mode is right. If you have given Claude a clear specification and want it to execute, full trust lets it work at its natural pace — and lets you stay focused on the output rather than approving each step.

Permission modes are context engineering for your own attention. Choose the mode that lets you focus on the level of abstraction you actually care about.

Memory across sessions

Here is a frustration you have probably experienced: you explain something to Claude in one session — a project decision, a naming convention, a preference for how errors should be handled — and then next time you start Claude Code, it has no idea. You explain it again. And again the session after that.

Memory solves this. You can tell Claude to remember things, and it stores that information in files in your project. Next session, it already knows.

The way it works: when you tell Claude to remember something, it writes that information to memory files that persist in your project directory. Every new session, Claude reads these files alongside your CLAUDE.md, so it starts with your accumulated project knowledge already loaded.

Here are practical examples of things worth remembering:

Project decisions:

Remember that we chose PostgreSQL over MySQL because we need JSONB support for the flexible metadata fields.

Next time you are working on anything database-related, Claude already knows the reasoning behind your database choice. It will not suggest MySQL. It will not question why you are using JSONB. It has the context.

Coding preferences:

Remember that I prefer functional components with explicit TypeScript interfaces over inline type annotations.

Now every component Claude generates matches your style without you having to say "no, like this" every time.

Team conventions:

Remember that our API uses snake_case for JSON response fields, even though the TypeScript code uses camelCase internally.

This is the kind of convention that Claude gets wrong constantly if it does not know about it. With memory, it gets it right every time.

Architecture boundaries:

Remember that the auth middleware in lib/auth.ts must be used on all protected API routes. Never check auth manually in a route handler.

This is knowledge that prevents bugs. Without it, Claude might generate a route handler that does its own auth check, creating an inconsistency in your codebase. With it, Claude follows the established pattern.

Think of memory as your project's institutional knowledge, accumulated over time. The first few sessions, you are teaching Claude how your project works. After a few weeks, Claude knows things about your project that you might have forgotten you told it. It becomes a genuine repository of project context that compounds in value the longer you use it.

The important thing is to be deliberate about what you tell Claude to remember. Good memories are specific, actionable, and stable — things that are true across sessions, not things that change every day. "Remember we use Tailwind" is good. "Remember that the current bug is in the auth flow" is not — that is session-specific context, not project-level knowledge.

Extended thinking

Some problems are straightforward. "Add a button that says Submit." Claude does not need to think deeply about that. It generates the code, you move on.

Other problems are hard. Debugging an intermittent race condition. Deciding how to restructure a module that has grown too large. Refactoring a component that touches twelve other files. These are problems where the first plausible answer is rarely the best answer — where you need to consider multiple approaches, weigh trade-offs, and think through edge cases before writing a single line of code.

For these problems, Claude Code can engage extended thinking — a mode where Claude pauses and reasons more thoroughly before responding. You will see a thinking indicator that shows Claude is working through the problem rather than immediately generating output.

You do not need to enable this or configure anything. Claude decides when deeper thinking is needed based on the complexity of your request. When you ask a straightforward question, you get a fast response. When you ask something that requires careful reasoning, Claude takes more time to get it right.

The result is noticeably different. For complex refactoring, you get a response that considers the ripple effects across your codebase. For debugging, you get a systematic analysis rather than a guess. For architecture decisions, you get a reasoned recommendation with explicit trade-offs rather than a generic suggestion.

The connection to context engineering is this: extended thinking is Claude giving itself more internal context to work with. When it pauses to think, it is reasoning through the problem space — exploring dead ends privately, evaluating alternatives, checking its own logic — before presenting you with a considered response. You are not adding context externally. Claude is generating it internally.

This matters because it means you can trust Claude with harder problems than you might expect. If you have been limiting yourself to simple, prescriptive requests because complex ones produced mediocre results, try giving Claude a genuinely hard problem and letting extended thinking do its work. You might be surprised at the quality of the response when Claude has the space to actually think.

Working smarter: practical patterns

Everything in this article so far has been about specific features. This section is about how you use them together — the practical patterns that make the difference between good and great results.

Scope your tasks. One clear goal per conversation works better than a sprawling session. "Add user authentication with email and password" as a focused conversation will produce better results than embedding it in "rebuild the entire backend." When you give Claude a single, well-defined task, all of the context in the conversation points toward that task. When you give it five tasks, the context for each one is diluted by the other four.

This does not mean you can only do one thing per session. It means you should complete one thing, then either /clear and start the next one fresh, or /compact to carry forward only what is relevant.

Start with intent, not instructions. Before diving into specifics, tell Claude what you are trying to achieve and why. Compare these two approaches:

The instruction-first approach:

Add a search bar to the header component with a text input and a submit button.

The intent-first approach:

Users can't find products in our catalog. I want to add search functionality 
so they can search by product name. It should be in the header so it's 
accessible from every page.

The second version gives Claude dramatically more context. It knows the problem you are solving, who it is for, and where it fits in the application. With that context, Claude might suggest debouncing the input, adding keyboard shortcuts, or including search-as-you-type behavior — things it would never think to suggest from the instruction-only version.

Course-correct early. If Claude's first response is heading in the wrong direction, redirect immediately. Do not wait three exchanges hoping it will self-correct.

Actually, I want this to be server-side search, not client-side filtering. 
The catalog has 50,000 products so we need to query the database.

Every message you exchange that goes in the wrong direction wastes context. The correction plus the original wrong direction are both now in the context window, competing with each other. Correcting on the first response keeps the context clean and focused.

Use follow-ups to build patterns. After Claude completes something well, leverage that context:

That looks good. Now do the same thing for the categories page and the 
brands page.

Claude has the pattern from the first implementation. It knows the approach you approved, the style you accepted, the conventions it followed. Applying it to similar cases is where AI-assisted development becomes genuinely faster than doing it yourself — Claude maintains perfect consistency across repetitions in a way that is hard to do manually.

Be deliberate about every message. This is the meta-pattern that contains all the others. You are not just chatting with an AI. You are managing a context window. Every message you send either adds useful signal or adds noise. A vague question adds noise. A specific question adds signal. A correction adds signal. A tangent adds noise.

This does not mean you need to be robotic or overly formal. It means you should be intentional. Before you send a message, spend half a second asking: does this help Claude understand what I need? If not, rephrase it until it does.

What you just learned

Context engineering is the meta-skill of AI-assisted development. It is not about knowing the right prompts or the right tricks. It is about understanding that every piece of context shapes the output — and then being deliberate about what context you provide.

Here is what you now have in your toolkit:

CLAUDE.md gives persistent project context. It loads before every conversation, ensuring Claude always knows your stack, your conventions, and your project structure. It is the foundation that everything else builds on.

Slash commands manage conversation context. /clear gives you a fresh start. /compact compresses without losing the thread. /cost shows you how full the context window is. Together, they keep your conversations focused and productive.

Memory carries knowledge across sessions. Project decisions, coding preferences, architecture boundaries — anything you tell Claude to remember persists. Over time, Claude accumulates a deep understanding of how your project works.

Permission modes control the workflow. They determine how much autonomy Claude has and, just as importantly, how much your own attention is interrupted. Choosing the right mode for the right task keeps you focused on what matters.

Extended thinking handles the hard problems. When Claude needs to reason deeply, it takes the time to do so. You get more thoughtful, more accurate responses for the problems that actually require thought.

Practical patterns tie it all together. Scope your tasks. Start with intent. Course-correct early. Use follow-ups. Be deliberate about every message.

The formula has not changed: better context in, better output out. Every time. Now you have the tools and the patterns to put that formula into practice.

Next in the series: what happens when one agent is not enough? We will look at how Claude Code handles multi-agent orchestration — running multiple Claude instances that coordinate on larger tasks.