An advanced guide to
Claude Code
What I've learnt from using Claude Code,
and strategies you can use to get even better results.

Claude Code is an incredibly powerful tool from Anthropic, which brings their advanced AI model into your terminal window. It can edit files, run commands, search your codebase, and build features from start to finish - all from a single conversation.
I've been using it daily for about six months now, and it's easily the biggest improvement to my workflow in years. That said, the quality of what you get back depends almost entirely on one thing: how specific you are with your prompts.
I made a lot of mistakes early on - vague prompts, wasted context, and letting Claude go down the wrong path before stepping in. This guide covers the strategies I regularly use in my professional work, so that you can skip the same trial-and-error phase. It assumes that you've already installed Claude Code and built a few small things - but if you haven't, you might want to start with my beginner guide first.
1. Write clear, specific prompts
This is the single biggest tip I can give you and the one thing that will immediately improve your results. Previously, I would write lazy prompts like "add a dark mode toggle" and then get frustrated when Claude made a bunch of decisions that I didn't agree with. It would pick the wrong file, use the wrong component library, or change things that I didn't want to be changed.
Instead, you should spend the extra 30 seconds and be incredibly specific about what you want to happen. Tell Claude which files it should change, what components to reuse, and what not to touch. You'll immediately see the results improve and it'll mean there's less back-and-forth, which will save you time too.
When you're writing a prompt, try to include:
- File paths - use
@filenameto reference files directly, so that Claude reads them before responding. Or you can copy the specific path, like/components/footer.tsx - Desired outcome - describe what the end result should look like
- Existing components - point to similar code that already exists in your project
- Constraints - mention anything that you don't want to be changed
You can also pipe data directly into Claude Code. Running cat error.log | claude will send the file straight into your conversation, which is really useful when you're sharing error logs or the build output.
Here's an example of a vague prompt versus a specific one:
Add a dark mode toggle to my app.
Add a dark mode toggle to the site header, which is found in components/site-header.tsx. - Use the existing Button component from components/ui/button.tsx - Store the preference in localStorage with the key "theme" - Toggle a "dark" class on the <html> element (Tailwind's dark mode strategy) - Use a sun/moon icon from lucide-react, make sure that it matches the existing icon style in the header - We should default to using the user's system preference on their first visit - Don't modify the existing colour scheme, just add the toggle button next to the existing nav items
The second prompt tells Claude exactly where to make changes, which components to reuse, how to store the state, and what not to break. It takes a few extra seconds to write, but it saves you from having to go back-and-forth correcting things.
By being specific from the very start, you'll get the results you want in the first 1-2 prompts and save yourself a lot of time.
2. Include images to guide the output
Claude Code can also read images, which is an incredibly powerful way to improve your results - but most people aren't aware of this feature. If you're working on anything visual - such as a new UI component, screen layout, or any other design - pasting a screenshot into the conversation is far more effective than trying to describe what you want in words.
AI models have become incredibly good at analysing images and identifying key objects within them, so you should use this to your advantage. I've found that images are especially useful in two situations:
Showing what good looks like. If you have a design in Figma, a mockup from a designer, or even a screenshot of another site that has the style you're going for - paste it in. Claude can use it as a reference and build towards it, rather than guessing what you had in mind.
I've attached a screenshot that shows the coffee card design from Figma. Implement this as a React component in components/coffee-card.tsx. - Match the border radius, padding, and shadow from the design - The coffee name is in Yirgacheffe with the origin in small caps above it - Tasting notes render as pill-shaped chips using the terracotta accent - Use the colours from our Tailwind config - Make it responsive - stack the cover image above the details on mobile, side-by-side on desktop

Showing what's broken. I've wasted a lot of time trying to describe visual bugs with text. "The dropdown is overflowing" doesn't give Claude much to work with. But if you attach a screenshot of the broken layout, Claude can see exactly what you're seeing and quickly fix the bug.
I've attached a screenshot that shows Drip's navigation bar on desktop. The Shop dropdown is overflowing at the bottom of the screen and the last two categories are being cut off. This is in components/site-header.tsx. Fix the overflow so that the dropdown stays within the viewport. Don't change the layout on mobile.

You can paste images directly into the Claude Code terminal or reference image files in your project. Either way, it will cut down on the back-and-forth messages and save you lots of time.

And here's the same view after Claude applied the fix:


Loop Newsletter
Get weekly AI insights delivered to your inbox
Subscribe for freeRead by executives at:

3. Ask Claude to research the codebase first
Before you jump into writing code, it's worth asking Claude to explore your codebase and summarise what it finds. This is especially useful when you're picking up someone else's code, onboarding to a new project, or trying to understand how something works before you change it.
Claude is really good at reading files, searching for patterns, tracing imports, and building a picture of how things fit together. By doing this research upfront, you both have a shared understanding of the code before any changes are made - which leads to better decisions and fewer surprises.
This will give Claude an overview of your codebase and focus the results in future messages. It also means that Claude is less likely to duplicate components that already exist in your codebase, as it's able to spot and re-use them.
Before we make any changes, I need you to research how authentication works in this codebase. Focus on: - Where are the auth-related files? (middleware, hooks, context providers, API routes) - How are protected routes currently handled? - What session/token strategy is being used? - Are there any utility functions for checking auth state? Summarise what you've found, so that we can discuss the approach before we implement anything.
I've used this approach when investigating complex bugs that span multiple files and when I'm planning to do a refactor. Rather than having to read through dozens of files yourself, you can let Claude do the legwork and show a clear summary.
You can also use this to generate documentation. Just ask Claude to explore a module and write up how it works - it's a great way to create internal docs for parts of your codebase that have never been properly documented.
4. Use plan mode for complex tasks
When you're trying to do a significant piece of work - whether it's a new feature, refactoring multiple files, or a bug that you haven't properly diagnosed - you should always use plan mode first. You can activate it by typing /plan or by pressing Shift+Tab to toggle it on.

In plan mode, Claude will explore your codebase, read any relevant files, and draft a plan before it writes any code. I've found this to be really valuable, as it gives Claude time to "think" and explore the problem in-depth. Plus, you a chance to see the plan and change course, before Claude goes and makes a bunch of changes that you didn't want.

I tend to use plan mode when:
- The task could be solved in several ways and I want to choose the approach
- I'm working on an unfamiliar part of the codebase
- The change will affect several files or components
- I want Claude to understand the full picture before making changes
- Or when Claude is struggling to fix a bug and needs more time to "think" through the options
I want you to add authentication to my app. We need: - A login page at /login - A signup page at /signup - Protected routes that redirect to /login if not authenticated - Manage the sessions with cookies Before you implement any code, I want you to review the route code in app/ and how we currently have the middleware setup. You need to properly understand your approach before you start writing the code.
After you've reviewed Claude's plan, you can approve it, ask for changes, or reject it entirely. This back-and-forth is far cheaper than having to undo a bunch of changes that went in the wrong direction.
That said, you don't use plan mode for everything. If the fix is small and you know exactly what needs to change, just ask Claude to do it directly. Planning will add some overhead and it's not necessary for those simple fixes.
But plan mode is only half the story when it comes to how you control Claude's reasoning. It decides when the thinking happens, but it doesn't decide how hard Claude reasons while it's writing the code.
A good way to think about this is breadth vs depth:
- Plan mode - use when you need to go broad into a problem
e.g. when a problem touches multiple files, you want Claude to explore the codebase, or you need a wide view before committing to a direction - Thinking mode - use when you need to go deep into a problem
e.g. when you're focused on a specific problem or a tricky bug, and Claude needs more time to reason through it
By default, Claude will adjust this reasoning setting for you and will automatically "think" harder when it's facing a more complex task. If you want to change this yourself, you can run /effort and pick a level - the options are low, medium, high, xhigh, and max.

The higher levels will give Claude a bigger reasoning budget, but it will use more tokens and the response times will be longer. I typically leave mine on the default setting - then bump it up when I'm stuck on a genuinely hard problem and the default isn't getting me through.
5. Add MCP servers
The Model Context Protocol (MCP) allows Claude Code to easily connect with external tools, extending what it can do beyond just reading and writing files. MCP servers act as plugins that allow Claude to access databases, APIs, browsers, and plenty more - with the ecosystem growing really quickly.

To add an MCP server, just run claude mcp add from your terminal. Once you've got it configured, these servers will persist across sessions and Claude can use them automatically when needed. Here are some of the most useful ones I've come across:
- Microsoft 365 - search and analyse your Outlook emails, SharePoint and OneDrive documents, and Teams meeting notes from inside Claude. This allows you to pull insights and answer questions about your work, without having to upload anything manually
- Gmail - ask Claude to search through your inbox and draft emails for you, without having to leave the terminal
- Notion - fetch data from your pages and databases, so that your conversations stay grounded in your existing docs
- Figma - turn your Figma designs into a working website, or convert an existing website's UI into editable Figma frames
- Slack - pull message history into Claude for context, or have it send updates back to your team. It's really useful when you want to kick off a long task and get the result delivered to your channel
- GitHub - create PRs, review issues, and manage your branches directly with Claude
- Canva - generate designs that match your brand kit, then export them in any format you need
- Playwright - Claude can open the website it just built in a real browser, then review it for mistakes and fix them automatically - before it passes the work back to you
- Context7 - fetches up-to-date documentation for popular libraries - like React, Next.js or Vue - so that Claude always has the most recent API documentation and doesn't rely on its training data
The real power comes from combining multiple servers. You could ask Claude to read a Notion spec, pull the relevant Figma designs, build the feature, run end-to-end tests with Playwright, then open a PR on GitHub - all in a single conversation.

While most MCP servers extend what Claude can do, Playwright is a bit different because it allows Claude to actually see and automatically improve its own work. It's still pretty underused, but it's the first MCP I'd recommend for when you're doing UI work.
Claude will write the UI code for you, open it in a real browser and review the changes, then make improvements until it matches what you asked for. You don't need to constantly reload the page, or compare screenshots between each attempt - Claude can do it all for you.
To set it up, run claude mcp add playwright npx @playwright/mcp@latest to register the server, then npx playwright install to grab the browser binaries. One thing that's worth knowing - you should mention Playwright by name in your prompt, otherwise Claude might fall back and try to control the browser through Bash.
Build a subscriptions page at app/subscriptions/page.tsx with three tiers - Solo (1 bag every four weeks, $18/mo), Duo (2 bags every four weeks, $34/mo), and Discovery (3 bags from rotating origins every four weeks, $48/mo, marked as recommended). Match the design language we're using on the rest of the Drip site. Once you're done, use the Playwright MCP server to open the page and take a screenshot at desktop and mobile widths. Compare it to /shop (grab a screenshot of that page too as a reference) and adjust the styling until the subscriptions page feels consistent. After that, walk through the page interactively - click each tier's CTA button and confirm the hover states feel right.
There are loads of useful workflows you can try, once you've got it running. You can ask Claude to review how a layout looks on different devices, walk through a checkout flow in plain English, or audit your app for accessibility issues. It's not free, as each screenshot and page read will lead to more tokens being used - but for UI work, it's the closest thing to having an extra pair of eyes on your screen.

6. Bring Claude into your GitHub workflow
If you're not a software engineer, you might not have heard about GitHub before. It's used by software teams to store their code, develop new features, and review each other's changes.
Each project sits in a "repository" (or "repo" for short), developers then propose a change through "pull requests" (PRs), and "issues" are used to report bugs or request new features. The team will then review these changes, add comments, and then approve it.
You can bring Claude into your GitHub workflow as a virtual teammate - allowing it to live inside your repo, pick up tasks when you tag @Claude in a comment, and keep things moving even when you're not at your laptop. This means that you can tag @Claude on a ticket on a Friday afternoon, head off for the weekend, and then come back to a draft PR.
You can also have Claude review every new PR as soon as it's opened, so that it can catch any obvious mistakes before they reach your team. To set it up, just run /install github app inside Claude Code and install it on your repo - two GitHub Actions will then be added automatically and can handle the rest.

@Claude there's a broken anchor link in the README under the "Getting started" section - the one pointing to docs/installation.md. Can you find it, fix it, and open a PR? Keep the change minimal and don't touch anything else in the README.
These two GitHub Actions can be customised using the .github/workflows config files. You can also give Claude access to MCP servers inside the Action itself - so you could run Playwright for visual regression tests, or connect to Sentry and pull live errors into a PR review. It's worth noting that every tool permission has to be listed explicitly in the workflow, you can't have any wildcards or shortcuts for what Claude can access.
Bringing Claude into your GitHub workflow is incredibly useful for both teams and individuals - as you've essentially got an extra pair of hands that can pick up issues when you're working on something else, review PRs before they reach you, and (paired with a strict review checklist, which I cover when we get to slash commands) allows you to focus on the harder problems.
7. Set up your project with CLAUDE.md
If you're going to be using Claude Code regularly on a project, you should create a CLAUDE.md file and store it in the root of your project. This file is automatically loaded into Claude's context at the start of every session, giving it constant knowledge about your codebase and how it's structured.
The easiest way to get started is to run /init inside Claude Code. It'll analyse your project and generate a starter CLAUDE.md file - which is based on how your codebase works, your test framework, and the patterns you use. It's not always perfect, but it will give you a solid foundation that you can improve over time.

You should think of it as onboarding documentation for an AI teammate. Without it, Claude will start every conversation from scratch and then has to figure out your project's conventions on its own - which will lead to more mistakes and more time spent correcting things.
A good CLAUDE.md file should include:
- Build and run commands - how to start the dev server, run tests, build for production
- Code style guidelines - naming conventions, how to order your imports, different component patterns
- Architecture decisions - why you chose specific libraries, conventions for the folder structure
- Common pitfalls - things that are easy to get wrong in your specific codebase
# CLAUDE.md ## Build Commands - npm run dev - Start development server - npm run build - Build for production - npm run test - Run test suite - npm run lint - Lint codebase ## Code Style - Use functional components with TypeScript interfaces for props - Imports: React first, then components, then utils - Use Tailwind with cn() utility for class merging - Follow shadcn/ui component patterns with forwardRef ## Architecture - State management: React Context API (no Redux) - Styling: Tailwind CSS with shadcn/ui components - API routes: Next.js App Router with route handlers - Database: Prisma ORM with PostgreSQL ## Important Notes - Always use the "use client" directive for components with hooks - Keep server components as the default in app/ directory - Use next/image for all images (required for optimisation)
It's important that you keep the CLAUDE.md file concise. If your it gets too long, Claude will start ignoring half of it - so you should only keep the lines that prevent mistakes and cut everything else.
A nice way to improve your CLAUDE.md over time is to use memory mode. If you notice that Claude keeps making the same mistake, you can hit # directly in the chat and add a new rule. Claude will figure out the right CLAUDE.md to update (project, user-level, or a subdirectory file) and then add the rule for you. It means that you can add corrections as they happen, rather than trying to write the perfect version upfront.

You can also create CLAUDE.md files in subdirectories for instructions that are specific to one area. For example, a components/CLAUDE.md might describe your component patterns in more detail, while a tests/CLAUDE.md could explain your testing conventions.
8. Create custom slash commands
If you find yourself typing the same prompts over and over, slash commands allow you to save these prompts and re-use them at another time. This means that you can write the perfect prompt once, and quickly invoke it again with a single command.
Here are some examples of where they're useful:
- Code review checklists - run every diff through your team's review checklist before you open a PR
- PR descriptions - turn the diff into a structured summary, test plan, and any screenshots
- Commit messages - format every commit in your team's preferred style (conventional commits, ticket numbers, the works)
- Generating tests - scaffold unit tests for a function, component, or file using your existing test patterns
- Security or accessibility audits - check the latest changes against a project-specific checklist before they go out
- Scaffolding new files - kick off a new component, API route, or migration with your project's conventions baked in

To do this, you simply create a markdown file inside .claude/commands/ at the root of your project. The filename will become the command - so review.md becomes /review. When you invoke the command, the file's content is immediately sent to Claude as the prompt.
## Changed files !`git diff --name-only` ## Detailed changes !`git diff` Review the changes in $ARGUMENTS for potential issues. Focus on: - Logic errors and edge cases - Error handling gaps - Security vulnerabilities (injection, auth bypass, data exposure) - Performance issues (N+1 queries, unnecessary re-renders, missing memoisation) - Whether the code follows our existing patterns and conventions For each issue found, explain the risk and suggest a fix. If everything looks good, confirm that too.
The !`` syntax is quite useful, as it embeds the shell output directly into your prompt. When you run this command, Claude can automatically see the current git diff without you having to paste it in. This is what makes slash commands so powerful - they can pull in the latest context every time they're run.
Notice the $ARGUMENTS placeholder - this gets replaced with whatever you type after the command. So running /review payment-form.tsx will automatically include that filename in the prompt.
/review components/checkout/payment-form.tsx
Since these command files live in your project directory, you can commit them to git and share these workflows with your team. It's a really powerful way to ensure there's consistency across the board - as everyone will run the same code review checklist, the same PR description template, and the same pre-commit checks.
You can also create personal commands in ~/.claude/commands/ for workflows that you want to make available across all of your projects. These show up as /command-name alongside any project commands, and are great for storing your personal preferences.
This ties in with what I said at the very start of this guide - the best prompts are specific and include plenty of detail. With slash commands, you can invest time writing the perfect prompt once and then reuse it forever. Once you've built a prompt that consistently gives you great results, you should save it as a command.
9. Create your own skills
If slash commands are where you start automating your prompts, skills are the natural next step. They work in a similar way - they're reusable instructions you write once - but Claude applies them automatically when it recognises the task. This means that you don't need to type /review as often, because Claude can spot that you're asking for a review and load the skill on its own.
A skill is just a folder with a SKILL.md file inside. This file should have a name and description at the top, which tells Claude when it should use the skill, and then your instructions below. Here's what a simple one looks like:
--- name: pr-description description: Writes pull request descriptions. Use when creating a PR, writing a PR, or when the user asks to summarise changes for a pull request. --- When writing a PR description: 1. Run `git diff main...HEAD` to see all changes on this branch 2. Write the description in this exact format: ## What One sentence explaining what this PR does. ## Why Brief context on why this change is needed. ## Changes - Bullet points of specific changes made - Group related changes together - Mention any files deleted or renamed
The clever bit is how skills are loaded. When Claude Code starts up, only the names and descriptions sit in your context - which means you can have dozens of skills available without bloating the context window. When you ask Claude to do something, it matches your request against the descriptions and asks you to confirm before loading the full body of the relevant skill. That's what makes skills much cheaper context-wise than putting everything in CLAUDE.md.
Skills live in two places:
- Personal skills - live in
~/.claude/skills/and follow you across every project
e.g. your preferred commit message style, documentation format, or test patterns - Project skills - live in
.claude/skills/and get shared with your team through git
e.g. your team's code review checklist, PR description format, or component conventions
The description is the most important field, because it's what Claude uses to decide whether to load the skill. A good description answers two questions - what does the skill do, and when should Claude use it? If you write a vague description, Claude won't be able to trigger the skill reliably. The fix is to add the kinds of phrases you actually use when you'd want the skill to fire.
A couple of advanced fields are worth knowing about:
- allowed-tools - lets you restrict what Claude can do when a skill is active. Useful for security-sensitive skills - for example, a code-review skill that should only be allowed to read files and run git commands, never edit or write
- Progressive disclosure - the answer when a skill grows large. Keep your
SKILL.mdunder 500 lines and put longer reference material inreferences/,scripts/, orassets/subfolders. Claude only loads those files when it actually needs them
One important call-out - don't reach for a skill when a CLAUDE.md rule would do. If something always applies (like your TypeScript strict mode setting), it belongs in CLAUDE.md. Skills are for things that are only relevant some of the time.
The rule of thumb I keep in mind: if you find yourself explaining the same thing to Claude twice, that's a skill waiting to be written.

10. Set up hooks for deterministic actions
Skills add new knowledge to Claude's conversation. Hooks do something different - they make sure certain actions always happen, no matter what. The way I think about it: CLAUDE.md says "Claude usually does X", a hook makes Claude always do X.
Hooks are short scripts that run automatically at specific points in Claude Code's lifecycle. The most common ones are:
- PreToolUse - runs before Claude uses a tool, and can block the action if needed
- PostToolUse - runs after a tool completes, useful for follow-up actions like formatting
- UserPromptSubmit - fires when you submit a prompt, before Claude processes it
- Stop - runs when Claude finishes a response
- Notification - runs when Claude sends a notification
The most common use case is auto-formatting. You can set up a PostToolUse hook that runs Prettier (or whichever formatter you use) every time Claude edits a file. You can tell Claude in CLAUDE.md to do this and it usually will - but with a hook, it always does, without exception.
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|MultiEdit|Write", "hooks": [ { "type": "command", "command": "prettier --write \"$CLAUDE_PROJECT_DIR\"" } ] } ] } }
The other common use case is blocking things you don't want Claude to do. A PreToolUse hook can inspect a tool call before it runs and decide whether to allow it. If your hook exits with code 2, the action is blocked and the error message is sent back to Claude as feedback - so Claude knows why it was blocked and can adjust.
This is useful for hard rules you want enforced rather than suggested:
- Block commits directly to the main branch
- Block edits to specific files - production configs, secrets, lock files
- Stop Claude from running
rm -rfor any command you consider too risky - Run your linter after every edit and feed errors back to Claude
You can configure hooks through the /hooks command inside Claude Code, or by editing .claude/settings.json directly. Since the settings file lives in your project, you can commit hooks to git and the whole team gets the same enforcement.
One last thing - don't reach for a hook when a CLAUDE.md rule would do. Hooks add overhead and complexity, so only use them for things that genuinely need to happen every time without fail. If something needs to happen every time without exception, don't put it in a prompt - put it in a hook.
11. Build custom subagents
Subagents are one of the most useful features in Claude Code, and most people barely scratch the surface. A subagent runs in a separate context window from your main conversation. It gets a task, does the work in isolation, and returns only a summary back to your main thread. The intermediate steps - all the files it reads, the searches it runs - stay in the subagent's context and don't clutter yours.
The decision rule I use is simple: does the intermediate work matter to you? If you need to see how Claude found the answer because you're going to react to it, keep the work in your main thread. If you only care about the answer itself, delegate it to a subagent.
Claude Code ships with a few built-in subagents you can use right away - general purpose, Explore (fast codebase search), and Plan (used inside Plan mode). But the real power comes from creating your own. Run /agents to walk through the setup - you'll choose a scope (project or user-level), the tools the subagent can use, the model that powers it, and a colour to identify it in the UI.
--- name: code-reviewer description: Reviews recently modified code for quality, security, and best practices. Use after a feature is implemented or a bug is fixed. You must tell the agent precisely which files you want it to review. tools: Bash, Glob, Grep, Read model: sonnet color: purple --- You are a code reviewer for our codebase. Your job is to examine recently modified code and identify issues that could impact reliability, security, maintainability, or performance. Provide your review in this format: 1. Summary - brief overview of what you reviewed and overall assessment 2. Critical issues - security vulnerabilities, data integrity risks, or logic errors that must be fixed 3. Major issues - quality problems or architecture misalignment 4. Minor issues - style inconsistencies, missing comments, small optimisations 5. Approval status - is the code ready to merge or does it need changes? 6. Obstacles encountered - any setup issues, workarounds you discovered, or commands that needed special flags Focus on what could actually break in production. Don't worry about stylistic preferences unless they affect readability.
There's a non-obvious thing about how subagents work that's worth knowing. The description field doesn't just control when Claude launches the subagent - it also shapes the input prompt that Claude writes for it. So if you add something like "You must tell the agent precisely which files you want it to review" to the description, the parent agent will start writing more specific launch prompts. It's a subtle leverage point that nobody figures out by themselves.
There are four patterns that make subagents reliable:
- Specific descriptions - covers both when the agent launches and what input it receives
- A structured output format - gives the subagent natural stopping points so it knows when it's done, rather than rambling on
- An "obstacles encountered" section - explicitly asks the subagent to report any setup issues or workarounds it discovered, so they bubble up to the main thread rather than getting lost
- Limited tool access - give it only the tools it needs. Read-only for research, bash for reviewers, edit and write only for ones that should actually change code
Where subagents really shine:
- Research and exploration - when you need to find something in a large codebase but don't want all those file reads in your main context
- Code reviews - Claude reviews code more critically when it looks like someone else's work. A reviewer subagent doesn't have the bias of being the one who wrote it
- Custom-prompt tasks - Claude Code's default style is concise and technical, which is fine for code but not for everything. A copywriting subagent or a styling subagent can have a completely different system prompt and produce results your main thread couldn't
A few patterns to avoid. Prompts like "you are a senior Python engineer" don't actually add anything - Claude already has that knowledge. Sequential pipelines (one subagent feeds into the next which feeds into the next) tend to lose information at every handoff - keep work like that in your main thread. And don't use a subagent as a test runner - when tests fail, you want the full output to debug, not a summary that hides the details.
12. Use Claude for code reviews
Claude Code isn't just great at writing new code - it's also great at reviewing the code you've already written. I've started using it to check my own work before committing, and it's caught things I would have missed: edge cases, missing error handling, or things I forgot to cleanup.
The key is to be specific about what you want it to focus on. If you just ask "review this code", you'll get really generic feedback. But if you point it at a specific file and tell it to look for a list of issues, the results are much more useful.
Review the changes I've made in components/checkout/payment-form.tsx. Focus on: - Any edge cases in the form validation - Whether the error handling covers all the failure modes from Stripe's API - If there are any race conditions - Whether the component properly cleans up the subscriptions on unmount Don't worry about styling or naming conventions for now, just focus on correctness and reliability.
You can also ask Claude to review a git diff before you commit, which is a great way to catch issues early. I do this regularly now - just ask Claude to look at your staged changes and flag anything that needs to be changed.
Beyond your own code, it's also useful when you're reviewing someone else's pull request. Ask Claude to explain the changes, highlight anything risky, and check whether the new code is consistent with the patterns that are used elsewhere in the project.
Look at the git diff for the latest commit on this branch. Explain what the changes do, flag anything that looks like it could cause issues, and check whether the new code follows the patterns that we use in the rest of the codebase. Pay special attention to: - Any new dependencies being added - Changes to shared code or types that could affect other parts of the app - Whether the error and loading states are being handled consistently
13. Give Claude a way to verify its work
This is something I wish I'd understood sooner. Claude is much better when it can check its own work. Without clear success criteria, it'll produce something that looks right but might not actually work - and you become the only feedback loop.
The most common form of this is the edit-test-fix loop. Instead of writing code and hoping it works, tell Claude to run your test suite after making changes. If a test fails, it can read the error output, diagnose the issue, and fix it - often without any input from you.
Add a utility function to lib/utils.ts that formats a number as a currency string. Requirements: - Accept a number and an optional currency code (default: "USD") - Handle negative numbers with a minus sign before the currency symbol - Round to 2 decimal places - Add thousand separators After you've implemented this, run the existing test suite with "npm run test" to make sure nothing is broken, then write tests for the new function in lib/__tests__/utils.test.ts and follow the patterns in the existing test file.
But verification goes beyond tests. You can ask Claude to take a screenshot of the UI and compare it against a design, run a linter to check code style, or validate the output against your expected results. If you give Claude a way to close the loop, it can catch its own mistakes and won't need you to do this for it.
Implement the card layout and use the attached design. After you've made these changes, take a screenshot of the result and compare it to the original. List any differences you can see and fix them.
This works especially well when your CLAUDE.md includes the test and lint commands, so Claude knows exactly how to run them. The more ways it can verify its own output, the less time you need to spend reviewing and correcting mistakes.
14. Manage your context window
You need to keep the context window in mind and be prepared to clear it. The AI model will have a context window that holds your entire conversation - every message, every file it reads, every command output. As this starts to fill up, its performance will drop off. Claude starts to forget your earlier instructions and can make more mistakes.
The best habit I've built is using /clear between unrelated tasks. If you've finished one feature and are moving on to something else, you should clear the context window so that Claude starts fresh again. A long conversation full of irrelevant information will only slow it down and impact the results.

Anthropic has made some changes in the background and will automatically compact your conversation when it gets too long, so this is less of an issue than before, but it's useful to know and can help you eke a bit more performance from Claude Code.
There are several ways you can manage the context window:
- /clear - reset the context completely and is useful when you're switching to an unrelated task
- /compact - summarise the conversation, so that you can free up space but still preserve the key decisions. You can also add instructions like
/compact focus on the API changes - Esc - stop Claude mid-action if you see that it's going off track. Context will be preserved, so that you can redirect the AI model
- Esc + Esc or /rewind - restore a previous conversation and code state. Every action Claude takes will create a checkpoint that you can rewind to
One mistake I kept making early on was correcting Claude over and over when it got something wrong. After two or three failed corrections, the context is full of bad approaches and Claude becomes even more confused.
It's almost always faster to hit /clear and start a fresh conversation with a better prompt that incorporates what you learnt from the failed attempts. You can also enable Plan mode and encourage Claude to think about the problem in greater depth.
Subagents are another way to keep your context clean - I covered them in detail in section 11, but in short: for research-heavy tasks, you can have a subagent do the digging in a separate context window and just return the summary.
One last thing on context - when you close a Claude Code session, your files are saved on your computer but the conversation history isn't kept by default. If you want to pick up where you left off later, run claude --continue to resume your most recent session, or claude --resume to pick from a list of past sessions. Useful for longer projects you come back to over multiple days.
15. Run multiple Claudes in parallel with worktrees
Once you've been using Claude Code for a while, you'll hit the natural ceiling - one Claude can only work on one thing at a time. If you want to scale up further, the answer is running multiple instances of Claude Code in parallel.
The catch is that running two Claudes on the same project folder is asking for trouble. They'll trip over each other's file edits, leave the codebase in a broken state, and you'll spend more time untangling conflicts than you would have writing the code yourself.
The solution is Git worktrees. A worktree is a separate working directory that's tied to the same repository, but on a different branch. Each Claude instance gets its own worktree, works in isolation, and you merge the results back when each one is done.
# Create a worktree for a new feature on its own branch git worktree add ../my-project-feature-x feature-x # Switch into the worktree and launch Claude Code cd ../my-project-feature-x claude # When the feature is done, switch back to main and merge cd ../my-project git merge feature-x # Clean up the worktree when you're finished with it git worktree remove ../my-project-feature-x
The workflow looks like this - spin up a worktree for each task, launch Claude Code inside it, describe what you want, and let them all work in parallel. When a task is done, commit the changes in that worktree and merge the branch back to main.
I usually pair this with a custom slash command (the kind we covered in section 8) that automates the worktree setup. The command creates the branch, sets up the worktree, and kicks off the task in one step - so spinning up a new parallel Claude is just one command away.
The honest framing here is that this changes the bottleneck. It's no longer "how fast can Claude work" - it's "how many Claudes can I keep track of at once?". Running three parallel Claudes isn't three times faster if you can't review their work fast enough to merge it back. I find two or three is the sweet spot, but it really depends on the complexity of what each one is doing.
It works really well when the tasks are genuinely independent - one Claude on the UI, one on the API, one writing tests. It works less well when the tasks need to coordinate or share state - in those cases, keep everything in a single conversation so Claude can carry the context forward.
Key takeaways
I've been using Claude Code for the last six months. It's an incredibly powerful tool and allows developers to write code faster than ever, fix issues in minutes, and design new user interfaces that will delight people.
During this time, I've really put Claude Code through its paces and learnt a lot about how you can extract the most from it. Here's a quick overview of the different strategies you can use.
1. Most problems come down to vague prompts
When Claude gives you a bad result, the first thing to check is whether your prompt was specific enough. Nine times out of ten, the issue isn't Claude - it's that you didn't tell it exactly what you wanted. The 30 seconds you spend writing a clearer prompt will save you 10 minutes of back-and-forth.
2. Screenshots are worth more than you'd think
I was sceptical about this at first, but I've saved a lot of time by pasting a Figma mockup or a screenshot that clearly shows the UI bug. It's much easier for Claude to build towards something that it can see, rather than something you've described in text.
3. Let Claude research before it builds
Before jumping into code changes, ask Claude to research the codebase first. It will read the relevant files, understand the patterns already in use, and produce much better results. This is especially useful when you're working in an unfamiliar part of the codebase.
4. Use plan mode for the big stuff
For complex tasks, use plan mode so that Claude can think through the approach before writing any code. It's a bit more effort upfront, but it will save you time by avoiding those wrong decisions and unnecessary changes. For really hard problems, bump /effort up or include ultrathink in your prompt.
5. MCP servers are a game-changer once you set them up
I put off setting up MCP servers for quite a while, as it seemed like extra work for very little gain. But once I connected it to Figma, GitHub, and Sentry, my workflows became significantly more powerful. The single biggest unlock is the Playwright MCP server - it lets Claude open your app in a real browser and iterate on the UI until it matches what you asked for.
6. The GitHub App gives you a 24/7 reviewer
Installing the GitHub App means Claude can run inside GitHub Actions - reviewing every PR automatically and responding to @Claude mentions on issues. It's a different mechanism to the GitHub MCP server, but they pair well together. For distributed teams, this is one of the highest-leverage things you can set up.
7. CLAUDE.md gets better with age
Run /init to generate a starter file, then refine it every time Claude makes a mistake that a rule could have prevented. Use # in the chat to add rules as you go. But make sure you keep it concise - if it's too long, Claude will start ignoring half of it.
8. Automate your best prompts
Once you've written a prompt that consistently gives you great results, save it as a slash command so you never have to write it again. Drop a markdown file in .claude/commands/ and your whole team can use it. It's one of the easiest ways to standardise quality across a project.
9. Skills are the next step beyond slash commands
If a slash command is a prompt you invoke manually, a skill is a prompt that Claude invokes automatically when it recognises the task. Drop a SKILL.md in .claude/skills/ and you stop typing the same command for every PR review or commit message.
10. Use hooks for the things that absolutely must happen
Hooks turn "Claude usually does X" into "Claude always does X". Use them for auto-formatting, blocking dangerous commands, or anything you need to be guaranteed rather than suggested. Don't reach for them when a CLAUDE.md rule would do.
11. Delegate work that doesn't need to be in your main context
The decision rule for subagents is whether the intermediate work matters to you. For research, code reviews, and tasks that need a different system prompt to your main thread, custom subagents are excellent. Avoid them for sequential pipelines and test runners.
12. Use Claude as your first code reviewer
Before you ask a colleague to review your code, ask Claude first. It can catch bugs, suggest improvements, and flag potential issues - all without taking up another developer's time. It won't replace human reviews entirely, but it will make them faster and more focused.
13. If you can't verify it, don't ship it
Tests, screenshots, linters, expected outputs - these all allow Claude to check its own work. The edit-test-fix loop is a reliable way to get working code, and it's often used by experienced developers.
14. Context is your most valuable resource
Use /clear to reset the context window between tasks. Ask Claude to use subagents for research. If you've corrected Claude twice and it's still wrong, don't correct it a third time - start fresh, enter Plan mode, and outline what Claude has already tried. A clean context with a good prompt will almost always outperform a long, cluttered conversation with lots of corrections.
15. Scale up with parallel Claudes
Git worktrees let you run multiple Claudes on the same project without them tripping over each other. It's a step-change in throughput, but the new bottleneck becomes you - so don't run more in parallel than you can realistically review.
Summary
The gap between an average experience with Claude Code and a great one comes down to a few things - how clearly you communicate what you want, how well you manage the context window, and how much of your workflow you've taught Claude to handle automatically. Be specific with your prompts, show Claude what you want with images, give it ways to verify its own work, set up CLAUDE.md and skills so you're not repeating yourself, and use /clear between tasks to keep things sharp.
If you found this guide useful, you'll enjoy my weekly newsletter - every week I analyse the latest AI advances and how you can use them. It's free and you can unsubscribe at any time.

Read by executives at:

You might also like

AI use cases for everyone
Practical ways that you can use AI. At work, at home, and everywhere in between.

Create your first AI agent
A comprehensive guide to building and deploying your first AI agent.

Create a short film with AI
The workflow I used to create an animated short in three days, with zero filmmaking experience.
Loop