You write Java for a living, and you have heard that Claude Code can work on your project from the terminal. This is a safe, small way to try it on real code.
You will install it, start it on a Spring Boot project, fix a failing test and add a new endpoint. You will see every prompt, every question it asks and every change it makes.
What you will do
You will install Claude Code, open a small Spring Boot project with it, and finish two tasks. First, you fix a failing test by changing the code.
Second, you add a GET /orders/{id} endpoint with tests. You review each change before you commit.
In our test run, Claude Code worked for under three minutes in total across all the prompts. You will need more time than that, because installing, signing in and reading each diff take longer than the typing.
Allow about an hour the first time. That hour is our guess, not a measurement.
You need a JDK (we used 25), Git, a terminal and a Claude account. Basic Spring Boot knowledge helps. You do not need to know Claude Code.
Everything below comes from one real test run: Claude Code 2.1.309 on 24 October 2026, Windows 11 with Git Bash, JDK 25 and Spring Boot 4.1.2. Some screens we could not see, such as the first sign-in. Those parts come from the official docs and say so.
We ran the first prompt and the two tasks in the terminal interface. We ran one side experiment, in the "What went wrong" section, non-interactively with claude -p. That section says which one.
What Claude Code is, in plain words
Claude Code is a coding agent that works in your terminal. An agent is a program that picks its own next step, uses a tool, looks at the result and repeats until the job is done.
Claude Code reads your project, runs commands and edits files. In Manual mode, it asks before it edits a file or runs a command. It is not autocomplete.
Autocomplete finishes the line you are typing. Claude Code takes a task, such as "fix the failing test", and works across files.
Your files, commands and edits stay on your machine. The thinking is done by a model that Claude Code reaches over the network, so it sends your prompt and the parts of the project it has read. Figure 1 shows the whole loop.
It can be wrong. It can write a test that proves nothing, or touch a file you did not expect. You review its work.
Read the diff before you commit. Every time.
Before you install: what you need
This list comes from the advanced setup page of the official docs, read on 24 October 2026. It changes, so check the page before you start. We do not list prices, for the same reason.
- Account. A Pro, Max, Team, Enterprise or Console account. The free Claude plan does not include Claude Code. You can also use a cloud provider: Amazon Bedrock, Google Cloud's Agent Platform or Microsoft Foundry.
- System. macOS 13.0 or later, Windows 10 1809 or later (or Windows Server 2019 or later), Ubuntu 20.04 or later, Debian 10 or later, or Alpine Linux 3.19 or later.
- Hardware and network. 4 GB of RAM or more, an x64 or ARM64 processor, and an internet connection.
- Shell. Bash, Zsh, PowerShell or CMD.
- Location. A country on Anthropic's supported list.
- Windows. Git for Windows is recommended. Without it, Claude Code uses PowerShell as its shell tool.
For this article you also need a JDK 25 and Git. JDK 25 is the current Java LTS, and the example project asks for it.
Install it
Pick the block for your system. The first command in each block is the native installer, which the docs mark as recommended.
It updates itself in the background. Homebrew, WinGet and the Linux package managers do not update themselves.
- macOS
- Linux and WSL
- Windows PowerShell
- Windows CMD
curl -fsSL https://claude.ai/install.sh | bash
Other methods from the docs: Homebrew, or npm (Node.js 22 or later).
brew install --cask claude-code
npm install -g @anthropic-ai/claude-code
Homebrew has two casks. claude-code follows the stable channel, about a week behind.
claude-code@latest gets new versions at once. Update Homebrew installs with brew upgrade claude-code.
curl -fsSL https://claude.ai/install.sh | bash
Other methods from the docs: npm (Node.js 22 or later), or a package manager. Signed repositories exist for apt (Debian and Ubuntu), dnf (Fedora and RHEL) and apk (Alpine). Their setup takes several steps, so follow the Linux package manager section of the docs.
npm install -g @anthropic-ai/claude-code
In WSL, open your Linux distribution and run the command there, not from PowerShell. Do not use sudo with npm.
irm https://claude.ai/install.ps1 | iex
Other methods from the docs: WinGet, or npm (Node.js 22 or later).
winget install Anthropic.ClaudeCode
npm install -g @anthropic-ai/claude-code
You do not need to run as Administrator. WinGet installs do not update themselves. Run winget upgrade Anthropic.ClaudeCode now and then.
curl -fsSL https://claude.ai/install.cmd -o install.cmd && install.cmd && del install.cmd
Your prompt shows PS C:\ in PowerShell and C:\ in CMD. If you see The token '&&' is not a valid statement separator, you are in PowerShell. Use the PowerShell tab instead.
The installer shows no progress while it downloads. When it finishes, open a new terminal window and check the version:
claude --version
Our run printed this:
2.1.309 (Claude Code)
Your number will be higher or lower. For a deeper check, run claude doctor. The docs say it prints read-only diagnostics about your install and settings.
If something is off
These rows come from the install troubleshooting page and the network configuration page. We did not hit these errors in our run, so we did not reproduce them.
| What you see | What to try |
|---|---|
command not found: claude (macOS) or 'claude' is not recognized (Windows) | The install folder is not on your PATH. The installer puts claude in ~/.local/bin (macOS and Linux) or %USERPROFILE%\.local\bin (Windows). On macOS with Zsh (use ~/.bashrc for Bash), run echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc and then source ~/.zshrc. Open a new terminal. |
permission denied when adding to ~/.zshrc or ~/.bashrc | Your user cannot write that file. Run ls -l ~/.zshrc to see the owner. If it is another user, use sudo chown $(whoami) ~/.zshrc. If it is you, use chmod u+w ~/.zshrc. Then repeat the PATH step. |
| Install fails behind a corporate proxy or VPN | Set HTTPS_PROXY (for example export HTTPS_PROXY=https://proxy.example.com:8080) before you start claude. For a company certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca-cert.pem. SOCKS proxies are not supported. Start claude --debug to see what loaded. |
TLS errors such as curl: (35) TLS connect error | Update your system certificates. On Ubuntu or Debian: sudo apt-get update && sudo apt-get install ca-certificates. |
WSL: Exec format error | You are on WSL 1. Convert the distribution with wsl --set-version <DistroName> 2 in PowerShell. |
| WSL: the browser does not open for sign-in, or the sign-in does not return | Paste the login code into the terminal at the Paste code here if prompted prompt. You can also run claude auth login, or set the BROWSER variable to your Windows browser. |
Get the example project
We start from a failing test for two reasons. It gives Claude Code something concrete to work on. And it gives you a clear pass or fail, so you do not have to trust anyone's word that it worked.
The project is a small Spring Boot orders service. It uses Maven (the wrapper is included), an in-memory H2 database and nothing else.
It lives in the AgentWorks HQ repository, in examples/claude-code-java/part-01/start. The finished version, after both tasks, is in part-01/finished.
We copy the folder out of the clone and make a fresh Git repository. That gives you a clean git diff later.
- macOS, Linux, WSL, Git Bash
- Windows PowerShell
git clone --depth 1 https://github.com/dvarahq/agentworkshq.git
cp -r agentworkshq/examples/claude-code-java/part-01/start orders-service
cd orders-service
git init
git add -A
git commit -m "Start of Part 1"
git clone --depth 1 https://github.com/dvarahq/agentworkshq.git
Copy-Item -Recurse agentworkshq\examples\claude-code-java\part-01\start orders-service
cd orders-service
git init
git add -A
git commit -m "Start of Part 1"
If Git asks who you are, set user.name and user.email first. On Windows, Git may warn that LF will be replaced by CRLF. You can ignore that warning here.
Check your Java version:
java -version
Our run printed this:
openjdk version "25.0.4.1" 2026-08-18 LTS
OpenJDK Runtime Environment Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode, sharing)
Now run the tests. On Windows PowerShell or CMD, use .\mvnw.cmd test.
./mvnw test
The first run downloads Maven and the libraries. On a fresh Maven cache it took 1 minute 55 seconds on our connection.
Later runs took about 30 seconds. Here is the failure, trimmed:
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.93 s -- in com.agentworks.orders.OrderControllerTest
[INFO] Running com.agentworks.orders.OrderServiceTest
[ERROR] Tests run: 3, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.528 s <<< FAILURE! -- in com.agentworks.orders.OrderServiceTest
[ERROR] com.agentworks.orders.OrderServiceTest.appliesTenPercentDiscountBeforeTax -- Time elapsed: 0.021 s <<< FAILURE!
org.opentest4j.AssertionFailedError:
[discount for a 90.00 subtotal: the threshold applies to the subtotal before tax]
expected: 0.00
but was: 10.80
at com.agentworks.orders.OrderServiceTest.appliesTenPercentDiscountBeforeTax(OrderServiceTest.java:48)
...
[ERROR] Tests run: 6, Failures: 1, Errors: 0, Skipped: 0
...
[ERROR] BUILD FAILURESix tests ran and one failed. The message says what is wrong: a 90.00 subtotal got a 10.80 discount.
The threshold should look at the subtotal before tax. 90.00 plus 20 percent tax is 108.00, which crosses 100.00. That is the bug.
Figure 2 shows where the test and the code live. The failing test is in OrderServiceTest. The code it checks is in OrderService.
orders-service/
├── pom.xml
├── mvnw, mvnw.cmd
└── src/
├── main/java/com/agentworks/orders/
│ ├── ApiExceptionHandler.java
│ ├── CreateOrderRequest.java
│ ├── Order.java, OrderItem.java
│ ├── OrderController.java
│ ├── OrderRepository.java
│ ├── OrderResponse.java
│ ├── OrderService.java <- the fix lands here in our run
│ └── OrdersServiceApplication.java
└── test/java/com/agentworks/orders/
├── OrderControllerTest.java
└── OrderServiceTest.java <- the failing test: leave it alone
Figure 2: The project tree of start/. The two highlighted files are the failing test and the one file the fix changed in our run. The fix changed one file, not two.
Your first session
Open the project folder in your terminal and start Claude Code:
cd orders-service
claude --permission-mode manual
Why the flag? The docs say that in version 2.1.283 and later, a new terminal session starts in Auto mode. In Auto mode, a separate classifier reviews most actions instead of you.
That is fine later. For learning, you want to see every question, so we start in Manual mode.
The CLI accepts manual as another name for default. Part 5 covers modes.
What you see on first run
1. Sign-in (from the docs). On first use, Claude Code asks you to log in. For subscription and Console accounts, you finish in the browser. If you run in WSL 2, over SSH or in a container, the browser may show a code instead. Paste it at the Paste code here if prompted prompt. Our machine was already signed in, so we did not see this screen.
2. The trust question (our run). The first time you open a folder, you get this:
Accessing workspace:
C:\work\orders-service
Quick safety check: Is this a project you created or one you trust? (Like your own code, a well-known open
source project, or work from your team). If not, take a moment to review what's in this folder first.
Claude Code'll be able to read, edit, and execute files here.
Security guide
❯ No, exit
Yes, I trust this folder
Enter to confirm · Esc to cancelThe highlighted choice is No, exit. Press the down arrow, then Enter on Yes, I trust this folder. Trusting means Claude Code can read, edit and run commands in this folder.
Say yes only for code you know. The docs say trust is saved per folder.
3. The prompt box (our run). After you trust the folder, you see a small header and a prompt:
▐▛███▛█ Claude Code v2.1.309
...
▝▝ ▝▝ C:\work\orders-service
...
❯ Try "how does <filepath> work?"
...
⏸ manual mode on · ? for shortcuts · ← for agentsThe header lines we cut show the model and your plan. The grey text after ❯ is only a hint, not something you typed.
The footer says manual mode on, which confirms the mode. Press ? to see the shortcuts:
! for shell mode double tap esc to clear input ctrl + shift + _ to undo
/ for commands shift + tab to auto-accept edits alt + v to paste images
@ for file paths ctrl + o for verbose output alt + p to switch model
/btw for side question ctrl + t to toggle tasks ctrl + s to stash prompt
backslash (\) + return (⏎) for ctrl + g to edit in $EDITOR
newline /keybindings to customizeThree of these matter today. ! runs a shell command.
/ lists commands. @ completes file paths.
The first prompt
We start with a question, not a change. It costs nothing to ask, and it shows whether Claude Code understood the project.
Explain what this project does and how to run its tests.
It read a few files and answered. This is the response, trimmed to the answer:
First prompt and answer
❯ Explain what this project does and how to run its tests.
Searched for 1 pattern, read 3 files, ran 1 shell command
● What it does
orders-service is a small Spring Boot 4.1.2 REST API for orders. It's the starting project for the "Claude
Code for Java Developers" article series. It uses Spring Web MVC, Spring Data JPA, bean validation and an
in-memory H2 database, so you don't need Docker or a database server.
Endpoints (OrderController):
- POST /orders creates an order from a customer email and a list of items. Each item has a product name,
quantity and unit price. It returns 201.
- GET /orders lists all orders.
Pricing rules (OrderService, per the README):
- Tax is 20% of the subtotal.
- A subtotal of 100.00 or more gets 10% off. The discount is applied before tax.
- Amounts are rounded to 2 decimals, half up.
ApiExceptionHandler turns errors into JSON error bodies.
How to run the tests
You need JDK 25 and Git. The Maven wrapper downloads Maven itself.
.\mvnw.cmd test # Windows PowerShell / CMD
./mvnw test # Git Bash, macOS, Linux, WSL
The first run downloads dependencies and takes a few minutes. Later runs take under a minute.
One failure is expected. The README says this folder is the "start" state and has one failing test on
purpose. You should see 6 tests run with 1 failure, OrderServiceTest.appliesTenPercentDiscountBeforeTax.
That test covers the discount rule, and fixing it is the first task in the article. I haven't run the tests
myself, so that result comes from the README.
To start the app, run ./mvnw spring-boot:run. It listens on port 8080.
✻ Baked for 11s · done 1:29 AMTwo details are worth noticing. It found the README and used it.
And it said plainly that it had not run the tests, so it could not confirm the failure. It did not guess.
Task 1: fix the failing test
Now the real work. Figure 3 shows the loop we follow. The orange boxes are the moments where you decide.
Here is the prompt we used:
Run the tests with ./mvnw test. One test fails. Find the cause and fix the code, not the test.
On Windows PowerShell, write .\mvnw.cmd test instead. Three parts matter. It says how to run the tests.
It names the problem. And it says what to change.
The sentence "fix the code, not the test"
A test is the written rule. If an agent wants a green build, the quickest way can be to change the rule.
Then the build passes and proves nothing. This sentence closes that door.
We should be honest about our run. In one non-interactive attempt we left the sentence out, and Claude Code still fixed the code. The sentence is cheap insurance, not a magic spell.
The permission questions
Claude Code asked before it ran the tests. This is the real screen:
Bash command
Tip: auto mode handles these prompts for you — choose "switch to auto mode" below
Run shell command
./mvnw test 2>&1 | tail -40
This command requires approval
Do you want to proceed?
❯ 1. Yes
2. Yes, and don’t ask again for: ./mvnw test *
3. Yes, and switch to auto mode · auto mode handles these prompts for you
4. No
Esc to cancel · Tab to amendHere is what each answer means, using the CLI's own words:
- 1. Yes runs this one command. Ask again next time.
- 2. Yes, and don’t ask again for
./mvnw test *saves a rule. The docs say a "don't ask again" answer for Bash commands lasts permanently for this repository and this command. - 3. Yes, and switch to auto mode changes the whole session to Auto mode.
- 4. No declines. Claude Code asks what to do instead.
We chose 1. Tab lets you add a comment to your answer. Esc cancels.
Next it showed the edit it wanted to make, as a diff. Lines with a minus sign are removed. Lines with a plus sign are added.
Permission question for an edit
Edit file
src\main\java\com\agentworks\orders\OrderService.java
28 BigDecimal subtotal = order.getItems().stream()
29 .map(OrderItem::lineTotal)
30 .reduce(BigDecimal.ZERO, BigDecimal::add);
31 - BigDecimal tax = money(subtotal.multiply(TAX_RATE));
32 - BigDecimal totalWithTax = money(subtotal.add(tax));
33 -
34 - // Orders of 100 or more get 10 percent off.
35 - BigDecimal discount = totalWithTax.compareTo(DISCOUNT_THRESHOLD) >= 0
36 - ? money(totalWithTax.multiply(DISCOUNT_RATE))
31 + // Subtotals of 100 or more (before tax) get 10 percent off, applied before tax.
32 + BigDecimal discount = subtotal.compareTo(DISCOUNT_THRESHOLD) >= 0
33 + ? money(subtotal.multiply(DISCOUNT_RATE))
34 : money(BigDecimal.ZERO);
35 + BigDecimal taxable = money(subtotal).subtract(discount);
36 + BigDecimal tax = money(taxable.multiply(TAX_RATE));
37
39 - order.setAmounts(money(subtotal), discount, tax, totalWithTax.subtract(discount));
38 + order.setAmounts(money(subtotal), discount, tax, taxable.add(tax));
39 return repository.save(order);
40 }
41
Do you want to make this edit to OrderService.java?
❯ 1. Yes
2. Yes, and switch to accept edits (auto-approve file edits and common file commands) for this session
(shift+tab)
3. No
Esc to cancel · Tab to amendThe edit prompt has a different second option: Yes, and switch to accept edits ... for this session. The docs say file-edit approvals last until the session ends. We chose 1 again.
Read the diff yourself. The old code worked out tax first, then checked the threshold against the total with tax, then took 10 percent off that total.
The new code checks the subtotal, takes 10 percent off, and charges tax on what is left. That matches the rule in the README.
Claude Code then ran the tests, and told us what it found:
The result
● I fixed OrderService.create in OrderService.java, and all 6 tests now pass (BUILD SUCCESS).
Cause: create worked out tax first and then checked the 100.00 threshold against the total with tax. It also
took the 10% discount off that total. This broke the stated rule in two ways:
- A 90.00 subtotal becomes 108.00 with tax, which crosses the threshold, so it wrongly got a 10.80 discount.
- Tax was charged on the full subtotal instead of the discounted one.
Fix: The code now follows the order the README describes:
1. It checks the threshold against the subtotal before tax.
2. It takes 10% off that subtotal.
3. It charges 20% tax on the discounted amount.
4. The total is the discounted amount plus that tax.
I didn't change the tests.
✻ Cooked for 1m 20s · done 1:33 AMIt says "I didn't change the tests", and the diff agrees. That whole step took 1 minute 20 seconds.
Review it yourself
Do not stop at the summary. Type /diff. The docs describe it as a way to review the changes in your working tree, including Claude's edits.
In our terminal it opened a panel next to the conversation. The header said 1 file changed +6 -7, which matches the edit above.
Then run the tests yourself. A line that starts with ! runs a shell command and adds its output to the session:
!./mvnw test
Our run printed Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 and BUILD SUCCESS. Claude Code then commented on the output.
You can run the same command in a second terminal if you prefer. The point is that you see the result with your own eyes.
Do not commit yet. We wait until the end so you see the whole flow. In real work, commit after each task.
Task 2: add GET /orders/{id}
Same pattern, with more detail. A good prompt for a feature gives the requirement and the rules:
Add GET /orders/{id}. It returns the order as JSON. If no order has that id, return 404 with a JSON problem body. Add tests for both cases. Follow the style of the existing code, and run the tests with ./mvnw test when you are done.
Count what the prompt carries. The behavior (return the order). The error case (404 with a problem body).
The tests (both cases). The style rule (follow the existing code).
The check (run the tests). Claude Code read four files, then proposed edits in a batch.
The batch of edits
❯ Add GET /orders/{id}. It returns the order as JSON. If no order has
that id, return 404 with a JSON problem body. Add tests for both
cases. Follow the style of the existing code, and run the tests
with ./mvnw test when you are done.
Read 4 files
● Write(src\main\java\com\agentworks\ord…\OrderNotFoundException.java)
● Update(src\main\java\com\agentworks\orders\OrderService.java)
● Update(src\main\java\com\agentworks\orders\OrderController.java)
● Update(src\main\java\com\agentworks\orders\OrderController.java)
● Update(src\main\java\com\agentworks\orders\ApiExceptionHandler.java)
● Update(src\test\java\com\agentworks\orders\OrderControllerTest.java)
● Update(src\test\java\com\agentworks\orders\OrderControllerTest.java)
Create file
src\main\java\com\agentworks\orders\OrderNotFoundException.java
1 package com.agentworks.orders;
2
3 public class OrderNotFoundException extends RuntimeException {
4
5 public OrderNotFoundException(Long id) {
6 super("No order with id " + id);
7 }
8 }
Do you want to create OrderNotFoundException.java?
❯ 1. Yes
2. Yes, and switch to accept edits (auto-approve file edits and
common file commands) for this session (shift+tab)
3. No
Esc to cancel · Tab to amendThe /diff panel was still open on the right in this capture, so the transcript shows only the left half of the screen. The first question was about a new file, OrderNotFoundException.java. This time we chose option 2, switch to accept edits for this session.
The footer then read accept edits on. File edits went through without a question after that. Commands still asked.
You can switch modes yourself with Shift+Tab. Use accept edits only when you plan to review the diff anyway.
What it built
Claude Code's summary was clear:
The result
● GET /orders/{id} now returns the order as JSON, or a 404 with a JSON
problem body when no order has that id. ./mvnw test passes: 8
tests, 0 failures.
Changes in src/main/java/com/agentworks/orders/:
- OrderController: new get method mapped to /{id}. It returns
OrderResponse, the same shape as the list endpoint.
- OrderService: new findById, a read-only transaction that throws
OrderNotFoundException when the id is missing.
- OrderNotFoundException: new file, a small runtime exception.
- ApiExceptionHandler: new handler that turns the exception into a
ProblemDetail. The status is 404, the title is "Order not found",
and the detail is "No order with id N". It follows the pattern of
the existing validation handler.
Tests added to OrderControllerTest:
- getByIdReturnsTheOrder creates an order, fetches it by id, and
checks the id, email, first item and total.
- getByIdReturnsNotFoundForAnUnknownOrder requests id 999999 and
checks for a 404 with the title and status 404.
The README's layout section doesn't mention the new endpoint or
exception class. I left it alone since you didn't ask for it.
✻ Brewed for 48s · done 1:38 AMNow review it. Stage everything and look at the size of the change:
git add -A
git diff --cached --stat
.../com/agentworks/orders/ApiExceptionHandler.java | 8 +++++++
.../com/agentworks/orders/OrderController.java | 6 ++++++
.../agentworks/orders/OrderNotFoundException.java | 8 +++++++
.../java/com/agentworks/orders/OrderService.java | 18 ++++++++++------
.../com/agentworks/orders/OrderControllerTest.java | 25 ++++++++++++++++++++++
5 files changed, 58 insertions(+), 7 deletions(-)
That is five files, and it includes the Task 1 fix. The new endpoint is small. This is the controller change, from git diff:
+ @GetMapping("/{id}")
+ public OrderResponse get(@PathVariable Long id) {
+ return OrderResponse.from(service.findById(id));
+ }
And the service method, which throws when the id is missing:
+ @Transactional(readOnly = true)
+ public Order findById(Long id) {
+ return repository.findById(id).orElseThrow(() -> new OrderNotFoundException(id));
+ }
The handler turns that exception into a JSON problem body with status 404. It follows the pattern of the validation handler that was already there. That is what "follow the existing style" bought us.
The change we asked for
We read the tests too. The 404 test checked the title and the status, but not the detail text.
A wrong message would still pass. So we asked for one more thing:
The 404 test does not check the detail text. Make it check that the detail names the missing id, and run the tests again.
The follow-up
❯ The 404 test does not check the detail text. Make it check that the
detail names the missing id, and run the tests again.
● Update(src\test\java\com\agentworks\orders\OrderControllerTest.java)
⎿ Added 2 lines, removed 1 line
71 mvc.perform(get("/orders/{id}", 999999))
72 .andExpect(status().isNotFound())
73 .andExpect(jsonPath("$.title").value(
"Order not found"))
74 - .andExpect(jsonPath("$.status").value
-(404));
74 + .andExpect(jsonPath("$.status").value
+(404))
75 + .andExpect(jsonPath("$.detail").value
+("No order with id 999999"));
76 }
77 }
● Running ./mvnw test 2>&1 | grep -E "Tests run|BUILD|FAIL|…
⎿ $ ./mvnw test 2>&1 | grep -E "Tests run|BUILD|FAIL|ERROR" | head
-30You do not start over when a first attempt is close. You say what is missing. The edit went through without a question, because we were in accept edits mode.
The command still asked. Then we ran the tests ourselves with !./mvnw test, in a new session on the finished project:
Running the tests with the ! prefix
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 13.03 s -- in
com.agentworks.orders.OrderControllerTest
[INFO] Running com.agentworks.orders.OrderServiceTest
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.484 s -- in
com.agentworks.orders.OrderServiceTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 25.090 s
[INFO] Finished at: 2026-10-24T01:59:10+05:30
[INFO] ------------------------------------------------------------------------
● The test run passed: ./mvnw test ended with BUILD SUCCESS and all 8 tests green.
- OrderControllerTest: 5 tests, 0 failures
- OrderServiceTest: 3 tests, 0 failures
The output has a few warnings, none of them failures:
- Mockito self-attach: Mockito attaches itself as a Java agent dynamically. A future JDK will block this, so
you'll eventually need to add Mockito as an explicit -javaagent in the Surefire config.
- spring.jpa.open-in-view: It's on by default. Set it explicitly in application.properties to silence the
warning. false is usually the better choice for an API.
I can make either of those changes if you want.
✻ Brewed for 37s · done 1:59 AMEight tests, no failures. Claude Code also pointed at two warnings in the output. Neither is a failure, and we left both alone.
What went wrong
Our runs were not clean. Two things went sideways, and both are useful.
It guessed the build tool. In one non-interactive run (claude -p), we gave a short prompt: the test name, and "Make it pass." It fixed the code. Then it tried to run the tests with plain mvn, and with a fallback to ./gradlew. This project has a Maven wrapper and no Gradle. In a -p run, a call that needs approval is denied unless something approves it. We had allowed only ./mvnw commands, so both were denied:
Bash: (mvn -q test -Dtest=OrderServiceTest 2>&1 || ./gradlew test --tests '*OrderServiceTest' 2>&1) | tail -30
result: This command uses shell operators that require approval for safety
Bash: mvn -q test -Dtest=OrderServiceTest
result: This command requires approval
...
I fixed `OrderService.create`, but I couldn't run the tests, so the fix is unverified. Both attempts to run Maven were blocked because they needed approval.Claude Code did not hide this. Its final message began: "I fixed OrderService.create, but I couldn't run the tests, so the fix is unverified." That is the right behavior.
The fix for us is to say how to run the tests, as we did in Task 1. Part 4 will put that in a file called CLAUDE.md, so you say it once.
It tried to script Git. When we finished, we asked for two commits: the discount fix first, then the endpoint. That sounds simple. But both changes sit in OrderService.java, because we waited to commit. Claude Code tried to split the file with git add -p and pre-typed answers:
The commit request
❯ Commit these changes. Two commits: the discount fix first, then the
new endpoint. Keep the messages short.
Running git status --short && git add src/main/java/com/a…
⎿ $ git status --short && git add
src/main/java/com/agentworks/orders/OrderService.java -p <<<
$'n\ny\n' >/dev/null 2>&1; git diff --stat
Bash command
Tip: auto mode handles these prompts for you — choose "switch to
auto mode" below
Run shell command
Text with escape codes in this command can't be checked before it
runs
Do you want to proceed?
❯ 1. Yes
2. Yes, and switch to auto mode · auto mode handles these prompts
for you
3. No
Esc to cancel · Tab to amendRead the command. It feeds n and y into git add -p and hides the output. The prompt also said it could not check the command before it ran.
We picked 3. No.
The screen answered Interrupted · What should Claude do instead?. Then we steered it:
Skip the split. Draft one commit message for all of these changes: a subject line of 50 characters or fewer, then a short body. Show it to me and do not commit.
The lesson is small. Read each command before you approve it.
When Claude Code does something clever, ask for something simpler. And commit after each task, so you never need this trick.
A note on guidance we did not see in our runs. Two other things go wrong often with coding agents. A test can be too weak, so it passes whatever the code does.
And a change can reach a file you did not mention. This is general advice, not a report from our runs. The cure for both is the same: read /diff.
Stay in control: the three things to learn first
1. Stop with Esc. Press Esc and Claude Code stops the current response or tool call. It keeps the work done so far, and you can type a correction.
2. Undo with rewind. Press Esc twice on an empty prompt, or type /rewind. The docs list /checkpoint and /undo as other names. Claude Code saves a checkpoint before each prompt that starts a turn. This is the menu from our run, after the follow-up prompt:
Rewind
Restore the code and/or conversation to the point before…
↑ 3 more
Add GET /orders/{id}. It returns the order as JSON. If no order has that id, return 404 with a JSON…
5 files changed +51
The 404 test does not check the detail text. Make it check that the detail names the missing id, an…
OrderControllerTest.java +2 -1
❯ (current)
Enter to continue · Esc to cancelPick a prompt and you get these choices:
The rewind choices
Rewind
Confirm you want to restore to the point before you sent this message:
│ The 404 test does not check the detail text. Make it check that the detail names the missing id, and
│ run the tests again.
│ (2m ago)
The conversation will be forked.
The code will be restored +1 -2 in OrderControllerTest.java.
❯ 1. Restore code and conversation
2. Restore conversation
3. Restore code
4. Summarize from here
↓ 5. Summarize up to here
⚠ Rewinding does not affect files edited manually or via bash.The choices are Restore code and conversation, Restore conversation, Restore code, and two summarize options that free up space. We cancelled with Esc and did not restore anything. The last line is the key one: "Rewinding does not affect files edited manually or via bash." The docs add that checkpoints cover Claude's file edits, and are not a replacement for Git.
3. Review before you commit. Use /diff inside Claude Code, or git diff outside it. Do this every time.
Permission modes also exist. You saw Manual and accept edits. Part 5 covers all of them.
Commit it
Here is the loop from Figure 3, finished. Claude Code drafted a message for us. It is a good shape: a short subject line, then a body that says why.
The drafted message
❯ Skip the split. Draft one commit message for all of these changes:
a subject line of 50 characters or fewer, then a short body. Show
it to me and do not commit.
● Here is the draft. I haven't committed anything.
Fix discount order and add GET /orders/{id}
Apply the 10% discount to the pre-tax subtotal and charge tax on the
discounted amount. The threshold was checked against the total with
tax, so a 90.00 subtotal wrongly got a discount.
Add GET /orders/{id}. An unknown id returns a 404 problem body via
the
new OrderNotFoundException. Add controller tests for both cases.
...
The subject line is 43 characters. Tell me if you want any wordingWe cut one line from the end of that message when we show it here: a Co-Authored-By trailer that Claude Code adds. The how Claude Code works page says the attribution setting changes or removes the commit and pull request attribution lines. Decide what your team wants.
These are the Git commands, with the message re-wrapped:
git status
git add -A
git commit -m "Fix discount order and add GET /orders/{id}" \
-m "Apply the 10% discount to the pre-tax subtotal and charge tax on the discounted amount. The threshold was checked against the total with tax, so a 90.00 subtotal wrongly got a discount." \
-m "Add GET /orders/{id}.
An unknown id returns a 404 problem body via the new OrderNotFoundException. Add controller tests for both cases."
On Windows PowerShell, put the command on one line, or end each line with a backtick instead of a backslash.
This commit holds two changes. Next time, commit after Task 1 and again after Task 2. Small commits are easy to review, and easy to undo.
A note on usage and cost
Watch two things. First, /usage shows your session cost and, on a subscription, your plan limits. The docs list /cost and /stats as other names.
In our run /cost opened the same screen. Second, /context shows what fills the context window.
Long sessions use more. The docs say Claude Code sends your whole conversation with each request, so a long session carries more with every turn. Use /clear when you switch to unrelated work.
We did not record usage numbers in our run, so we give none. Check the costs page for current limits.
Cheat sheet
| Command, key or prompt | What it does |
|---|---|
claude --version | Prints the installed version. |
claude doctor | Read-only checkup of your install and settings. |
claude --permission-mode manual | Starts a session in Manual mode, where Claude Code asks before edits and commands. |
? | Shows the shortcut list. |
/help | Shows help and available commands. |
! at the start of a line | Runs a shell command and adds its output to the session. |
/diff | Shows the changes in your working tree, including Claude's edits. |
Esc | Stops the current response. |
Esc twice on an empty prompt, or /rewind | Opens the rewind menu. |
Shift+Tab | Cycles the permission mode. |
/usage (also /cost) | Shows session cost and plan usage. |
/context | Shows what fills the context window. |
/clear | Starts a new conversation with empty context. |
/exit, or Ctrl+D twice | Leaves Claude Code. |
| "Explain what this project does and how to run its tests." | A safe first prompt. It changes nothing. |
| "Run the tests with ./mvnw test. One test fails. Find the cause and fix the code, not the test." | A bug-fix prompt with the check and the rule. |
Add GET /orders/{id} ... Follow the style of the existing code, and run the tests. | A feature prompt with behavior, error case, tests, style and check. |
Try it yourself
Three short exercises on the same project. Start each from a clean Git state, and read the diff at the end.
- Add a
GET /orders?minTotal=filter. Hint: say the parameter is optional, and ask for tests with and without it. A good result adds one service or repository method, one controller parameter and two tests. It does not change the existing tests. - Ask Claude Code to explain the discount logic. Hint: ask for a step-by-step walk through
OrderService.createwith a 120.00 example, and say "do not change any files". A good result says the discount comes off the subtotal first, then tax applies. It also notes that 100.00 exactly gets the discount.git statusstays clean. - Ask it to list risks in the controller without changing anything. Hint: say "list risks, do not edit". A good result names specific lines and gives a reason for each. Then check each claim yourself. Some may be wrong.
What comes next
Part 2, "Prompts that work on a Java codebase", is not published yet. The full plan has 14 parts in four levels. Figure 4 shows where you are.
On X and Instagram, we post a weekly slide series called "AI for Developers" every Saturday, from Claude Code basics to pro use. This blog series is the full written version. You do not need the slides to follow the articles.
To follow along, subscribe to the RSS feed, or follow @agentworkshq on X or @agentworkshq on Instagram. See the series page for the current list.