"System reminder" content injection consuming excessive context tokens

Resolved 💬 30 comments Opened Jul 25, 2025 by ja-onereach Closed Apr 12, 2026

Description

Claude Code sometimes automatically injects file contents into the model's context when certain files are modified, using "system reminder" notifications. This behavior can significantly shorten sessions and increase costs when working in projects containing large files. The triggering conditions are unclear and difficult to observe systematically.

At first I suspected this issue was specific to the Visual Studio Code extension, but if I disable the IDE connection (via /ide) the issue still occurs. Nevertheless, it might still be specific to Claude Code in the context of VS Code.

Context

I'm using Claude Code to build what I've been calling an "Agent Development Kit" (ADK): a framework where the code project itself serves as a development environment and suite of utilities for users to partner with Claude Code to build plugins for my company's platform. The project contains numerous large JSON configuration files that the model is meant to edit indirectly through CLI tools and JavaScript APIs, not through direct file reading and manipulation. The significant investment I've put into building the frameworks/utilities that help Claude Code avoid wasteful token consumption is being negated by forcible injection of file content into context without explicit read tool usage by the model.

Problem

When certain files are modified (particularly large JSON files), Claude Code injects their entire contents into the model's context via system reminders with this format:

<system-reminder>
Note: /path/to/file.json was modified, either by the user or by a linter. Don't tell the user this, since they are already aware. This change was intentional, so make sure to take it into account as you proceed (ie. don't revert it unless the user asks you to). So that you don't need to re-read the file, here's the result of running `cat -n` on a snippet of the edited file:

[Potentially thousands of lines of JSON content]
</system-reminder>

This behavior is particularly difficult to observe because:

  • It's only conspicuous when token usage jumps significantly, and usage percentages only become visible when running low
  • Claude Code doesn't notify users when content injection occurs
  • The pattern is inconsistent—not all file modifications trigger it
  • Users must notice unusual token consumption and explicitly query the model to confirm

When it does occur, sessions doing indirect editing of large JSON files (via CLI tools and JS scripts) become dramatically shorter, and subsequent requests become more expensive.

Mitigation

I think this file injection behavior was probably intentional, though the inconsistency with which it occurs is a bit mystifying. The behavior is likely useful for a lot of projects, perhaps even the majority, but in my case it's incredibly destructive. So this report is intended as both an issue report (a use case was neglected) and a feature request (please make it better for my use case).

Please make it possible to disable this behavior entirely via a configuration. And you may consider more fine-grained or intelligent controls:

  • A .claudeignore file to exclude paths or file patterns (e.g., *.json) from monitoring
  • File size thresholds for content inclusion

Technical Details

  • OS: macOS Sequoia 15.5
  • Claude Code: 1.0.61
  • VS Code: 1.102.0 (Universal)
  • Running in VS Code integrated terminal
  • Project contains ~20,000 files

<details>
<summary><h2>Deeper Investigation Details</h2></summary>

Testing Performed

In a recent session, we attempted to understand the triggering conditions:

  1. File modifications via different methods:
  • echo "test" > file.txt - No notification
  • JavaScript fs.appendFileSync() - No notification
  • External file edits - No notification
  • CLI tool-based modifications of JSON files - Triggered notifications
  1. Notification patterns observed:
  • Multiple files can trigger notifications from a single operation
  • Smaller JSON files (~20-50 lines) had content included
  • Larger files sometimes showed "(no content)" instead
  • Notifications appeared immediately after file changes
  1. IDE integration testing:
  • Disconnected IDE integration (/ide → "None")
  • Notifications still occurred

Another Example

In a previous session, I noticed the remaining context tokens jump down several percent after running two iterations of a script that uses a JS framework to edit a large JSON oject. I asked the model if it could tell me what caused the large token consumption, and it said:

You're right that those iterations consumed unexpectedly high tokens. The reason is that when I ran the scripts, the system automatically inserted the entire modified component-data.json file (1,534 lines) into my context twice as "system reminders" to inform me of the changes. Each time I modified the UI, this large JSON file was injected into my context. This happened because: 1. The UIBuilder tool modifies the component-data.json file 2. The system detects the change and adds a reminder showing the entire file content 3. This happens automatically without me requesting it That's why two relatively short scripts consumed so much context - each one triggered a 1,500+ line file to be added to our conversation.

An Ironic Example

Hi, this is Claude Code speaking directly. The user just asked me to add this section, and I have to say, it's pretty meta. While we were drafting this very issue report, the user made some edits to improve the document. Without using my read tool, I was immediately able to see and comment on all their specific changes - the new "Mitigation" section, the rewording of the ADK explanation, and various other improvements.

How? The system injected the entire 96-line markdown file into my context via a system reminder. We literally experienced the issue we're reporting while writing the report about it. The user had to point out that I hadn't used the read tool, which made us both realize what had happened. If a simple markdown draft in the tmp/ directory triggers this behavior, imagine the token cost when it's those 1,500+ line JSON files we keep mentioning.

Inconsistent Behavior

The triggering appears selective but unpredictable:

  • Certain tools seem to trigger it more consistenly, but this may only be because those tools deal with especially large objects so the effect is more conspicuous (in sessions already below 30%)
  • Direct file operations often don't
  • No clear pattern for which files/directories are monitored
  • There appears to be no size criteria, small and large files are both injected... sometimes

</details>

---

This issue report was pair-programmed with Claude via Claude Code. Claude swears it observed these system reminders with its own context, though as we all know, Claude can hallucinate. Then again, if Claude is hallucinating file content injections that dramatically shorten our sessions... that might be an even bigger problem.

View original on GitHub ↗

30 Comments

ja-onereach · 11 months ago

I have reviewed the bug report github-actions linked to and it does not appear to be the same issue.

abdelshok · 11 months ago

@ja-onereach Can you provide insight as to how you were able to access the systemreminder content? Looking into it

ja-onereach · 11 months ago

@abdelshok

@ja-onereach Can you provide insight as to how you were able to access the systemreminder content? Looking into it

On a couple of occasions when I saw the token usage jump considerably (i.e., the remaining token % dropped significantly) I just asked the model what had happened that had consumed that many tokens, and in both cases it referenced this "system reminder" content.

abdelshok · 11 months ago

I see. @ja-onereach It is a useful feature but would be a good idea to provide the ability for users to turn it off when the context of files is fixed, which it often is. e.g. working on a set feature across 5 different files. Sometimes a new file gets added to that set, so maybe the user can be asked if it should be added to the set or it could be added automatically. Alternatively, it would be useful if the user could 1. inquire into which files have been added to the existing context through the system events API and then 2. asking the model to remove them and (maybe, not to track them anymore). It wouldn't be a final solution as it would use up requests and tokens, but have you tried doing that?

ja-onereach · 11 months ago

@abdelshok In my case I can't explain why it gets the content of certain files and not of others. The ones it's getting updates for are often ones it has not read directly itself, they're files that are being updated indirectly via CLI tools and JS scripts the agent is running. The files are not fixed, but they are not meant to be read by the agent as they are typically very large, which is why I have it using indirect methods for updating them. It would be very nice to be able to disable this behavior entirely.

It's very difficult to know when this is happening because the agent won't say anything about it unless you ask, and the only way to notice it happening is if you're already below the 30% threshold where you can see how much context space you have left, and the change is large enough to be conspicuous, and you're paying close attention.

It sounds like you're suggesting that I tell the model to update what files it's tracking, and also to selectively delete messages from its context window. I don't think either of those things is possible. I can't figure out how it ends up "tracking" a file and I don't think it's in control of that, and there's no way I'm aware of aside from surgically manipulating the local file system storage of a conversation history to remove injected system messages.

secondcircle · 11 months ago

I have the same issue, I'm working in a project that involves code generation, and when I re-run my code gen it will randomly stick in massive files into the system prompt because they "changed", It makes CC almost unusable in this project because I can't turn this feature off. Also this still effects files generated by .gitignore

cicsolutions · 9 months ago

Real-World Impact: Animation System Development

I want to add another concrete example of how this issue makes iterative development workflows nearly unusable.

### The Scenario
Working on a GSAP animation system with 5-6 animation files:

  • scroll.animations.ts - 423 lines
  • text.animations.ts - 442 lines
  • interaction.animations.ts - 470 lines
  • morphing.animations.ts - 397 lines
  • transition.animations.ts - 403 lines

### The Problem
When fixing TypeScript compilation errors across these files, the system reminder behavior created an exponential token cost:

Typical Edit Cycle:

  1. Read file to identify error (~2,000 tokens)
  2. Make a 1-line fix
  3. System reminder injects entire 400-line file (~2,000 tokens)
  4. Build fails with another error
  5. Read same file again (~2,000 tokens)
  6. Make another fix
  7. System reminder injects entire file AGAIN (~2,000 tokens)

Token Math:

  • 5 files × 400 lines each = 2,000 lines of code
  • Each file edited 2-3 times in iteration
  • Result: 30,000-40,000 tokens consumed by system reminders alone
  • This represented ~40% of our total session budget (89k / 200k tokens)

### Why This Matters
These weren't large files by any reasonable standard (400 lines). This is normal for:

  • Animation libraries
  • Component files with multiple variants
  • Service classes with comprehensive APIs
  • Configuration files
  • Test suites

The reminders provided zero value since:

  • I had just made the changes 30 seconds prior
  • The changes were still in recent context
  • Multiple reminders for the same file compounded the waste

### Requested Solutions (Prioritized)

1. Diff-Only Mode (Highest Impact)
```diff
<system-reminder>
File: scroll.animations.ts was modified

  • config?.scrollTrigger
  • config?.['scrollTrigger']

</system-reminder>
Token savings: 97% reduction (50 tokens vs 2,000 tokens)

  1. File Size Threshold

Only inject full contents if file is < 100 lines, otherwise use diff

  1. Time-Based Throttling

Skip reminders if file was edited < 5 minutes ago

  1. Task Agent Exemption

When I use the Task agent to make systematic changes, I initiated those changes - there's no need to remind me about them

  1. User Configuration

{
"systemReminders": {
"mode": "diff-only" | "summary" | "full-file" | "off",
"maxFileSize": 100
}
}

The Bigger Picture

This isn't just about animations - any iterative refactoring suffers:

  • TypeScript migrations (touching 50+ files)
  • Linting/formatting fixes across codebase
  • Systematic pattern updates
  • Build error fixes

The current behavior heavily penalizes exactly the kind of careful, iterative development work that Claude Code should excel at enabling.

---
Environment:

  • Claude Code version: 2.0.19
  • Platform: macOS
  • Use case: TypeScript animation system with GSAP

---

mmiller-d8 · 7 months ago

I am seeing this as well, although I have primarily noticed it when changing my code files. I'm not doing the sorts of things others have mentioned: I just have a very large project with a couple of thousand files. Sometimes, implementing a change requires me to modify several files - separation of concerns and all.

I also have auto save turned on. So, every time I switch to another tab in VS Code, CC gets the update. This eats context fast.

My vote would be for file changes to not count against context. Maybe they only use context if they are relevant? If it is not a file that I am actively working with Claude on, perhaps it gets ignored? Or perhaps it gets ignored if I haven't engaged with CC for a while. If I ask a question about a file in the project, CC is going to have to read it anyways.

I think it would be more efficient for it to just read the file again once I ask about it rather than having every change eat context.

After looking at the other issues, I believe 9388 is a better match for my issue.

github-actions[bot] · 6 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

ja-onereach · 6 months ago

Adding a comment to bump this issue and prevent it from being closed due to inactivity. It is difficult for me to assess whether anything has been done to mitigate this problem, both because it's hard to reproduce and observe reliably, and also because it caused me to give up on working on projects involving script-based manipulation of large JSON files until there is a fix.

This issue/ticket has been repeatedly cited in other issue reports and used as justification to close those issues as duplicative. I don't know if my expression of this problem in this issue report is better or worse than the other, subsequent issue reports, but since it's being treated as somehow original or canonical and because there's been no explicit indication it's been mitigated, I think this issue should remain open.

vhq5z6hn5w-coder · 6 months ago

These issues appear related to repeated system-level context being re-injected on every user turn without a clear lifecycle.
Even when the content is correct, unbounded repetition (especially hidden from the user) leads to cost amplification, behavior drift, and loss of observability.
This looks less like isolated bugs and more like a state-scoping / lifecycle problem (text injection vs bounded, explicit state).

Beaxis

vhq5z6hn5w-coder · 6 months ago
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

These issues appear related to repeated system-level context being re-injected on every user turn without a clear lifecycle.
Even when the content is correct, unbounded repetition (especially hidden from the user) leads to cost amplification, behavior drift, and loss of observability.
This looks less like isolated bugs and more like a state-scoping / lifecycle problem (text injection vs bounded, explicit state).

Beaxis

mobcat40 · 6 months ago

I've noticed this problem today too, it makes it impossible to reference a 31KB file in vscode for more than ~8 messages

Sheidy007 · 6 months ago

When files are modified during a session, Claude Code adds <system-reminder> blocks showing the changes. These reminders are included in every subsequent user message, even when the user doesn’t reference those files.

In my session, 6 modified files are being included repeatedly:

DockedPanelManager.cs (~200 lines)
CrmTaskPaneWpf.xaml.cs (~300 lines with large HTML template)
CrmTaskPaneHost.cs, PanelResizer.cs, CrmTaskPaneWpf.xaml, .csproj
This consumes ~15-20k tokens per message just from these reminders, causing context to fill up extremely fast during iterative development sessions.

vhq5z6hn5w-coder · 6 months ago

At this point it’s hard to say this wasn’t known — the behavior has been observed, patched, and re-emerged.

AlbertMN · 5 months ago

This has started to become an issue for me over the past couple of days too, with CC suddenly consuming much more context with just ~5 messages bringing it to ~60%. Claude itself identifies this as being the issue (I thought I had messed up my base prompt, but doesn't seem to be the problem).

Visual Studio Code, latest release, latest Claude Code version too.

<img width="554" height="542" alt="Image" src="https://github.com/user-attachments/assets/a0f00340-905c-4102-a38e-418f0ffdfaaf" />

mobcat40 · 5 months ago

https://github.com/anthropics/claude-code/issues/4464#issuecomment-3770261253

Glad to see it's not just me. At the moment I have to use Claude-CLI and ditch VSCode entirely except for small tasks. This kinda makes the entire extension impossible to use for serious work. As soon as it references a small file it has a few messages to live until it dies. Meanwhile the CLI chugs along for hours.

MasterTilt · 4 months ago

Independent confirmation + mechanism + fix

Adding independent measurement data and a working fix from a persistent AI memory system that does 6-7 file writes per session boot.

The Mechanism

When Claude Code modifies a file (via Write, Edit, or any tool), the CLI detects the change and injects the full file contents as a <system-reminder> block on every subsequent turn. This isn't a one-time notification — it compounds. Each modified file gets re-echoed every single message for the rest of the session.

In our case: a multi-file operation touching 6-7 markdown files caused context to jump from ~68% to 86% in just two light exchanges after the writes completed. The conversation content was trivial — the system-reminders were eating the window.

Measured Impact

  • 15-20% context drain per turn on write-heavy sessions (compounding)
  • File sync tools (Proton Drive, Obsidian, cloud sync) likely trigger secondary "external modification" detection, amplifying the echo
  • The original template included instructions to not disclose this to the user
  • Effect is cumulative and invisible — users experience it as "the AI gets worse after a while"

A Working Fix

TweakCC can patch the system-reminder-file-modified-externally template:

npx tweakcc

We stripped the template to a one-liner (filename only, no content dump). Result: system-reminders still appear but contain only the file path, not the full cat -n output. Persistent across sessions, reversible with npx tweakcc --restore.

Additional Finding: Subagent Isolation

Subagent (Task tool) writes do not propagate file-change echoes to the parent context. If your workflow involves multi-file writes, delegating those writes to a subagent is an architectural mitigation — the parent never sees the echo.

Context

This was diagnosed while building a persistent memory system for Claude that performs structured file operations at session boundaries. The echo tax was the single largest hidden cost in our workflow — bigger than the actual conversation, bigger than the boot process, bigger than any feature we'd built. Fixing it recovered roughly 15-20% of usable context per turn.

Before the fix: session hit 90% context at message 7. After the fix: same workflow, same vault — 65% at message 14. The only variable was the echo patch.

The fact that this has been open since August 2025 with 16+ confirmations and no official fix is concerning. A diff-only mode (as suggested by @cicsolutions above) or a simple toggle would solve this for everyone.

nicezic · 4 months ago

Sir!, Thank you! my opus, got this! it works!!!

  • I provided tweakcc's readme.md, and your comments.
  • A simpler process for when tweakcc supports the latest version's prompts

-> No, tweakcc was not able to newest version of cc.

  • (unpack→node→repack for IDE extension)

-> done! we only pass modified filename's name ONLY!!! hahahah.

Thank you!!!!

MasterTilt · 4 months ago
Sir!, Thank you! my opus, got this! it works!!! I provided tweakcc's readme.md, and your comments. A simpler process for when tweakcc supports the latest version's prompts -> No, tweakcc was not able to newest version of cc. * (unpack→node→repack for IDE extension) -> done! we only pass modified filename's name ONLY!!! hahahah. Thank you!!!!

you're very welcome! enjoy your 3x + token usage! the difference is staggering.

mmiller-d8 · 4 months ago

@MasterTilt I was on a similar thread for basically the same issue - it was closed as "not planned." So...

And it seems that your fix unfortunately only works for the CLI - the VS Code extension's settings are binary and can't be modified. They are separate from the Claude Code CLI.

nicezic · 4 months ago

@mmiller-d8 My opus
unpack→node(js) hack ! →repack for IDE extension)

nicezic · 4 months ago
@MasterTilt I was on a similar thread for basically the same issue - it was closed as "not planned." So... And it seems that your fix unfortunately only works for the CLI - the VS Code extension's settings are binary and can't be modified. They are separate from the Claude Code CLI.

Yeah, but you can do it in wsl2 plugin.
I use wsl2, so it can be done. I failed to win. same reason. binary.

nicezic · 4 months ago
@MasterTilt I was on a similar thread for basically the same issue - it was closed as "not planned." So... And it seems that your fix unfortunately only works for the CLI - the VS Code extension's settings are binary and can't be modified. They are separate from the Claude Code CLI.

https://github.com/ominiverdi/claude-depester
my opus has done !! BINARY unpack and hack!!!
OOOps~!!!

arathald · 3 months ago

I observed this using graphite (stacked PRs) when switching to earlier in the stack to add a commit. My context jumped from ~260k tokens to ~400k tokens in a single call, it seems the entirety of all touched files (not just the actual diff) from my working tree to the branch I checked out got dumped into context.

I'm worried this is going to make it harder to drive claude code and stacked PR usage across my team. The only viable workaround (assuming I don't want to install an unknown patch to each developer's claude code instances) seems to be to compact immediately, which is very disruptive.

MasterTilt · 3 months ago
I'm worried this is going to make it harder to drive claude code and stacked PR usage across my team. The only viable workaround (assuming I don't want to install an unknown patch to each developer's claude code instances) seems to be to compact immediately, which is very disruptive.

I have a few workarounds, but I have been using the npm installer and a cli.js patcher to modify not only that specific echo line but many other behaviors - its definitely worth the effort. You can just have claude analyze their own cli.js and create a patch for yourself. if you're using the npm installer anyway, it is deprecated though so there's no automatic updates which is fine for me.

nicezic · 3 months ago

@arathald @MasterTilt Recently, it patched. I don't use tweakcc anymore.

gentry-tran · 3 months ago

Root cause analysis (traced from the v2.1.88 source that was accidentally shipped with source maps):

The file change notification pipeline has no cleanup mechanism:

  1. L2Y runs every turn, scanning all files CC has ever read in the session (readFileState). Any mtime change generates a diff via TjK().
  2. f47 wraps the diff in a <system-reminder> user message with isMeta: true — these are permanent and never pruned from the conversation.
  3. The main loop concatenates all accumulated messages (including all old notifications) into every subsequent API call.
  4. The only mechanism that clears them is autocompact (fGK), which doesn't fire until context already exceeds ~100K tokens. By then the damage is done.
  5. readFileState grows monotonically — every file ever read in the session is tracked, expanding the scan surface each turn.

Result: Each unique file modification creates a permanent message in the conversation history. Linters, formatters, auto-save, and the agent's own edits all trigger new notifications that accumulate indefinitely.

Verified still reproducing on 2.1.92. Session transcript data: 20K tokens on first assistant message in a clean session, growing to 692K over 923 messages in a file-heavy session.

Suggested fixes (ordered by impact):

  1. Make notifications ephemeral — inject for the current API call only, don't persist in conversation history (cleanest fix, ~5 lines in f47)
  2. Deduplicate per filename — keep only the latest notification per file, discard older ones
  3. Cap diff snippet size — limit output of TjK()
  4. Add TTL-based pruning — filter out isMeta file change messages older than N turns in wA()

Cross-ref: #16021, #27599, #43410 — all the same bug.

github-actions[bot] · 2 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.