artificial-intelligence

I Hit My Claude Pro Limit in 90 Minutes Refactoring an .NET Core API. Then I Rebuilt My Workflow.

It was a Tuesday afternoon. I had a two-hour block carved out for what should have been a clean refactor: split a bloated OrderService into command and query handlers, update the EF Core migrations, run the integration tests. I opened Claude Code, pointed it at the solution, started working.

Ninety minutes in, the message I had been pretending wouldn’t come:

Claude usage limit reached. Your limit will reset at 6:30 PM.

I had not shipped the refactor. I had not finished the first handler. And the part that nagged at me for the rest of the week was that I genuinely could not tell you where those tokens went.

So I went looking.

This is the first piece in a four-part series on getting more out of AI coding subscriptions when you’re doing real .NET work. Part 1 is Claude Code on the Pro plan. Part 2 will be Antigravity. Part 3 covers Codex, Copilot CLI, and Cursor. Part 4 is the multi-tool workflow — how I actually rotate between them when one taps out mid-task.

If you’re a senior .NET developer paying for Pro out of pocket and feeling like the limits hit faster than they should, this one is for you.

Why .NET burns Claude Code tokens faster than people warn you

Here’s the part nobody explains until you find out the hard way. On every turn, Claude Code resends the entire conversation back to the model. Your prompts, its responses, every tool result, every file it read, every command output. That’s how transformers work. They don’t “remember” earlier in the session, they reprocess everything every time.

So the cost of message 40 is not the cost of message 40. It’s the running total of everything in the session.

For most languages that’s bad enough. For .NET it’s worse. The default tooling generates more noise per useful line of code than almost any other ecosystem:

  • A typical EF Core migration snapshot is 1,500 to 3,000 lines of auto-generated code, almost none of which Claude needs
  • Designer files (*.Designer.cs) in WinForms or Blazor can run into hundreds of lines of generated plumbing
  • .csproj files are XML, which is token-heavy and rarely changes
  • dotnet test output, unfiltered, includes the discovery log, every passing assertion, NuGet restore lines, and the framework banner before it gets to the failure you actually wanted
  • Solution-wide grep across a multi-project repo pulls in hundreds of files Claude doesn’t need

The first time I ran /context mid-session, it showed 78 percent full. About a third of that was a single migration snapshot Claude had read while answering an unrelated question forty messages earlier. It was still sitting there, riding along on every subsequent turn.

As of May 2026, Pro gives you roughly 44,000 tokens per 5-hour rolling window, with weekly caps stacked on top since August 2025. Sonnet 4.6 is the default model on Pro. Opus 4.7, which shipped April 16, 2026, has a new tokenizer that can produce up to 35 percent more tokens for the same input text. So switching to Opus eats your budget faster than the headline pricing suggests.

If you aren’t actively managing what enters context, .NET will eat your Pro allocation alive.

Here’s the system I built.

1. Front-load the setup

The highest-leverage thirty minutes you’ll ever spend on Claude Code is the setup you do before the first prompt.

Write a tight CLAUDE.md

Run /init in your project root and Claude generates a CLAUDE.md. It reads this at the start of every session and it persists for the whole session, which also means every token in it gets paid for on every turn. A 5,000-token CLAUDE.md costs 5,000 tokens whether you send two messages or two hundred.

So make it a lookup table, not a brain dump. Here’s the structure I use for .NET projects:

# Project: OrderingApi (.NET 10, ASP.NET Core, EF Core 10, SQL Server)

## Layout
- src/Domain - entities, value objects, no dependencies
- src/Application - handlers, validators, no infrastructure
- src/Infrastructure - EF Core, external clients
- src/Api - controllers, DI registration
## Commands
- Build: dotnet build -c Release
- Test single project: dotnet test tests/Application.Tests --filter "FullyQualifiedName~<Name>"
- Migration: dotnet ef migrations add <Name> -p src/Infrastructure -s src/Api
- Run: dotnet run --project src/Api
## Conventions
- MediatR for handlers, FluentValidation for validators
- xUnit + FluentAssertions for tests
- Records for DTOs, classes for entities
- No DataAnnotations on domain entities
## Do not touch
- src/Infrastructure/Migrations/*.Designer.cs
- Any *.generated.cs
## When unsure
- Ask before applying migrations or modifying DI registration

That’s roughly 200 tokens. It saves several thousand tokens of re-explanation across the session.

Set a .claudeignore for .NET

The most underused file in the .NET Claude Code workflow. Drop one at the repo root:

bin/
obj/
.vs/
TestResults/
coverage/
packages/
node_modules/

# auto-generated, never useful in context
**/*.Designer.cs
**/Migrations/*ModelSnapshot.cs
**/*.generated.cs
**/*.received.txt
# verbose, low-signal
**/*.lock.json

If Claude needs a migration snapshot for some reason you can still @-reference it explicitly. The default of "don't read this unless I ask" is the right one.

2. In-session discipline

/context after every major task

Make this muscle memory. It returns a structured breakdown of every item in your context window with token counts. Treat it like a memory profiler.

You’ll be shocked the first time. There’s always a file you forgot Claude opened, sitting there costing you on every turn.

/compact at natural breakpoints

/compact summarizes the conversation into a compressed representation that captures decisions made, code written, files touched, and current task state. The default trigger fires near 95 percent capacity, which is too late. By then your quality has already degraded.

Run it manually after each completed subtask. Before compacting, tell Claude what to preserve:

Before /compact: preserve the OrderService refactor decisions,
the three handlers we've stubbed out, and the failing test name.
Drop the exploration of MediatR pipeline behaviors —
we decided against it.

/clear between unrelated work

The most counterintuitive habit. If you finish the OrderService refactor and someone pings you about a Razor page bug, don’t keep going in the same session. Run /clear and start fresh. The savings are enormous because you stop paying for context you no longer need.

A Git commit makes this safe. Your work is checkpointed, you lose nothing by clearing.

Plan mode before anything risky

Shift+Tab toggles plan mode. Claude produces a structured plan of what it intends to do without doing any of it. You review, correct, approve.

For .NET, the threshold for “risky” is lower than people think. Always use plan mode for:

  • EF Core migrations (a hallucinated schema change applied to a real DB is the kind of thing that ruins a Friday)
  • Cross-project refactors in a multi-project solution
  • Anything touching DI registration in Program.cs
  • Environment config changes (appsettings.*.json)
  • Any change to the request pipeline

The cost of reviewing a plan is near zero. The cost of Claude reading six files and writing four before you realize it misunderstood is your entire window.

Checkpointing

Every action creates a checkpoint. Double-tap Escape or run /rewind to restore conversation, code, or both to any previous state. This changes how you experiment. You can tell Claude to try something aggressive, and if it doesn't work, rewind without paying for the cleanup.

3. The .NET-specific moves that actually move the needle

This is where the article earns its keep. Generic Claude Code tips don’t capture the .NET ecosystem.

Use the dotnet CLI instead of letting Claude read files

You don’t need Claude to parse a .csproj to add a NuGet package. Run the command yourself:

dotnet add src/Application/Application.csproj package MediatR --version 12.4.1

The tokens you save by not having Claude read the project XML, propose an edit, and write the change back add up fast. Same for dotnet list package, dotnet ef migrations list, dotnet new, and most of the CLI surface.

The rule: if there’s a dotnet command that does the thing, use it directly. Let Claude handle the code, not the project plumbing.

Scope test runs ruthlessly

dotnet test with no filter is one of the worst offenders in .NET. It dumps NuGet restore output, framework banner, every test discovery line, and every passing assertion before the failures you care about.

# instead of: dotnet test
dotnet test tests/Application.Tests \
  --filter "FullyQualifiedName~OrderServiceTests" \
  --logger "console;verbosity=minimal" \
  2>&1 | grep -E "Failed|Error" | head -50

Pipe through grep, cap the output, run the smallest test slice that exercises your change. Claude doesn't need the full suite log to fix a failing test. It needs the failure.

Subagents for codebase archaeology

The feature most .NET devs ignore and shouldn’t. When you need every caller of IOrderRepository.GetById across a 200-file solution, that's a subagent task. The subagent explores in an isolated context, returns a clean summary, and your main session never sees the noise.

Use a subagent to find every caller of IOrderRepository.GetById
in the solution. Return only the file path, the method name, and
one line of surrounding code. Do not include full file contents.

The “do not include full file contents” line is the difference between a 200-token answer and a 20,000-token one.

@file references over copy-paste

If you paste a file’s contents into chat, they live in the conversation history forever. If you use @OrderService.cs, Claude reads it once into the tool result for that turn. Still in context, but at least it's structured and you can manage it.

Even better: paste only the method, not the class. Never the whole file.

Don’t ask Claude to “look around”

The fastest way to burn a session. Start with “look at this repo and figure out how to…” and Claude will read six files trying to understand the layout, four of which turn out to be irrelevant, and the tokens are gone.

Replace exploration prompts with directed ones:

Slow: “Look at the OrderService and tell me how to split it into handlers.” Fast: “Read src/Application/Services/OrderService.cs (only that file). Propose how to split methods CreateOrder, CancelOrder, and GetOrderStatus into three MediatR handlers under src/Application/Handlers.”

The second prompt produces the same result for a fraction of the tokens.

4. Model selection and the weekly cap math

Default to Sonnet 4.6. It handles roughly 80 percent of the .NET work I do — handler refactors, test writing, EF Core queries, controller plumbing, debugging async code.

Switch to Opus 4.7 deliberately, not by default, for:

  • Cross-project architectural decisions
  • Gnarly LINQ-to-SQL translation issues where Claude has to reason about generated SQL
  • Async deadlock debugging where the cause is buried three layers deep
  • Anywhere wrong code costs more than slow code

Two things to know about Opus 4.7. First, the new tokenizer (April 2026) can produce up to 35 percent more tokens for the same input, so the same conversation eats your window faster. Second, Anthropic gives Opus less generous treatment under the weekly cap, so heavy Opus use exhausts your Pro allocation much sooner than Sonnet-only sessions.

Haiku is your friend for renames, formatting, lookups, “what does this regex do” questions. Most .NET devs forget Haiku exists and pay Sonnet prices for trivial work.

5. What I still do manually

Every Claude productivity article I’ve read pretends the AI does everything. It doesn’t.

I still do these myself because Claude is either slower or not worth the budget:

  • Renaming a single symbol — Visual Studio’s F2 is faster and free
  • Adding using statements — the IDE does it
  • Single-line typo fixes
  • Running tests in Test Explorer when I want the visual tree, not a CLI dump
  • Reading stack traces — I read them myself first, only feed Claude the relevant frames
  • git status, git diff, git log — I run them, paste the specific output if Claude needs it

The rule: if it takes me under 30 seconds and Claude would need to read three files to answer, I do it myself.

When the limit hits anyway

Some days, even with all this discipline, the limit hits at 3 PM and there’s still work to ship. Before the session ends, I dump a recovery context to a file:

Before this session ends: write a CONTEXT.md summarizing
the OrderService refactor — current state, decisions made,
next three steps, the failing test, and the file paths I'll need.
I'll feed this into the next session as the starting context.

Then /clear, and when the window resets the next session boots from that file instead of from scratch.

But sometimes even the reset is hours away and the work can’t wait. That’s when I switch tools. Antigravity is next in this series — what it does better than Claude Code, what it does worse, and the hacks for stretching its free tier the way we just stretched Pro.