# Claude Code struggles with our legacy .NET monolith. How do I give it the context it is missing?


URL: https://getunblocked.com/answers/claude-code-legacy-dotnet-monolith-context/
Published: 2026-11-06T14:00:00Z
Updated: 2026-11-01T13:41:59Z
Author: Brandon Waselnuk
Categories: Context Engine, Engineering Insights

**Short answer:** Claude Code reads C# well. What it lacks is what the code never recorded: which patterns are dead, why odd code exists, whether you are staying on .NET Framework, and how to prove a change is safe. Give it four things: short CLAUDE.md files per subsystem, the C# language server, a queryable source for PR, ticket and chat history, and characterization tests to run.

---
Claude Code struggles with a legacy .NET monolith because the hard part of that code is not in the code. It can read a 15-year-old C# solution fine. It cannot see which of three data-access patterns is the current one, whether you plan to stay on .NET Framework, why a strange retry loop exists, or how to prove a change is safe. **Institutional context** is that missing layer: the reasons behind the code that live in old pull requests, tickets, chat threads and people's heads. The fix is to give Claude Code four things. Write short instruction files for each subsystem. Install the C# language server so it navigates by symbol. Connect a source it can query for history. Then pin current behavior with tests it can run.

## What Claude Code can and cannot see in a legacy .NET monolith

Anthropic's guidance draws the line clearly. Claude "starts every task by reading your code," and it is good at finding layout, conventions and test frameworks. "What it can't find is the information that was never in the repo," such as "a decision your team made in a meeting" or "a deploy process that lives in one person's head" ([Claude Code best practices](https://code.claude.com/docs/en/best-practices)).

A legacy monolith is mostly that second kind of knowledge. Take the runtime. The project file says which framework you target today, but not whether you are staying there or porting next year. A .NET Framework 4.x project and a modern .NET project look alike in C#. But Microsoft lists technologies that are not available on .NET 6 and later, including app domains, remoting, code access security and Windows Workflow Foundation ([Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/core/porting/net-framework-tech-unavailable)). If nobody tells the agent the plan, it can suggest fixes that do not fit your code or your roadmap.

Dead patterns work the same way. Most monoliths have an old way and a new way of doing one job, both everywhere, and the code cannot tell the agent which to copy.

## Write down only what the code hides, per subsystem

The first instinct is to generate a big architecture document for CLAUDE.md. Resist it. A February 2026 study tested repository context files across several agents and models. It found that providing context files "does not generally improve task success rates" while raising inference cost "by over 20% on average" ([arXiv 2602.11988](https://arxiv.org/abs/2602.11988)). That held for both LLM-generated files and files developers wrote.

Anthropic's docs agree, more gently: target "under 200 lines per CLAUDE.md file," because "longer files consume more context and reduce adherence" ([Claude Code memory docs](https://code.claude.com/docs/en/memory)). Keep only what the agent cannot work out alone:

- The target framework and the build and test commands, down to running one test project
- Misleading code: the old pattern that new code must not copy, or the folder that looks unused but ships
- Decisions that live outside the repo, such as which logging helper won

For a monolith, split this up. Claude Code's large-codebase guide recommends a root file for rules that apply everywhere plus one file per subsystem, "such as `src/db/` or `src/api/`," which loads only when Claude works there ([Claude Code large codebases](https://code.claude.com/docs/en/large-codebases)). The same guide shows `Read` deny rules to keep generated and vendored code out of reach. If your agents keep skipping these files, our answer on [making CLAUDE.md rules stick](https://getunblocked.com/answers/agents-ignore-claude-md-rules-how-to-make-context-stick/) covers why.

## Let it navigate by symbol, not by text search

In a solution with hundreds of projects, finding who calls a method by grep is slow and noisy. Overloads, partial classes and interfaces all hide the real call path. **A code intelligence plugin** is a Claude Code plugin that connects the agent to a language server, the same engine your IDE uses for go-to-definition. The official C# plugin, `csharp-lsp`, connects to the `csharp-ls` language server ([Claude Code code intelligence](https://code.claude.com/docs/en/plugins/code-intelligence)).

With it running, Claude "finds definitions and references by symbol instead of by text search." It also sees type errors and missing imports from its own edits before you run a build. When a full build takes minutes, that matters.

## Connect the history the code does not carry

Instruction files and a language server tell the agent what the code is. They do not tell it why. Why does the billing module write to two tables? Which ticket made that `Thread.Sleep` necessary? Who decided not to touch the WCF layer? Those answers sit in old pull requests, issue trackers, wikis and chat.

Anthropic's large-codebase guide agrees. If your organization already runs a search index over the repository, "expose it as an MCP tool so Claude queries it instead of reading files directly" (Claude Code large codebases, linked above). You can wire up one MCP server per source, or use a context engine that reasons across all of them.

Unblocked is the second kind. It connects code, PRs, issues, docs, Slack or Teams and incidents, and its `context_research` tool returns "a synthesized answer with citations" to Claude Code over MCP ([Unblocked MCP docs](https://docs.getunblocked.com/unblocked-mcp/mcp-overview)). With Data Shield on for a source, answers only contain what the asking engineer is authorized to see there ([Unblocked Data Shield docs](https://docs.getunblocked.com/team-settings/data-shield)). For how Unblocked settles a wiki that disagrees with the code, see [inside the Unblocked context engine](https://getunblocked.com/blog/inside-the-unblocked-context-engine/). Our answer on [asking why code was written this way](https://getunblocked.com/answers/ask-why-code-was-written-this-way-from-jira-confluence-and-slack-history/) covers the history side.

Expo has more than a decade of company history behind its code, and the reasons for much of it predate today's team. Brent Vatne, VP of Engineering at Expo, said in the [Expo customer story](https://getunblocked.com/customers/expo/): "A lot of these questions can't be answered by people who've been here a year or two when the organization has been around for ten. Why is this done this way? Nobody knows unless they were around seven years ago. New hires tell us that compared to onboarding at other roles, it's just so much easier with Unblocked."

## Give it a check before it changes anything

Context tells the agent what to do. Tests tell it whether it did it. Most legacy monoliths have thin coverage. **A characterization test** is a test that records what the code does today, odd behavior included, so any change in that behavior fails loudly. Have Claude write those first, before it edits anything. Anthropic's guidance is blunt about the alternative: without a check to run, "that makes you the test suite" ([Claude Code best practices](https://code.claude.com/docs/en/best-practices)). Our guide to [refactoring legacy code with AI agents](https://getunblocked.com/blog/refactoring-legacy-code/) walks through that workflow.

If the real goal is moving off .NET Framework, Microsoft now recommends its GitHub Copilot app modernization agent and calls .NET Upgrade Assistant deprecated ([Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/core/porting/)). A tool like that handles the mechanics of a port, and our [legacy code modernization guide](https://getunblocked.com/blog/legacy-code-modernization/) covers the wider plan. The reasons behind the code still have to come from the steps above.

## Read more

- [How to Refactor Legacy Code with AI Agents (2026)](https://getunblocked.com/blog/refactoring-legacy-code/)
- [AI-Powered Legacy Code Modernization: The Complete Guide (2026)](https://getunblocked.com/blog/legacy-code-modernization/)

## Related answers

- [Is an LLM-maintained wiki in git a better fix than a context tool for engineering knowledge?](https://getunblocked.com/answers/llm-maintained-wiki-vs-context-tool/)
- [How do we drive adoption of an AI coding tool from a third of engineering to everyone?](https://getunblocked.com/answers/drive-ai-coding-tool-adoption-across-engineering/)
- [How do I make sure Claude actually calls the context MCP without every engineer editing their CLAUDE.md?](https://getunblocked.com/answers/make-claude-call-context-mcp-without-editing-claude-md/)
- [Atlassian Rovo MCP versus a dedicated context tool for Confluence, Jira and code?](https://getunblocked.com/answers/atlassian-rovo-mcp-vs-context-tool/)
