Debugging With Claude Code as a Non-Dev | Coding Capybaras

Debugging with Claude Code when you can't read code fluently: the workflow, the exact prompts, and the five failure patterns that waste your whole afternoon.

· Justin Boggs

A magnifying glass resting on a desk next to a gray laptop computer

Photo by Agence Olloweb on Unsplash

Debugging with Claude Code as a non-developer works when you stop trying to diagnose the bug and start building a loop that diagnoses it for you. You cannot read the code well enough to spot the flaw — that's the premise, and pretending otherwise is what wrecks the afternoon. What you can do is describe the symptom precisely, hand Claude a check it can run itself, and refuse to accept "fixed" without evidence. That's the whole playbook. This post is the actual workflow I use, the exact prompts, and the five failure patterns that turn a ten-minute bug into a four-hour hole.

TL;DR

  • Your job isn't finding the bug. It's building the loop that finds it — give Claude a command it can run that returns pass or fail, and it will iterate without you.
  • Describe the symptom, the likely location, and what "fixed" looks like. "Fix the login bug" is the prompt that produces four hours of nothing.
  • Paste the actual error text. Not your paraphrase of it. Your paraphrase is where the information dies.
  • After two failed corrections, /clear and start over with a better prompt. A third correction almost never works — the context is polluted with failed attempts.
  • Demand evidence, not assertions. "The tests pass" means nothing. The test output means something.

Why debugging is different when you can't read the code

Here's the asymmetry nobody warns you about. When a developer debugs with an AI assistant, they're collaborating — the AI proposes something, they glance at the diff, and their gut says no, that's not it. That gut is doing enormous work, and you don't have it.

So the failure mode is specific. Claude proposes a fix. It looks reasonable. It compiles. You accept it. And it's wrong in a way you won't discover for two weeks, or it "fixes" the symptom by suppressing the error rather than solving the cause. Anthropic's own Claude Code best practices name this — they call it the trust-then-verify gap: "Claude produces a plausible-looking implementation that doesn't handle edge cases." Their prescribed fix is the sentence I'd tattoo on a non-tech founder's monitor: "If you can't verify it, don't ship it."

Which sounds like bad news, because you can't verify code by reading it. But verification doesn't mean reading. It means running something that tells you the truth. And that you can absolutely do.

This reframes the entire job. You are not the person who finds the bug. You are the person who builds the machine that finds the bug, and then checks the machine's receipts. Everything below follows from that.

The second thing worth internalizing: the same best-practices guide points out that "Claude stops when the work looks done. Without a check it can run, 'looks done' is the only signal available, and you become the verification loop: every mistake waits for you to notice it." Read that again as a non-developer. If you're the verification loop, and you can't read code, then there is no verification loop. The bug ships. That's not a Claude limitation — it's an architecture problem in how you're working, and it's fixable in one prompt.

Step 1: Describe the symptom, not the bug

The single highest-leverage change you can make is in the first sentence you type. Compare these two, straight from the Anthropic docs' own before/after table:

  • Before: "fix the login bug"
  • After: "users report that login fails after session timeout. check the auth flow in src/auth/, especially token refresh. write a failing test that reproduces the issue, then fix it"

The second one isn't better because it's longer. It's better because it contains three things the first one doesn't: the symptom (login fails after session timeout), the likely location (src/auth/, token refresh), and the definition of done (a test that reproduces it, then passes).

Here's the part that trips up non-developers: you think you can't supply the "likely location" because you don't know the codebase. You know more than you think. You know what you clicked. You know what page it happened on. You know it worked yesterday and didn't today. All of that is diagnostic gold, and none of it requires reading code.

A prompt template I actually use, verbatim:

When I [exact action I took], I expect [what should happen] but I get
[what actually happens]. Here's the exact error:

[paste the entire error, all of it, including the boring parts]

This worked [when it last worked, if you know]. The only thing that
changed since then is [what changed, if you know].

Before you change anything: find the root cause and explain it to me
in plain English. Don't fix it yet.

That last line matters more than the rest combined. "Don't fix it yet" separates diagnosis from treatment. Without it, Claude will start editing files inside of thirty seconds, and if the diagnosis was wrong, you now have a wrong fix layered on top of a bug — and you can't read the code well enough to unwind it.

One more thing on error messages: paste the whole thing. Non-developers habitually summarize errors because they look like noise. "It says something about a null." That stack trace you trimmed contains the file, the line number, and the call path. You threw away the answer because it looked ugly. The docs' common workflows guide is explicit here: "Tell Claude the command to reproduce the issue and get a stack trace."

Step 2: Give Claude a check it can run

This is the whole ballgame, and it's the step non-technical founders skip.

The best-practices guide puts it plainly: "Give Claude a check it can run: tests, a build, a screenshot to compare. It's the difference between a session you watch and one you walk away from." The check is anything that returns a signal Claude can read — a test suite, a build exit code, a linter, a script that diffs output against a fixture, or a browser screenshot compared against a design.

Why this matters so much for you specifically: a check converts a problem you can't evaluate (is this code correct?) into a problem you can (did the command print pass or fail?). You don't need to understand the fix. You need the fix to be provable.

So instead of:

"the checkout page is broken, fix it"

You write:

"the checkout page throws [error] when I click Subscribe. Write a failing test that reproduces this first. Then fix the root cause — don't suppress the error. Then run the test and show me the output."

Now Claude has a closed loop. It writes the test, watches it fail, fixes the code, runs the test, reads the result, and iterates until it passes — without you. The docs describe exactly this: "Claude does the work, runs the check, reads the result, and iterates until the check passes."

For UI bugs, the check is visual. Paste a screenshot of what's wrong. Claude Code takes images directly — drag and drop into the window, or Ctrl+V (Cmd+V works in iTerm2 on macOS). Then ask it to take a screenshot of the result and compare. For a non-developer this is enormous, because a screenshot is a spec you're fully qualified to write.

And critically — demand the evidence, not the verdict. The docs again: "Have Claude show evidence rather than asserting success: the test output, the command it ran and what it returned, or a screenshot of the result." When Claude says "I've fixed the issue and the tests pass," that's an assertion. Ask for the terminal output. Nine times out of ten it's real. The tenth time is the one that would have shipped.

Step 3: Know the five ways this goes wrong

The best-practices guide has a section called "Avoid common failure patterns," and every one of them hits non-technical founders harder than developers. Here they are with what they feel like from your chair:

| Failure pattern | What it feels like | The fix | | --- | --- | --- | | The kitchen sink session | You started on the checkout bug, asked about the email template, went back to checkout. Claude seems dumber than an hour ago. | /clear between unrelated tasks | | Correcting over and over | Third correction on the same bug. Each fix breaks something new. | After two failed corrections, /clear and rewrite the prompt with what you learned | | The over-specified CLAUDE.md | Claude ignores rules you explicitly wrote down. | Prune it. Bloated files bury the important rules | | The trust-then-verify gap | It looked right, you shipped it, it broke in production. | Always provide a check. If you can't verify it, don't ship it | | The infinite exploration | You asked it to "look into" something. It read 200 files and now it's confused. | Scope it, or delegate to a subagent |

The second one deserves its own paragraph because it is the non-developer trap. When you can't read code, correcting feels like your only lever, so you pull it repeatedly. But each failed attempt stays in the conversation, and Claude is now reasoning in a context stuffed with approaches that didn't work. The docs are unambiguous: "If you've corrected Claude more than twice on the same issue in one session, the context is cluttered with failed approaches. Run /clear and start fresh with a more specific prompt that incorporates what you learned. A clean session with a better prompt almost always outperforms a long session with accumulated corrections."

I resisted this for months. It feels like giving up — you're throwing away all that context, all that progress. You're not. You're throwing away three failed theories and keeping the one thing that had value: what you learned. Write it into a fresh prompt and go again. The whole loop looks like this:

flowchart TD
    A[Bug appears] --> B[Paste exact error + symptom + last known good]
    B --> C{Ask for root cause<br/>DON'T fix yet}
    C --> D[Claude explains cause in plain English]
    D --> E{Does the explanation<br/>match what you saw?}
    E -->|No| F[Correct once with the detail it missed]
    F --> C
    E -->|Yes| G[Ask for a failing test that reproduces it]
    G --> H[Claude fixes + runs the check]
    H --> I{Show me the output}
    I -->|Pass, evidence shown| J[Done — commit]
    I -->|Fail, 2nd time| K["/clear and restart<br/>with what you learned"]
    K --> B

Notice where the loop exits to /clear. That's not failure — it's the designed escape hatch, and using it early is what separates a thirty-minute bug from a lost day.

Step 4: The tools that do the heavy lifting

A few Claude Code features carry disproportionate weight when you can't read code. None of them require you to.

Plan mode. Claude reads files and proposes a plan without touching anything. Press Shift+Tab to cycle into it, or start with claude --permission-mode plan. For debugging, this is how you get diagnosis without treatment. You can read a plan in English. You can't read a diff. The docs note it's most useful "when you're uncertain about the approach, when the change modifies multiple files, or when you're unfamiliar with the code being modified" — which describes literally every bug you'll ever hit.

/rewind and checkpoints. Every prompt creates a checkpoint. Double-tap Escape or run /rewind to restore the conversation, the code, or both. This is your undo button, and it's why you can afford to let Claude try something risky. One warning from the docs worth knowing: checkpoints only track changes made through Claude's file editing tools, not changes made via Bash commands. It's not a replacement for git.

Subagents. When you need something investigated, say "use a subagent to investigate how the checkout flow handles failed payments." The subagent reads files in its own context window and reports back a summary — your main conversation stays clean. This directly defuses the infinite-exploration trap. You can also use one to grade the work: "use a subagent to review this fix for edge cases." A fresh reviewer that didn't write the code isn't biased toward it.

/context. Shows you a live breakdown of what's eating your context window. When things start feeling foggy, this tells you whether you're near the limit — which is usually the real reason Claude seems to have gotten worse.

CLAUDE.md. A file Claude reads at the start of every session. Put the things it can't guess: your commands, your gotchas, your architecture rules. Keep it short — the docs are emphatic that "bloated CLAUDE.md files cause Claude to ignore your actual instructions." The test they give for every line: "Would removing this cause Claude to make mistakes?" If not, cut it. The CLAUDE.md in the Coding Capybaras boilerplate is exactly this — the rules about which regions are safe to edit, so Claude doesn't wander into the platform plumbing while chasing a bug in your product code.

If you're newer to the tool, the Claude Code starter guide for non-developers covers install and first session, and the underused features post goes deeper on the ones above.

Frequently asked questions

What if I don't understand Claude's explanation of the bug?

Say so. "Explain that again like I've never seen this codebase" is a completely legitimate prompt and it works. If you approve a fix you don't understand at the level of what went wrong and why, you've skipped the only quality gate you actually have. Reading the output well enough to judge it is a learnable skill — I broke it down in how to read your AI's output when you don't speak code.

How do I know if Claude actually fixed it or just hid the error?

Ask for the root cause in plain English before any fix, and ask "did you address the root cause or suppress the symptom?" after. The docs specifically flag this pattern — the recommended prompt is "fix it and verify the build succeeds. address the root cause, don't suppress the error." Suppression looks like a passing build and a bug that returns in a month.

Should I use plan mode for every bug?

No. The docs put it well: "If you could describe the diff in one sentence, skip the plan." A typo or a log line doesn't need planning overhead. Anything touching multiple files, or anything you don't understand, does.

Why does Claude seem to get worse the longer I work?

Because it does, and it's not your imagination. Performance degrades as the context window fills — every file read and command output takes up space. Run /context to see, and /clear between unrelated tasks. This is the most common self-inflicted wound in AI-assisted debugging.

What's the difference between /clear and /rewind?

/clear wipes the conversation and starts fresh — use it between unrelated tasks or after failed corrections. /rewind restores a previous state, including the code, so you can undo changes and try a different approach. /clear forgets; /rewind un-does.

Can I just let it run unattended and check later?

Only if the check is airtight. That's the entire point of step 2 — an unattended run is only as trustworthy as the pass/fail signal it's iterating against. With a real test suite gating the work, yes. Without one, you're just generating plausible code with nobody home to catch it.

The one habit that matters

If you take one thing from this: debugging with Claude Code isn't about getting better at reading code. It's about getting better at building loops. Symptom in, evidence out, and a hard rule that "it works now" is a claim requiring proof rather than a status update you accept.

That reframe took me longer to find than it should have. I spent months squinting at diffs I couldn't evaluate, feeling like the bottleneck, assuming the answer was to eventually learn enough to review the code myself. It wasn't. The answer was to stop being the verification loop and start designing one — which, it turns out, is a founder skill, not an engineering skill. You already know how to define done. That's the whole job.

The Coding Capybaras boilerplate ships with the CLAUDE.md rule files that make this loop work out of the box — the architecture is documented for the AI, so when you paste an error at 11pm, Claude already knows which region of the codebase it's allowed to touch.