← Claude Code Hub
Oct 24, 2026 · 5 min read ✦ Tip #239

Claude Code @ file mentions eat tokens: send the path, not the file

Every @ in Claude Code attaches the whole file before Claude starts. CLAUDE_CODE_DISABLE_FILE_MENTIONS turns it into a path Claude reads with its own tools, and only as much as the question needs.

Comparison in Claude Code: by default @ attaches the whole file before Claude starts, 16,418 new tokens; with CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 a note with the path arrives, Claude runs a grep and it costs 5,637

TL;DR Export CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 in your shell or in the env block of ~/.claude/settings.json. From then on @src/file.ts attaches nothing: Claude gets the path with a note and reads, with its own tools, as much as the question needs. Asking about one function in a 22 KB file cost 16,418 new tokens by default and 5,637 with the variable. Leave it off when you want the whole file in context.

Every @ in Claude Code is resolved before the model sees your message: Claude Code reads the file from disk and attaches it whole to the turn, with the CLAUDE.md of its tree thrown in, as the hidden cost of @ measures. It costs no turn, but how much goes in is decided by you when you type the @, not by Claude when it reads the question. Since v2.1.299, CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 swaps the attachment for a one-line note with the path, and Claude decides what to read and how much.

What Claude receives with the variable

The note, as it sits in the v2.1.310 binary:

The user @-mentioned src/payments.ts. File contents are not attached automatically in this session: if these are files or directories in your working directory, read them with your file tools before responding.

Nothing else: not the file, and not the listing if it was a directory. In the session's .jsonl the attachment changes type, file with the whole content against at_mention_reference with the list of paths:

jq -r 'select(.type=="attachment") | .attachment
       | select(.type=="file" or .type=="at_mention_reference")
       | "\(.type)\t\(.filename // (.mentions|join(",")))"' \
  ~/.claude/projects/<your-project>/<session>.jsonl

What each path costs

The same question, "what does handler42 return in @src/payments.ts", on a 22 KB file in a scratch project, in -p runs of Claude Code v2.1.310. New tokens are the ones the turn adds to context (cache_creation_input_tokens), the same ones re-read on every later turn:

model        default                               with the variable
Sonnet 5.5   whole file attached, 16,418 new       note + grep, 5,637 new
Haiku 5.5    whole file attached, 16,415 new       note + cat of the file, 16,611 new

About 4,700 of each figure is session startup, the same in both columns. The rest is what changes:

  • Sonnet ran grep -n handler42 and pulled 25 lines: close to a thousand tokens against the file's 11,700. And what stays in the history is the fragment, not the file.
  • Haiku read the whole file anyway, with a cat. The same cost as the attachment, plus one call. The variable saves nothing on its own: it hands the model the decision you used to make, and a small model with a vague question reads everything.

Asking for a summary of the file saves nothing either: the model needs the whole file and reads it with Read, which adds line numbers (15,955 new over two calls against 18,222 for the attachment, on Haiku). The saving comes when the question points at a part.

The large file that already came in this way, silently

By default @ attaches the file only when it fits the Read tool's limit, 25,000 tokens. Above that, on v2.1.310 it attaches nothing and says nothing: with a 60 KB file the mention stayed as text in the message, with no attachment of any kind, and Haiku read the whole thing in two Read calls, 36,188 new tokens, to summarize it. With the variable that file arrives with the same note as the small ones, and the pointed question about it (handler217, on Sonnet) cost 5,339 new with it and 6,677 without, a grep in both cases.

How to turn it on

1. In your shell or in user settings

# this session only
CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 claude

# every session: in ~/.zshrc or ~/.bashrc
export CLAUDE_CODE_DISABLE_FILE_MENTIONS=1

Or in ~/.claude/settings.json, which applies however you launch claude:

{
  "env": {
    "CLAUDE_CODE_DISABLE_FILE_MENTIONS": "1"
  }
}

2. Not in the project

Claude Code ignores this key in .claude/settings.json and .claude/settings.local.json, so a cloned repository can't decide what Claude reads. With --debug it says so:

[WARN] CLAUDE_CODE_DISABLE_FILE_MENTIONS in .claude/settings.json is ignored — project-scoped settings can't set this key. Set it in ~/.claude/settings.json or managed settings instead.

3. Turn it off for one session when you want the whole file

1 and true turn it on; 0 or an empty value turns it off, even with the export in place:

CLAUDE_CODE_DISABLE_FILE_MENTIONS=0 claude

4. Ask with a target

With the variable, @ only tells Claude where to look. "Review @src/auth.ts" reads the whole file; "why does refreshToken in @src/auth.ts return null" allows a grep. A directory, @src/, arrives as the same note and Claude runs ls: 173 new tokens for the listing. The other ways to hand over context are in five ways to give Claude Code the right context.

And one effect that is not about tokens: PreToolUse hooks don't run on an @ attachment, because there is no tool call. With the variable they do, because Claude reads with Read or Bash. If a PreToolUse hook decides what Claude may read, the variable closes that gap.

Reference

Case What Claude receives What it costs
Default, file under 25,000 tokens The whole file and the CLAUDE.md of its tree, before the first turn The whole file, this turn and re-read on every later one
Default, file above that Nothing: the path stays in your text and Claude reads it on its own, unwarned Whatever Claude decides to read, with no note asking for portions
With CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 A note with the paths and the instruction to read them with its tools What the question needs, plus one call

Official docs: Environment variables

Requirements

  • Claude Code v2.1.299 or later. Measured on v2.1.310, in -p runs on a scratch project, with Sonnet 5.5 and Haiku 5.5.
  • The variable is read from the environment, user settings or managed settings; project settings ignore it.
Free guide

The 51 essentials, as a guide.

One page per tip. Five chapters. What I actually use daily in production. No theory, no fluff.

  • I. Getting started 10 tips
  • II. Awareness 3 tips
  • III. Mastery 22 tips
  • IV. Autonomy 10 tips
  • V. Comparison 6 tips
Are you a professional Web developer?

You'll receive the guide by email · You join the Gravitas newsletter · Unsubscribe anytime

of 51
#

Wmedia · 51 Tips
Free guide · 51 tips · 5 chapters

The 51 essentials, as a guide.

Are you a professional Web developer? · Unsubscribe anytime
Workshop for teams

Multiply your team's output without sacrificing quality: a 6 to 8 hour AI First workshop, online, on the Claude platform.

See the workshop

Want the 51 Claude Code essentials as a guide?