A loop, not an oracle
Claude Code is not a chatbot that emits a block of code for you to paste. It runs a loop:
- Explore — read files, grep for symbols, run read-only commands to understand the situation.
- Plan — decide on a sequence of edits and commands.
- Act — edit files and run your build, tests, or tools.
- Verify — read the output, see whether it worked, and correct course.
It repeats that loop until the goal is met or it needs you. The single biggest shift from “AI that writes code” to “agent that does work” is that verification is built in: Claude runs ./gradlew test, reads the red, and fixes it — the same loop you run by hand, just faster.
This is why Java is a good fit. We have fast, reliable verifiers: a compiler that catches type errors, a test suite, static analysis. Here is the idea that runs under this entire course — call it the price of verification: the cheaper and more reliable the check that proves a change correct, the more of that work you can safely hand to an agent. Where a verifier is cheap (a test, a compile), delegate freely; where it’s expensive or missing (an API contract, a security boundary), stay hands-on. You’ll meet this thread again in Module 5 and Module 8.
Give Claude a way to check its own work, and it will use it on every turn. A meaningful test suite is the best prompt you never wrote.
Prompt the goal, not the keystrokes
The most common mistake is prompting Claude like an autocomplete: “add a getter here.” That wastes the agent. Describe the outcome and the constraints, and let it find the path.
Compare:
# Weak — you're doing the thinking
> Add a field `private boolean archived` to Order.
# Strong — you state intent and constraints
> Orders need to be archivable. Add an `archived` flag that defaults
to false, expose it through the REST layer, make sure it's
persisted via JPA, and add a Liquibase changeset for the column.
Keep existing endpoints backward compatible and add tests.
The strong version gives Claude enough to plan a multi-file change and verify it. Good prompts for Java work usually name:
- The intent — what should be true when you’re done.
- The conventions — “match the existing tests,” “use constructor injection, not field injection,” “AssertJ, not Hamcrest.”
- The boundaries — what not to touch, backward-compatibility requirements, modules to leave alone.
- The done condition — “the new test passes and
mvn verifyis green.”
Use plan mode for anything non-trivial
Before Claude changes code, you often want to see its approach. Pressing Shift+Tab cycles through the permission modes, and one of them is plan mode: Claude researches and writes a plan but makes no edits until you approve it. (You’ll see the full set of modes in Module 3.)
# Enter plan mode (Shift+Tab), then:
> We need to introduce optimistic locking on the Account aggregate
to fix the lost-update bug. Plan the change across the entity,
the repository, the service, and the tests.
You get a reviewable plan — which entities get a @Version column, which tests need to assert on OptimisticLockException, which migration is required — before a line changes. For a Java developer this is the equivalent of reviewing a design before the PR, and it is where you catch a wrong approach cheaply.
Let it think harder when the problem is hard
For genuinely tricky reasoning — a concurrency bug, a subtle generics problem, an architectural trade-off — you can nudge Claude to spend more effort before it acts by asking it to think the problem through (stronger phrasings like “think hard about this first” push further). It trades latency for depth.
> This ExecutorService occasionally deadlocks under load. Think hard
about the lock ordering and the thread-pool sizing before you
propose a fix.
Reserve this for problems where the answer isn’t obvious. For routine edits it just slows you down.
Reference files and feed in output
A few input shortcuts pay off constantly:
@references a file or directory so Claude reads exactly what you mean:@src/main/java/com/acme/OrderService.java.!runs a shell command and puts its output into the conversation. Great for handing Claude a stack trace:!mvn testthen ask it to fix the failure it sees.- Paste a stack trace or build log directly. Claude is very good at reading a Java stack trace and walking to the root cause — give it the whole thing, not a paraphrase.
> Here's the failure from CI:
!cat target/surefire-reports/com.acme.OrderServiceTest.txt
Find the root cause and fix it.
Keep context clean
Claude works from a context window — everything in the current conversation. Two habits keep it sharp:
/clearbetween unrelated tasks. Finished the migration and now fixing an unrelated test? Clear first. A context full of the previous job degrades the next one.- Don’t hoard one giant session. Long, drifting conversations accumulate dead ends and stale assumptions. Short, goal-shaped sessions outperform marathon ones.
When a task is large and long-running, Claude summarises older context automatically so work can continue — but you’ll still get better results by scoping sessions deliberately.
Tip: If Claude heads down the wrong path, interrupt it (Esc), correct course in one sentence, and let it continue. You don’t have to let a turn finish before steering. Catching a wrong turn early is cheaper than reviewing a wrong diff.
What just happened
You learned that Claude Code is a verify-as-it-goes loop, that the quality of your prompt is mostly about stating intent and constraints, and that plan mode lets you review the approach before any code changes. Next you’ll make Claude permanently smarter about your project.
Key takeaways
- The loop is explore → plan → act → verify; built-in verification is why it works on real code.
- Prompt the outcome and constraints, not individual edits; name conventions, boundaries, and a done condition.
- Use plan mode (Shift+Tab) for non-trivial changes; add “think” for hard reasoning.
@references files,!injects command output, and pasted stack traces are gold./clearbetween unrelated tasks — context hygiene is a performance setting.