Skip to main content
Back to blog

Claude Code in Anger

John

People had lots to say about our 150,000 lines of vibe coded Elixir. Some agreed with my thoughts. Some thought I didn’t deserve to spend time near computers. That post was mainly about Elixir and what I learned building a specific project. This one is about Claude Code itself. The workflow, the tools, the lessons from over a year of using AI to help me write code.

For the haters, here’s another heart attack: I no longer open a code editor. In the previous edition, I stopped writing code by hand. Today I only prompt Claude. Five instances at once across git worktrees. No Vim, no VS Code, no IDE. Just a terminal and a voice. I do read diffs, but in a vibe-coded diff viewer I built for local use because I got sick of the GitHub UI.

I’ve been on Claude Code for eight months. About two months without opening an editor at all. This post is what I’ve learned. What makes sessions good and what makes them bad. Not from a weekend project. From thousands of prompts and a couple hundred thousand lines of production code. I include that number because BoothIQ has gone from hobby weekend prototype to a production app with real users, real use cases, and constant change. All built with AI.

If You’re Not Sure, Just Ask

I’ve wasted more time on analysis paralysis than on any bad AI output. Sitting there thinking “I’m not sure how this should work” before sending a single message. The best sessions started when I took what was in my head, confusion and all, and just spat it out. “I need a way to batch enrich contacts that failed on the first try. Not sure the best approach. Here’s the current flow…” and let it rip.

It’s like rubber ducking, but the duck is intelligent. You explain the problem, and Claude comes back with options you maybe hadn’t considered. Reacting to a first draft is fast. Creating from nothing is slow.

You’re still doing the thinking. But you don’t need a clean starting point. Say what you’re trying to do. If you’re unsure, say that. Let it propose options. Look at what comes back and say “no, not like that, more like this.” That’s the whole loop.

When It Screws Up, Ask Why

If the AI seems to be screwing up hardcore, that’s usually your architecture pushing back on you. If it’s making crazy leaps or doing something convoluted, stop and ask why.

I noticed an N+1 in a diff where Claude grabbed a bunch of records and then looped through them to fetch more records one at a time. The filter clause it needed didn’t exist yet, so Claude made a decision: instead of extending the API, it worked with what it had. Wrong call. I told it to add a filter clause that accepts a list of IDs. The issue cleared up right away.

If the AI is doing something convoluted, it probably doesn’t have the right tools in place. Figure out why before you let it do it the hard way.

Use Voice Input

You can talk way faster than you can type, and these days I speak most of my prompts. They come out more detailed, faster, and easier than anything I’d type. Boris Cherny, the creator of Claude Code, says voice input makes him 3x faster. I started with Mac’s built-in dictation and moved to Wispr Flow (not an ad, it’s just way better than the built-in dictation).

Trust, But Verify

The AI will hallucinate. It’ll tell you a library function takes three arguments when it takes two, or silently drop an edge case during a refactor. It’ll tell you a bug is fixed when it just moved the failure to a different screen. Without access to run the code, it can’t catch its own mistakes.

Make it prove it. “Write a test that proves this works.” If the test passes, trust the change. If it doesn’t, the AI sees the failure and fixes it. Without tests, the AI will proudly tell you something’s complete without having verified it.

I’ve watched Claude write a function, write five tests for it, run them, see two fail, fix the code, and run them again until they pass. All without me typing a word. That loop is where AI coding works best. But it only works if the AI can actually run the code.

Give It Access

Let it read files. Let it run commands. Let it read your dev database. If you hired a junior engineer and made them submit working PRs without ever running the code, that’d be insane. That’s what people do to their AI when they lock it out of the dev environment.

It needs to see error messages, read test output, check the database. Every piece of access you take away is feedback it loses.

Here’s a real example. I use Claude Code on my Mac and on my iPhone. Same model, same codebase, same prompts. The Mac version is way better. Why? On my Mac, Claude can run Elixir, execute tests, read logs through Tidewave, and inspect the browser through DevTools MCP. When it writes broken code, it sees the compilation error and fixes it. When a test fails, it reads the output and tries again. On the iPhone, none of that exists. No terminal, no test runner, no dev server. It writes code and assumes it works, even when there’s a compilation error or a failing test. It has no way to self-correct.

Here’s what a good session looks like on the Mac. I mumble a messy, half-baked idea into the mic. It writes the code, runs the tests, reads logs in the REPL via Tidewave to troubleshoot failures, then verifies the UI through DevTools MCP. I build nearly every feature this way. Seeing the AI self-correct, view the UI, and self-correct again as it creates a working feature from scratch is the closest thing to magic I’ve experienced in my career.

If you’re getting poor results from AI coding, check what access you’ve given it. Tests, logs, and MCP servers give the agent real feedback. Without them, it’s guessing and you’re babysitting.

Don’t Customize (Yet)

We, as developers, love customization. Dotfiles, themes, plugins, keybindings. We spend weekends on our terminal setups. That instinct carries right into AI tooling: MCP servers, hooks, custom system prompts layered six deep. Most of it gets in the way of learning the tool as it’s meant to be used.

Boris Cherny, the creator of Claude Code, keeps his setup intentionally vanilla. No customizations to speak of. Claude Code works well out of the box, and starting from that baseline lets you feel where the real friction is before you start fixing things that aren’t broken.

Every skill, plugin, and MCP server you add clutters your context. Disable every MCP server you’re not actively using. Run /context on a fresh conversation and see how much of your context window is already gone before you’ve said a word. Some people lose 30 to 40% to tool definitions they’re not even using. I’ve seen horror stories of 60%. That’s context the model could be spending on your code.

Let the friction guide your customizations. If you notice a theme here, it’s that everything I used to do by hand, I just ask Claude to do now. Claude works for me, not the other way around.

Put Your Business in Your CLAUDE.md

Business context steers Claude toward the right calls. Without it, Claude will happily do whatever seems reasonable in the moment. It’ll build a QR code scanner when you need OCR text reading. It’ll make a paid feature available for free. It’ll name things wrong because it doesn’t know your domain.

Our CLAUDE.md has our architecture, our code conventions, and what BoothIQ does. Who our customers are. What’s free versus paid. What we build and what we won’t. When I tell Claude to build a new feature, it already knows the product. It knows we scan badges with AI/OCR. It knows our paid users get CRM sync. It knows our core workflow is capture, record, follow up.

Here’s where that pays off. I was wondering whether to break a large module into smaller files. I couldn’t figure out where to draw the line. Because Claude had the business context, it pointed out that the core of the app is capturing contact and meeting info. All the derivative operations hang off those concepts, so they belong together. A lot of operations, but logically one module. Without that context, it would have happily split everything apart on arbitrary lines, and the next agent session would have burned tokens trying to figure out where everything went.

Every session after the first gets better. The code reads like it was written by someone who works here.

Teach It How You Want It to Think

Business context tells Claude what to build. But you also need to tell it how to build. These four guidelines, derived from Andrej Karpathy’s observations on AI coding, work well in a CLAUDE.md:

  1. Think before coding. Surface assumptions upfront. If something is ambiguous, ask instead of guessing.
  2. Simplicity first. Write the minimum code that solves the problem. No speculative features, no unnecessary abstractions.
  3. Surgical changes. Only touch what the request asks for. Don’t improve adjacent code, comments, or formatting.
  4. Goal-driven execution. Define what success looks like before starting. Loop until verified.

These shape how the agent approaches every task. Without them, Claude defaults to its training: write more code than needed, add error handling for impossible cases, refactor things you didn’t ask about. Adding guidelines like these to your CLAUDE.md turns those defaults off.

Build an Automated Code Review Loop

I used to correct Claude on the same Elixir conventions and codebase styles over and over. Every codebase has its own version of these. When you notice Claude making the same mistake a few times, or something that seems generally repetitive, tell Claude to add it as a rule. You can even ask it directly: “You keep adding error handling for cases that can’t happen. How do we set up a rule so you stop doing that?” It’ll write the rule for you. Periodically tell it to review and reorganize its rules so they’re easier for it to parse.

Then I took it further. I asked Claude to help me build a code review skill that checks for our most common violations. I didn’t write it by hand. I didn’t need to know how skills work, where they live, or how they should be structured. I just said “help me write a skill for the Elixir conventions I keep correcting you on.” Claude built it. Now the workflow is:

  1. Plan the feature
  2. AI implements it
  3. Run the automated code review
  4. AI fixes what the review catches
  5. Repeat until it comes back clean
  6. Now I look at it

By the time I see the code, it’s already been through its own code review. The routine mistakes are gone. It just needs my final look before I sign off and merge.

Run Multiple Instances

One Claude Code instance is useful. Three is a team. Five is absurd and I do it anyway.

I used to write the occasional line by hand. A CSS tweak, a minor fix. Then I noticed Claude would panic whenever I edited a file directly, convinced I was reverting its work. So I started prompting it for everything, even one-line changes. After a while I realized I hadn’t opened my editor in weeks. That made me weirdly nervous. I closed it anyway and let Claude Code’s TUI fill the full width of my terminal. Haven’t looked back.

My job now is managing Claudes. Git worktrees make this work. Each instance gets its own worktree and branch, with its own running dev server. They share the database. They don’t step on each other’s code. One building a feature, another fixing a bug, a third refactoring, a fourth writing tests, a fifth on something speculative.

The lazy prompt works well here. “Clean up the contact enrichment flow, it’s gotten messy.” Review what comes back. Looking at a diff and saying “keep this, redo that” is faster than writing detailed instructions.

I started with one instance, moved to three, now run up to five. The limit is how many things I can keep in my head at once.

Refactoring Is Free Now

Before AI, refactoring was a lie we told ourselves. “We’ll clean this up later” meant never. The cost of a rename or rewrite was measured in days. Nobody approved that work because the features always won.

We all have those moments. You’re building a feature and you hit the seam where the old approach and the new approach collide. You start migrating other code from old to new, realize it would triple the scope of the PR, and abandon the change halfway through. That’s no longer necessary. Delegate the refactor to another Claude instance or a sub-agent and forget about it. It’ll be done a few minutes later.

BoothIQ has gone through several large refactors that would normally take days, if not a week or more. Made worse by the fact that new code keeps landing while the refactor is in flight, requiring rebases, merge conflicts, and constant coordination. When you can land the big refactor in hours or a single day, you skip all of that.

You don’t need to get the architecture right on the first try. Build it, ship it, learn from users, restructure when you know more. Changing your mind is basically free.

Fight Scope Creep Ruthlessly

Claude will naturally try to introduce changes unrelated to the current PR or blow the scope with things you didn’t ask for. Fight back against that. It is trivial to tell it to spin off the extra work to a different branch with a sub-agent or hand it to another Claude instance. Have it break plans down into small, focused PRs. You review each one quickly. By the time the first is merged, the second is ready for a look. Small changes move faster than big ones. They’re easier to review and revert. The next Claude session can build on them without drowning in context.

Resist Shiny Object Syndrome

AI makes every idea feel worth building. A new CRM integration? Twenty minutes. A settings page nobody asked for? An hour. A notification system you thought of in the shower? Done by lunch. You’ll have three more ideas by dinner.

I’ve caught myself building things just because I could. Shipped a feature in two hours, then realized nobody needed it. The code sat there doing nothing, making the codebase harder to work with. AI didn’t save me from a bad decision. It just let me make it faster.

Every feature you ship is a feature you maintain. It can break. It adds weight the AI has to navigate in every future session. The fact that something is easy to build does not make it worth building.

That said, this advice is for shipping products to real users. If you’re a hobbyist or building side projects, fully give in to shiny object syndrome. Claude Code can turn your what-if thoughts into fully working prototypes. That’s one of the best things about it.

There Are No Silver Bullets

The pace of change is fast and there are no signs of slowing down. Best practices shift with every model release and tool update. There are no silver bullets, and anyone claiming to know what’s best is lying. The advice in this post may be obsolete tomorrow.

What hasn’t changed: you still have to think. The AI writes the code. You decide what gets built, what gets shipped, and what gets thrown away. That part is still yours.

At least for now.

BoothIQ is a universal lead capture app that integrates with your calendar and CRM, making follow-up and sales a breeze.

FAQ

What AI coding tool do you use?

Claude Code from Anthropic. It runs in the terminal with direct access to the filesystem and git. It connects to dev tools through MCP (Model Context Protocol).

Do you still need to know how to code?

You need to understand what the AI is writing. If you don’t, ask it to explain. You can even set Claude Code’s output style to “Explanatory” in /config so it explains the why behind every change. Use it as a companion to level up your learning, not as an excuse to skip the fundamentals. This is where “trust, but verify” matters most: when the AI gives you an explanation, make it prove it. Tests, numbers, data.

How do you manage five Claude instances at once?

Git worktrees. Each instance gets its own directory and branch with its own running dev server. They share the database. I check diffs as they come in, approve or redirect, and merge when they’re clean. The limit is how many tasks I can keep in my head, not any technical constraint.

What if the AI keeps getting it wrong?

Kill the session and start a new one. That’s step one. Long conversations, especially after big planning sessions or context compactions, can confuse the model. I’ve seen it misinterpret what I said I wanted as what I didn’t want. If an agent seems to be losing the plot, a fresh session fixes it more often than arguing does.

If it’s still wrong after a fresh start, check two things. Does it have access to run the code, see errors, and read test output? Without that feedback loop, it’s guessing. Is your architecture fighting it? If Claude is doing something convoluted, it probably doesn’t have the right tools in place. Fix the root cause before blaming the model.

References

  • Stack Overflow 2025 Developer Survey: 84% of developers are using or planning to use AI tools, with 51% using them daily
  • METR Study on AI Developer Productivity: A rigorous early-2025 study found AI tools made experienced developers 19% slower. It tested Sonnet 3.5 and 3.7 era models without terminal-native agents or MCP. Since then, models like Opus 4.6 and tools like Claude Code have changed the picture. I went from writing 90% of my code in January 2025 to writing none by December. The methodology was sound. The conclusions describe a world that no longer exists.
  • Boris Cherny on keeping Claude Code vanilla: The creator of Claude Code on why he intentionally doesn’t customize it much.
  • Boris Cherny on voice input: Voice input makes him 3x faster with Claude Code.
  • CLAUDE.md Guidelines Derived from Andrej Karpathy: Four principles (think before coding, simplicity first, surgical changes, goal-driven execution) for reducing mistakes and rewrites.
  • Claude Code: Anthropic’s terminal-native AI coding agent.
  • Tidewave: MCP server that connects AI agents to your running web app for real-time logs, database queries, and REPL access.
  • Chrome DevTools MCP: MCP server for browser inspection and UI verification.
  • Wispr Flow: Voice dictation app for macOS.
  • Boris Cherny on Claude Code tips: Tips from the creator of Claude Code, including the Explanatory output style for learning.

Try BoothIQ free and see what one engineer with AI can build.

Want to learn more?

See how BoothIQ can transform your event lead capture and follow-up process.