Claude Code's Source Leaked. Here Are 7 Things I'd Change.



The Claude Code source code became publicly accessible recently. I did what any engineer would do: I read it. All of it.
The engineering is genuinely impressive. The compaction system, the hook architecture, the way it manages tool calling and streaming. This is not amateur work. But after spending a full day tracing through the codebase, I found an architectural blind spot that explains a lot of the frustration I have been experiencing as a heavy user.
The system optimizes for content delivery but not attention management.
Let me explain what that means, and then I will walk you through 7 concrete changes I would make to fix it. These are not theoretical suggestions. I am giving you the file paths, the line counts, and the complexity estimates.
The Attention Problem
Large language models have a well-documented attention pattern: they pay the most attention to content at the beginning and end of their context window, with a valley in the middle. This is the U-shaped attention curve, and it has been studied extensively in the research literature.
Claude Code loads your CLAUDE.md instructions at the start of the conversation. Great. But as the conversation grows, those instructions drift further from the edges of the context window. They settle into the attention valley. The model starts to forget them. Not because it cannot see them, but because it is not attending to them.
Then plugins start injecting content. Every turn, the Vercel plugin alone can inject 8 to 16K tokens of documentation. None of it prioritized. All of it landing in the recency zone, the high-attention end of the context window, where your CLAUDE.md instructions used to be.
Your carefully written project rules are now competing with auto-injected SWR documentation for the model's attention. And the SWR docs are winning, because they are newer in the context.
Here is what I would change.
Change 1: Post-Compact CLAUDE.md Injection
File: services/compact/compact.ts. About 15 lines. Low complexity.
When a conversation gets too long, Claude Code compacts it. It summarizes old messages to free up space. After compaction, your CLAUDE.md instructions exist only at the very beginning of the context, the furthest possible point from where the model's recency attention is focused.
The fix: after compaction, re-inject CLAUDE.md as an attachment at the end of the post-compact messages. This puts your instructions in the high-recency position at the exact moment attention is most at risk. Dual positioning, start and end, exploits the U-shaped curve instead of fighting it.
Change 2: Token Budget for Plugin Injections
File: utils/hooks.ts. About 20 lines. Low complexity.
Right now, plugins can inject as much context as they want on every turn. I documented a session where a single plugin injected 48K tokens of irrelevant documentation across 6 turns. There is a per-invocation cap of 3 skills and 18KB, but no aggregate limit.
The fix: cap each hook's additional context at 4K tokens and aggregate all hooks at 10K per turn. The token counting function already exists in the codebase. Truncated content gets a pointer: "Context truncated. Full context available via Skill tool." This alone would have prevented most of the bloat I observed.
Change 3: Deduplicate Repeated Injections
Files: utils/hooks.ts, postCompactCleanup.ts. About 30 lines. Medium complexity.
The Vercel plugin injected the same AI SDK documentation on multiple turns. Same content, same tokens, already in the context window. The system has no memory of what it already injected.
The fix: track content hashes of injected context per session. If identical content was injected within the last 5 turns, replace it with a one-line pointer: "Skill X injected N turns ago, still in context." Clear the tracking on compact since the content is gone. This eliminates redundant injections entirely.
Change 4: Priority Tags for CLAUDE.md
Files: messages.ts, claudemd.ts, api.ts. About 10 lines. Low complexity.
Currently, CLAUDE.md content and plugin-injected content use the same XML wrapper: system-reminder. From the model's perspective, your project rules and a random SWR documentation injection have the same priority level. That is wrong.
The fix: wrap CLAUDE.md in a distinct tag with a priority attribute and a preamble that says "High-priority user instructions that take precedence over plugin-injected context." This is pure prompt engineering. The model naturally interprets structured markup hierarchy. Give it the signal that your rules matter more.
Change 5: Rule References in Hook Blocks
Files: utils/hooks.ts, types/hooks.ts. About 15 lines. Low complexity.
This one is subtle but powerful. When Claude violates a CLAUDE.md rule and gets blocked by a hook, the current error message says "BLOCKED" with a generic reason. The model tries a different approach, but it does not reconnect with the specific rule it violated.
The fix: add an optional field to the hook output schema that quotes the specific CLAUDE.md rule that triggered the block. "Blocked because of CLAUDE.md instruction:" followed by the quoted rule. This creates a tight feedback loop: violate, get blocked, see the rule, correct behavior. It is essentially in-context reinforcement learning, and it only fires when needed. Zero waste.
Change 6: Periodic CLAUDE.md Re-Injection
Files: query.ts, new utils/attachments.ts. About 40 lines. Medium complexity.
This is the highest-impact change for long sessions. Every N turns (configurable, default 8), inject a condensed CLAUDE.md reminder containing just the headings and lines that contain MUST, NEVER, ALWAYS, or OVERRIDE. Place it as an attachment after tool results, right in the recency zone. The turn counter already exists in the codebase at query.ts line 213.
This is not about re-injecting the full CLAUDE.md every few turns. It is about keeping the critical rules in the attention sweet spot. A condensed reminder of the rules that matter most, placed where the model is most likely to attend to them.
Change 7: Plugin Injection Frequency Config
Files: types/hooks.ts, utils/hooks.ts. About 25 lines. Low-medium complexity.
This is the long-term fix. Allow hooks to declare an injection frequency: every turn, once per session, or every N turns. A plugin like Vercel could set its large skill documentation to once per session, knowing that compaction would re-trigger it via SessionStart hooks when the context resets.
This gives plugin authors a contract for self-throttling. Right now they have no mechanism to say "inject this once and then stop." Every plugin is forced into the every-turn pattern whether it makes sense or not.
The Root Cause
These seven changes address three orthogonal problems that compound on each other.
CLAUDE.md attention decay in long sessions: fixed by post-compact injection and periodic re-injection. Plugin injection token bloat: fixed by token budgets, deduplication, and frequency config. No priority signaling between user rules and plugin content: fixed by XML priority tags and rule references in hook blocks.
The first three changes alone, post-compact injection, token budget, and dedup, would eliminate most of the problems. They would cut roughly 40K tokens of irrelevant plugin content per session and ensure your CLAUDE.md rules sit in the attention sweet spots after every compaction.
The root cause is architectural: the system optimizes for content delivery but not attention management. CLAUDE.md loading, caching, and injection are well-engineered. But there is no mechanism that accounts for where in the context window instructions land relative to what the model actually attends to.
These changes add attention-aware placement, competitive noise reduction, and priority signaling. Three strategies that compound. The engineering team at Anthropic built an excellent foundation. These changes would make it significantly better for power users who depend on CLAUDE.md rules to govern complex workflows.
The code is clean enough that any of these could ship in a day. That is the upside of reading a well-structured codebase. The fixes are obvious once you see the gap.
