cd /news/artificial-intelligence/i-grepped-my-own-claude-code-logs-an… · home topics artificial-intelligence article
[ARTICLE · art-75561] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

I Grepped My Own Claude Code Logs and Found the Hidden Tag Anthropic Never Shows You

A developer discovered that Anthropic's Claude Code injects a hidden system-prompt tag, `<ip_reminder>`, on every turn for copyright safety. By grepping their own session logs, they found 151 lines matching the tag and 17 opening tags with zero closing tags, indicating the tag is often truncated. The developer verified the tag's presence independently, while four related GitHub issues on `anthropics/claude-code` were closed as 'not planned.'

read6 min views1 publishedJul 27, 2026

I was mid-conversation with Claude Code, asking it to help draft a blog post, when a literal

<ip_reminder>

tag showed up pasted into my own message. I hadn't typed it. It took me a few

minutes of back-and-forth with the model to figure out what I was even looking at.

TL;DR: ip_reminder is a real, non-displayed system-prompt injection Claude Code sends on every turn for copyright safety. You don't have to trust anyone's self-reported numbers about it — you can grep your own session logs and count it yourself. In my case: 151 matching lines, 437 raw occurrences, in one session file alone.

I use Claude Code daily across a handful of projects, and one thread of work turned into asking

the model whether it was safe to write publicly about something I'd noticed: a block of text that

looked like a system tag, <ip_reminder>...</ip_reminder>

, had turned up inline in the

conversation. Claude's own response to seeing it was telling:

"今回の

<ip_reminder>

は本物のシステム注入ではなく、ユーザーが手打ちでメッセージ本文に貼り付けたテキスト...

なお直前のBash結果内に埋め込まれた<ip_reminder>

ブロックは、ツール出力に混入した外部由来のテキスト"

Translated: this occurrence was pasted by the user, not a live system injection. A few turns

later, while trying to hand a prompt containing that same discussion off to a delegation script

via a Bash command, an argument-parsing error (exit code 2

, wrong flag) caused part of the

prompt text — including an <ip_reminder>

-shaped fragment — to spill back out into the tool's

error output. Claude flagged that second appearance explicitly as "text mixed into a tool result

from an external source" and disregarded it as an unrelated instruction rather than acting on it.

Neither occurrence was a live, hidden system-level injection in that moment — but the tag had

already become real enough, twice, in two different ways, that I wanted to know what it actually

was.

Instead of taking my own memory of that exchange at face value, I went back to the actual

transcript. Claude Code writes every session to a JSONL file under

~/.claude/projects/<project-key>/

, one line per event, and nothing in that file is edited after

the fact — it's the closest thing I have to a raw record of what really happened.

PROJECT_KEY=$(pwd | tr '/' '-')
LOG_DIR="$HOME/.claude/projects/$PROJECT_KEY"

grep -c "ip_reminder" "$LOG_DIR"/*.jsonl

grep -o "<ip_reminder>" "$LOG_DIR"/*.jsonl | wc -l
grep -o "</ip_reminder>" "$LOG_DIR"/*.jsonl | wc -l

Run against the session file where this happened, that gave me:

151 lines matched "ip_reminder"
437 total occurrences of the string
17  literal <ip_reminder> opening tags
0   literal </ip_reminder> closing tags

Zero closing tags against 17 opening tags was the detail that made me stop and actually look

closer, rather than just nod at "yep, it's in there somewhere." Whatever pipeline stage summarizes

or truncates tool output in the transcript apparently drops the closing half of the tag more often

than not — the tag gets cut off, not cleanly removed.

The GitHub-Issue side of this story (four Issues on anthropics/claude-code

, all filed by other

people, all independently discovering the same tag) is worth knowing, but I want to be explicit

about which numbers are mine and which are someone else's, because blending them would be

dishonest:

Someone else's numbers (self-reported, not independently verified by Anthropic):

Issue method reported finding

mitmproxy

traffic capture, 32 days/cost

and /status

outputAll four are state: CLOSED, stateReason: NOT_PLANNED

— confirmed with gh issue view <n> -R

for each. A precursor Issue, #12443 (a different,

anthropics/claude-code --json state,stateReason

malware-warning-flavored hidden reminder, not ip_reminder

itself), is CLOSED, DUPLICATE

.

My own numbers (first-party measurement, same session as above):

I extended the grep into a token-accounting pass, reusing the same JSONL-usage

-field method I'd

used in an earlier post about Claude Code's prompt-cache behavior. I isolated the window of that

session from the first ip_reminder

mention to the end of the file — 432 assistant turns with

usage data — and summed the token fields:

#!/usr/bin/env python3
import json
from pathlib import Path

path = Path.home() / ".claude/projects/<project-key>/<session-id>.jsonl"
lines = path.read_text(encoding="utf-8").splitlines()

start_line = next(i for i, l in enumerate(lines) if "ip_reminder" in l)

cache_create = cache_read = fresh_input = output = 0
turns = 0
for line in lines[start_line:]:
    try:
        e = json.loads(line)
    except Exception:
        continue
    msg = e.get("message", {})
    if msg.get("role") != "assistant":
        continue
    usage = msg.get("usage")
    if not usage:
        continue
    turns += 1
    cache_create += usage.get("cache_creation_input_tokens", 0) or 0
    cache_read += usage.get("cache_read_input_tokens", 0) or 0
    fresh_input += usage.get("input_tokens", 0) or 0
    output += usage.get("output_tokens", 0) or 0

total = cache_create + cache_read + fresh_input
print(f"turns={turns} cache_create={cache_create} cache_read={cache_read} "
      f"fresh_input={fresh_input} cache_read_share={100*cache_read/total:.2f}%")
turns=432 cache_create=2,251,420 cache_read=148,817,233 fresh_input=1,415
cache_read_share=98.51%

98.51% of every input-side token in that stretch of conversation was a cache read, not fresh

input. That's not an ip_reminder

-specific number — it's the whole session's cache behavior — but

it puts the Issue #17601 author's 15.79%-of-context-window claim in a useful frame: even a tag

that's a comparatively small slice of a single request compounds when nearly every token in the

conversation is being replayed from cache turn after turn. I have not isolated the injection

block's own token count per turn; that's a harder measurement than counting string occurrences,

and I'm not claiming to have done it here.

Call it grep before you trust the self-report: when a vendor's hidden-injection behavior shows

up in your own tool, the fastest way to know if it's actually affecting you is to search your own

logs, not to import someone else's Issue thread as if their numbers were yours.

Someone else's 5,358,910 tokens tells you the phenomenon exists. Your own

grep -c

tells you

whether it's happening to you, and how often.

This also reframes what "closed, not_planned" across four Issues actually means for a user. It

doesn't mean the tag stopped existing — Anthropic's own system-prompt documentation

(platform.claude.com/docs/en/release-notes/system-prompts

) still lists ip_reminder

by name

alongside image_reminder

, cyber_warning

, system_warning

, ethics_reminder

, and

long_conversation_reminder

(the exact count of listed types varies by model-version doc section

— 5 in one section, 6 in another, when I cross-checked). The name is acknowledged. The content and

cost accounting are not. "Not planned" means the burden of detection stays on you, permanently,

which is exactly why a local, repeatable detection habit is worth more here than a bug report.

   ls ~/.claude/projects/$(pwd | tr '/' '-')/*.jsonl

(Older sessions may be gzipped — use zgrep

instead of grep

on *.jsonl.gz

files.)

ip_reminder

shows up:

   grep -c "ip_reminder" ~/.claude/projects/*/*.jsonl

What's the highest ip_reminder

count you find in your own logs — and does it change how you

think about what a "turn" in Claude Code actually costs?

Sho Naka (nomurasan). I check my own logs before I quote someone else's numbers. Measured on Claude Code, macOS, 2026-07-23/24.

This piece started from a Japanese investigative essay I wrote after noticing the same tag in my

own session (published on note.com). This English version is a first-person rewrite built from

my own session-log measurements, not a translation — I worked with AI to shape the prose; the

grep commands, the measurements, and the conclusions are mine.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @anthropic 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-grepped-my-own-cla…] indexed:0 read:6min 2026-07-27 ·