When we ask Claude Code to fix a bug or implement a feature, it may read several files, change the code, and run tests. It processes the text from our request, the source code files, and the test results. It also produces text as it works. This text is counted in small pieces called tokens. The number of tokens it uses affects the cost of the task.
For example, Claude may need only one error message to understand a failing test. If it reads thousands of unrelated log lines as well, it has more text to process. We may pay for that extra work even when it does not help fix the bug.
To reduce costs, we give Claude a clear task, keep useful project instructions easy to find, and avoid sending information it does not need. We still run the tests and review the code. Saving money is useful only if the fix remains correct.
In this guide, we ask Claude Code to fix the same bug using different instructions and settings. We compare how much each attempt costs and check whether the fix passes the tests. These examples show which changes helped with this task and how we can check whether they help in our own projects.

1. Start With the Work Claude Does Not Need
Before changing models or settings, look at what Claude reads to complete a task. A bug in one class may need a few source code files and one failing test. It probably does not need the release checklist, every API example, or thousands of unrelated log messages.
The first step is to remove information the task does not need while keeping the instructions and tests that help Claude get it right. A shorter request alone does not guarantee a cheaper result. If we leave out important details, Claude may spend more time searching or make changes we did not want.
1.1. What a Lower Cost Means
Claude Code uses tokens when it sends information to the model and receives an answer. During a task, it may send several requests as Claude reads files, edits code, and checks the result. Information from the earlier steps can be sent again so Claude has what it needs to continue.
The service can reuse an unchanged part of an earlier request through prompt caching. Reusing stored information is a cache read. Storing new information for reuse is a cache write. Cache reads cost less, so the kind of tokens matters as well as the number. We look at the prices in Section 6.
If we pay for usage, reducing token cost can reduce the bill. If the work is covered by a fixed-price subscription, the dollar estimates in this article do not represent an extra charge or a reduction in the monthly fee. We use them to compare how much model usage each version requires.
For example, the original bug-fix attempt costs about $0.14. Roughly $0.098 of that comes from cache writes, compared with $0.023 for cache reads and $0.018 for output. This gives us a reason to begin with the large instruction file. It adds information at the start of the task, whether this bug needs it or not.
1.2. The Example We Compare
We use a small Java application to see how this works. OrderDesk handles orders for an online bookstore. Its OrderValidator class checks the product code, quantity, and price on each order line. The validateLine() method contains the following bug.
private void validateLine(OrderLine line) {
if (line.sku() == null || line.sku().isBlank()) {
throw new ValidationException("sku is required");
}
if (line.quantity() == 0) { // the bug, should be <= 0
throw new ValidationException("quantity must be positive for " + line.sku());
}
if (line.unitPrice() == null || line.unitPrice().compareTo(BigDecimal.ZERO) < 0) {
throw new ValidationException("unitPrice must not be negative for " + line.sku());
}
}
The quantity check rejects zero but accepts negative numbers. Changing == 0 to <= 0 fixes it. An existing test, OrderValidatorTest.rejectsNegativeQuantity, already catches the error.
The complete example project includes the source code, instructions, scripts, and recorded results.
This gives us a small task with a clear result. We can ask Claude to fix it with different instructions, compare the costs, and check whether the tests still pass.
The project uses Java 21 and Spring Boot 4.1.2. The recorded attempts use Claude Code 2.1.310 with Opus 5.5. We repeat each version three times, starting from the same broken code. After every attempt, we run all 11 tests and review the code changes. For this comparison, test files must stay unchanged.
We call the original instructions and settings the baseline. This is the starting point for the comparisons.
The tables use the median cost, which is the middle of the three costs when sorted from lowest to highest. They also show the range from the cheapest attempt to the most expensive. Three attempts can reveal a useful difference, but they cannot guarantee the same saving on another project.
Passing these tests and reviewing the change gives us evidence about this particular fix. It does not prove that the same instructions or model will maintain quality for a large feature. A feature needs checks for its own requirements, and adding new tests may be part of that work. Our no-test-change rule applies only to this comparison.
2. Keep CLAUDE.md Useful and Short
The CLAUDE.md file tells Claude how to work in a project. It is a good place for build commands, test commands, and coding rules that apply to most changes. Claude Code reads it when a session starts.
Our original CLAUDE.md file has 417 lines. Alongside the everyday instructions, it contains release procedures, examples for 16 REST endpoints, notes about database changes, and instructions for handling production incidents. Most of that does not help fix the quantity check.
We keep the build commands and main coding rules in CLAUDE.md. We move the longer explanations to separate files.
| Content | Where it went |
|---|---|
| Build and test commands, package layout, five coding rules | CLAUDE.md (29 lines) |
| REST API catalogue | docs/api.md, linked from CLAUDE.md |
| Full style guide, review checklist, glossary | docs/style.md, linked from CLAUDE.md |
| Release process, environments, incident runbook, migration notes | The orderdesk-release skill |
For example, writing docs/api.md as a plain path tells Claude where to find the API documentation. It can open the file when it needs the details. Writing @docs/api.md imports the document instead, so its contents load with CLAUDE.md. A plain path is the better choice when we want to avoid loading it for every task.
We put release instructions in a skill, which is a set of instructions for a particular job. Claude sees the skill’s short description and reads the full instructions when it uses that skill. This keeps the detailed release procedure available without adding it to every bug-fix conversation.
We can make the same review in our own project. For each part of CLAUDE.md, we ask whether most coding tasks need it. Build commands and rules about handling money may belong in the main file. A deployment checklist can live in a separate document if everyday changes do not need it.
After moving the text, we update the file paths and check that Claude can find the guidance for a task that needs it. Moving important instructions out of sight without telling Claude where to find them would create a different problem.
The shorter CLAUDE.md has 29 lines.
# OrderDesk
Order service for the online bookstore: REST orders, validation, stock reservation, pricing with
coupons and tax, confirmations. Java 21, Spring Boot 4.1.2.
## Build and test
- Run all tests: `mvn test`
- Run the app: `mvn spring-boot:run` (port 8080)
## Where things are
- `com.howtodoinjava.orderdesk.order`: orders, validation, REST controller, in-memory repository
- `com.howtodoinjava.orderdesk.pricing`: subtotal, coupons and tax
- `inventory`, `notification`, `reporting`, `common`
## Rules
- Money is BigDecimal with scale 2 and RoundingMode.HALF_UP; compare with compareTo.
- Bad client input throws ValidationException; ApiExceptionHandler maps it to 400.
- Constructor injection, final fields, records for data carriers.
- Don't change test expectations to make a test pass; fix the code.
- Never log customer personal data.
## More guidance (read only when the task needs it)
- REST API catalogue: docs/api.md
- Coding style details: docs/style.md
- Release, environments and incident runbook: the orderdesk-release skill
We keep the rule about not changing test expectations. Removing that rule would make the file smaller, but it could also make the result less trustworthy. The aim is to remove instructions the task rarely needs, rather than remove useful guidance.
For this first comparison, we keep the bug-fix request and model the same. We change the project guidance from the original file to the shorter file and separate reference documents.
| Setup | Cost (median) | Range | Checks passed |
|---|---|---|---|
| 417-line CLAUDE.md | $0.1402 | $0.1315 to $0.1536 | 3 of 3 pass |
| 29-line CLAUDE.md | $0.0971 | $0.0884 to $0.0984 | 3 of 3 pass |
The median cost falls from $0.1402 to $0.0971, about 31%. Claude follows much the same process in both versions. It reads the failing test and validator, changes the comparison, and runs the tests again.
We can inspect our own starting instructions with /context. We type this command inside Claude Code before entering the task. The Memory files row includes instructions loaded from files such as CLAUDE.md. In our example, that row falls from about 5,400 tokens to 423 after the changes.
This report shows what is loaded at that moment. It is not the total usage for the task. After editing CLAUDE.md, we start a new session and inspect the report again so we compare the revised starting instructions.
The shorter instructions reduce the amount of new information stored for reuse by about 5,000 tokens. That accounts for most of the difference in cost. We explain how this storage works in Section 6.
Keep the instructions Claude needs for everyday work in CLAUDE.md, and provide paths to longer documents. The official costs documentation suggests keeping the file under 200 lines. Useful content matters more than reaching a particular line count.
3. Tell Claude What a Successful Change Looks Like
“Fix the validation” sounds straightforward, but it leaves Claude to decide what is wrong and how much code to change. It may add checks that are sensible but unrelated to the bug we wanted fixed.
A more useful request describes the problem, the expected result, and the checks to run. If something must stay unchanged, we say that too.
We compare these three requests using the short CLAUDE.md, a list of the main classes, and a command for running the validator tests.
- “Some tests are failing in this project. Please fix them.”
- “Orders are accepting bad data. Please fix the validation.”
- “OrderValidator accepts order lines with a negative quantity, so OrderValidatorTest.rejectsNegativeQuantity fails. Make OrderValidator reject any quantity of zero or less with a ValidationException. Don’t change the tests or any public method signature. Verify with mvn -q test -Dtest=OrderValidatorTest, then run mvn -q test once before you finish.”
| Prompt | Cost (median) | Range | Checks passed | Files changed |
|---|---|---|---|---|
| 1. “Some tests are failing” | $0.1004 | $0.0882 to $0.1397 | 3 of 3 pass | OrderValidator |
| 2. “Orders are accepting bad data” | $0.1787 | $0.1522 to $0.2019 | 2 of 3 pass | OrderValidator in 3 runs, OrderValidatorTest in 1 |
| 3. Behavior, constraints and verification | $0.1402 | $0.1374 to $0.1502 | 3 of 3 pass | OrderValidator |
The second request costs 78% more than the first. Claude does more work because “bad data” can mean several things. In two attempts, it adds a check for a null order line. In one of those attempts, it also adds a test. All tests pass, but that attempt fails our comparison rule because a test file has changed.
The third request keeps the change to one line in every attempt. It costs 22% less than the vague second request, although it costs more than the first. It asks Claude to run both the validator tests and the full test suite, so Claude does more checking.
Why does the short first request work well here? The failing test already names the class, shows the problem, and states the expected result. Claude can get the missing detail from that test. A short request would be less useful if the problem were not already captured in a test.
Give Claude enough detail to make the intended change, and keep the checks needed to trust it. A longer request can be worth the extra tokens if it prevents an unwanted change or another round of corrections.
The same approach works for a feature request. For example, we could ask Claude to add an order-status endpoint, name the required status values, explain how to handle a missing order, and ask for tests covering those cases. That gives Claude a clearer job than “add order tracking.” This is an illustrative request, not another measured result from our example.
4. Avoid Feeding Claude Large, Unrelated Logs
A test can print thousands of lines even when only a few explain the failure. If Claude reads the entire output, those lines become part of the conversation and may be included in later requests.
Maven is the build tool used by our Java project. Our example has DEBUG logging enabled, which prints detailed diagnostic messages. These Maven commands produce very different amounts of output.
| Command | Output |
|---|---|
| mvn test | 144,311 characters |
| mvn -q test | 39,089 characters |
| mvn -q test -Dtest=OrderValidatorTest | 1,887 characters |
We can ask Claude to start with mvn -q test -Dtest=OrderValidatorTest, inspect any failure, and run mvn -q test after making the fix.
The -q option reduces routine Maven messages. Adding -Dtest=OrderValidatorTest runs only the named test class. During the fix, that smaller test run can help Claude check the relevant code without reading output from unrelated tests. We still run the full suite before accepting the result.
After shortening the instructions, we add the class list and targeted test command. For the hook version, we keep those additions and ask Claude to run the test commands without its own pipes. We then add a hook, which is a script Claude Code runs at a particular event. The hook script, registered in .claude/settings.json, changes matching Maven commands so they return selected test messages instead of the whole log. In the recorded failing run, it returns 2,184 characters, including the error and stack trace.
However, the hook does not produce a clear cost saving in this small example. Claude already filters the output itself in most attempts. The median cost is $0.0930 with the hook, $0.1004 with the class list and targeted test command, and $0.0971 with the short instructions alone. The ranges overlap. These three attempts per version do not establish a reliable saving from the hook.
There is also a practical limit to filtering. The lines we remove may contain the explanation for another failure. A shell pipeline can hide Maven’s failure status if it returns the filter’s status instead. We therefore check the full test result separately. Shorter output is useful only when it still lets us diagnose the problem.
Start with quieter logging and a relevant test command. Add an automatic filter when the logs are a repeated problem, and make sure the full output and the original test status remain available.
5. Use a Cheaper Model or Helper Where It Makes Sense
A cheaper model can reduce costs, but its token price does not tell us the cost of the finished task. If it needs several corrections, the saving may disappear. We need to compare results using the same task and tests.
All the main conversations in this example use Opus 5.5. At the listed rates, Sonnet 5.5 costs half as much for the token types compared here. We have not run this task with Sonnet, so we cannot claim it would finish the job for half the cost.
We do try a smaller model for one limited job. A helper called code-locator finds the classes and tests related to the bug. It uses Haiku 5.5 and cannot edit files. This kind of helper is called a subagent. It works in a separate conversation and returns its findings to the main one.
The helper is defined in .claude/agents/code-locator.md.
---
name: code-locator
description: Finds the classes, methods and tests related to a bug or feature and reports file paths with line numbers. Read-only.
tools: Read, Grep, Glob
model: haiku
---
Find the code related to the request. Report each relevant file path, the method names, and the
line numbers that matter, with one sentence on why each one is relevant. Do not edit files.
After saving that definition, we ask Claude to use code-locator to find the relevant validation code and tests before making the fix. The main model then carries out the detailed request from Section 3. The comparison keeps that request, the main model, and the project instructions unchanged; the helper is the addition.
| Setup | Cost (median) | Range | Opus cost | Haiku cost | Checks passed |
|---|---|---|---|---|---|
| Prompt 3, no subagent | $0.1402 | $0.1374 to $0.1502 | $0.1402 | none | 3 of 3 pass |
| Prompt 3 with the Haiku subagent | $0.1241 | $0.1212 to $0.1460 | $0.1220 | $0.0016 | 3 of 3 pass |
Each cost column shows its own median. The Opus and Haiku medians can come from different attempts, so adding them may not equal the median total.
The helper reads four to six files and costs between $0.0014 and $0.0021 per attempt. The main model still reads OrderValidator before changing it, but it does not repeat the search or read the test class again.
Including both models, the median cost is 11% lower. The ranges overlap, though. Some attempts with the helper cost more than some attempts without it, so we need more attempts before treating this as a reliable saving.
A helper is most useful when it can read a lot and return a short, useful answer. Finding relevant files or summarizing a long error log are examples. If the task already names the file and method, asking another model to find them may add work.
Always include the helper’s cost in the total. Moving work out of the main conversation does not make that work free.
6. Keep Related Work in the Same Conversation
A session is one conversation in Claude Code. Suppose Claude has just explained the order-validation code. We then ask it to fix a bug in that code. Continuing the conversation lets it use what it has already read. Starting again may mean reading the same files another time.
The same applies to the conversation’s cached information. Prompt caching lets the service reuse unchanged information from earlier requests at a lower price. Reading that stored information is called a cache read. Storing new information is called a cache write.

The prices below show why this matters. They are Anthropic’s listed Opus 5.5 prices in US dollars per million tokens, checked on October 25, 2026.
| Token kind | What it is | Price per million tokens |
|---|---|---|
| Input | New content that isn’t cached | $4.00 |
| Cache write | New content stored in the cache, with a 5-minute or a 1-hour lifetime | $5.00 (5 minutes), $8.00 (1 hour) |
| Cache read | Content served from the cache | $0.20 |
| Output | Text, tool calls and thinking that the model produces | $20.00 |
Reading a million cached tokens costs $0.20. Storing a million tokens for one hour costs $8.00. A longer conversation that reuses stored information can therefore cost less than a shorter one that needs more new information stored.
The cache has a time limit. We can check the Prompt cache (main) line in /usage to see whether the main conversation is reusing stored information. A warm cache means stored information is available; a cache miss means the request could not reuse the information it needed. The main conversation normally gets one hour within the included usage of a Claude subscription. API keys, usage credits, and cloud providers normally use five minutes. Helper requests may use different limits. The prompt caching documentation describes these settings.
6.1. Continue, Start Fresh, or Use /compact
We have three choices when moving to the next task.
- We can continue the conversation and keep what Claude has already read.
- We can use /clear to remove the conversation history. The project’s starting instructions still load.
- We can use /compact to replace the history with a summary. For example, /compact Focus on the order validation asks the summary to preserve that part of the work.
To compare these choices, we first ask Claude to explain OrderDesk and identify API endpoints that are missing from the code. It reads most of the classes and tests. We then ask it to fix the quantity bug using the detailed request from Section 3.
| How the task started | Task cost (median) | Range | Checks passed |
|---|---|---|---|
| Fresh session | $0.1402 | $0.1374 to $0.1502 | 3 of 3 pass |
| Continued the long session within the cache lifetime | $0.0799 | $0.0761 to $0.1132 | 3 of 3 pass |
| /compact, then the task | $0.3222 | $0.3149 to $0.3430 | 3 of 3 pass |
| Continued the long session after the cache expired | $0.1919 | $0.1854 to $0.2027 | 3 of 3 pass |
Continuing while the cache is still available gives the lowest median task cost, $0.0799. Claude has already read the validator and its test. It can move directly to the change and test runs.
Using /compact first costs $0.3222, including both the summary and the following bug fix. Writing the summary costs $0.1014. The summary also changes the conversation text, so more information must be stored again for the next task.
This does not make /compact a bad choice. It is useful when a conversation has become too long and we need to keep earlier decisions. It simply has a cost of its own. We do not need to run it before every related task. This comparison covers only the next bug fix. It does not establish which choice would cost least across many later tasks.
6.2. What Happens After the Cache Expires
A saved conversation and its cached copy are different things. We can reopen the conversation after the cache expires, but the service must process its history again instead of reusing the expired copy.
For this comparison, we use a five-minute cache and wait six minutes before starting the bug fix. The median task cost becomes $0.1919, compared with $0.0799 while the cache is available. The five-minute cache also has a cheaper write price than the one-hour cache, so these figures compare two particular conditions rather than measuring expiry alone.
The earlier work also has a cost. Preparing the conversation costs a median of $0.4054, which is not included in the task costs in the table. Creating a long history just to make this small bug fix cheaper would cost more overall.
For related work, continuing the existing conversation is worth considering. For an unrelated task, /clear can remove information it does not need. We choose based on what helps the next task, rather than assuming every new conversation or every summary saves money.
7. Check Whether a Change Actually Saves Money
Claude may take different steps even when we give it the same task. One cheap attempt is not enough to show that a change helped. In our measurements, repeated attempts with the same instructions differ by as much as $0.05.
We compare the median and the full range, and we check the result after every attempt. In the tables, Checks passed counts attempts that pass both the tests and our no-test-change rule. It is not a count of individual tests. The token columns count tokens across the task, while Turns counts the model’s turns as it works. The following table brings together all ten versions. We have not changed and measured only one setting throughout the whole table. Some rows combine shorter instructions with a different request or session history. Each percentage compares that row with the original $0.1402 baseline. A minus sign means lower cost, and a plus sign means higher cost. The percentages cannot be added together.
| Setup | Cost (median) | Change from baseline | Cache write | Cache read | Output | Turns |
|---|---|---|---|---|---|---|
| Baseline, 417-line CLAUDE.md, prompt 1 | $0.1402 | 12,309 | 114,599 | 921 | 6 | |
| 29-line CLAUDE.md | $0.0971 | -31% | 7,309 | 96,716 | 963 | 6 |
| Short instructions with class list and targeted test command | $0.1004 | -28% | 7,837 | 97,394 | 910 | 6 |
| Class-list version with output hook | $0.0930 | -34% | 7,795 | 76,278 | 770 | 6 |
| Prompt 2 (vague goal) | $0.1787 | +27% | 14,233 | 131,508 | 1,924 | 6 |
| Prompt 3 (behavior, constraints and verification) | $0.1402 | 0% | 11,588 | 121,903 | 1,151 | 8 |
| Prompt 3 with a Haiku subagent | $0.1241 | -11% | 8,848 | 121,602 | 1,318 | 7 |
| Prompt 3 in a warm, related session | $0.0799 | -43% | 4,365 | 129,545 | 1,072 | 4 |
| Prompt 3 after /compact | $0.3222 | +130% | 22,546 | 113,869 | 1,058 | 5 |
| Prompt 3 in the same session after the cache expired | $0.1919 | +37% | 30,729 | 95,591 | 973 | 4 |
All attempts pass the tests. One attempt with the vague second request changes a test file, so it fails our additional rule that tests must stay unchanged.
The /compact total includes creating the summary, but its token and turn columns show only the task after the summary. The helper total includes Haiku’s cost, but its token columns show only the main conversation. This is why the token columns alone do not reproduce every total.

7.1. Read the Usage Report
In Claude Code, /usage shows token usage and an estimated cost. In the version used here, /cost opens the same report. The Prompt cache (main) line helps us see whether the conversation is reusing cached information.
The dollar amount is an estimate, not necessarily an extra charge. If the work is covered by a Pro or Max subscription, reducing this estimate does not lower the fixed monthly subscription fee. For usage-based billing, the token counts and applicable rates determine the charge.
We save reports automatically by running the request from the command line.
claude -p "Some tests are failing in this project. Please fix them." \
--output-format json --model opus \
--permission-mode acceptEdits --allowedTools "Bash Read Edit Write Glob Grep Agent"
The -p option supplies the request, and –output-format json returns a report that a script can save and read. The other options choose Opus and allow the listed tools and file edits in our separate example project.
Here is the report from the baseline attempt with the median cost.
{
"num_turns": 6,
"total_cost_usd": 0.1402,
"usage": {
"input_tokens": 10,
"cache_creation_input_tokens": 12309,
"cache_read_input_tokens": 116362,
"output_tokens": 921
}
}
The total_cost_usd field gives the estimated cost. The usage section separates new input, cache writes, cache reads, and output. The num_turns field reports how many model turns the task took. These are Claude’s turns while working, rather than just the messages we type.
In this attempt, storing 12,309 tokens at the one-hour write rate costs about $0.098. Reading 116,362 cached tokens costs about $0.023. Producing 921 output tokens costs about $0.018. Most of the cost comes from storing new information, even though the cache-read count is much larger.
7.2. Try One Change at a Time
We can use the same approach on our own project.
- We choose a task with a result we can check, such as a failing test. We save the starting code so every attempt begins in the same state.
- We run it several times with the current instructions and record the costs. We also note whether the cache is available.
- We change one thing, such as the contents of CLAUDE.md, and repeat the task with the same model and other settings.
- We run the tests and review the code after each attempt. A cheaper attempt that produces the wrong result does not count as an improvement.
- We compare the costs across attempts. Small differences need more evidence before we rely on them.
The example includes runner/run.sh to repeat the task and run checks. For each attempt, it saves the JSON usage report, the test log, and the code diff in the results folder. Its runner/analyze.py script calculates the medians. For continued conversations, the runner calculates the new task’s cost separately from the earlier work. The reported total for the task attempts and history preparation is $6.70 at list prices.
7.3. A Routine We Can Use on the Next Task
We begin by checking /usage so we have a starting point. We review CLAUDE.md for long material that most tasks do not need. Then we give Claude the problem, any relevant file or error message we already know, and the conditions a correct result must meet.
While Claude works, we use the relevant tests to get quick feedback. Before accepting the change, we run the broader checks the change requires and read the diff. We keep the conversation for related follow-up work. If the next task is unrelated, we consider starting a fresh one.
Only after these basics do we try helpers or automatic output filters. We measure their combined cost and check whether they actually reduce repeated work. That gives us an order to follow without changing several things at once.
8. Conclusion
Start with the instructions and information Claude reads for everyday tasks. Keep the build commands and important rules in CLAUDE.md. Move long reference material to separate files, describe the intended change clearly, and keep unrelated logs out of the conversation.
In this example, shortening CLAUDE.md produces the clearest saving, about 31% of the median estimated task cost. The detailed request also keeps the change focused. Continuing a related conversation while its cache is available costs less than creating a summary first.
Helpers and output filters can be useful, but the small differences here need more evidence. We keep checking the tests and code changes alongside the cost. That is how we find savings we can use without making the result less reliable.
9. Further Reading
Happy Learning!