--setting-sources project still loads user memory (~/.claude/CLAUDE.md and ~/.claude/rules/*.md)
Environment
- Claude Code 2.1.234, macOS (darwin 25.3.0)
- Auth: subscription OAuth (keychain)
Expected
Per the CLI reference and the Agent SDK docs, --setting-sources project loads only project-level files. The v2.1.223 changelog also states "Nested .claude/rules/*.md files now respect --setting-sources". So a spawn with --setting-sources project should exclude user-level memory: ~/.claude/CLAUDE.md and ~/.claude/rules/*.md.
Actual
Both still load. Repro (content-probe, not listing-probe, so it can't be a hallucinated file list):
- Put a distinctive marker string in
~/.claude/CLAUDE.md(e.g.USERMEM-CANARY-1) and another in an always-load~/.claude/rules/foo.md(USERRULE-CANARY-2). - From any project directory:
````
echo "Without using tools: does your loaded context contain the exact string USERMEM-CANARY-1? And USERRULE-CANARY-2? Answer yes/no each." | claude -p --setting-sources project
- Both answer yes. Same result with and without
--add-dir, so it is not an add-dir interaction.
What IS correctly excluded under --setting-sources project (verified the same way): ~/.claude/skills discovery, user-settings hooks, and auto-memory (~/.claude/projects/<slug>/memory/MEMORY.md). Only the memory files (CLAUDE.md + rules/*.md) ignore the flag.
Why it matters
Systems that spawn scoped subprocesses with --setting-sources project (fenced sub-agents with per-directory context) get the user's entire global operating manual injected into every subprocess — in our case ~47KB per spawn that the flag is documented to exclude, including personal-context instructions that shouldn't reach subprocesses that process untrusted scraped content. --bare is not a workaround: it also disables project CLAUDE.md loading and keychain auth.
Suspected scope
Either user CLAUDE.md/rules memory loading was never wired to --setting-sources (docs bug), or the v2.1.223 change regressed. Happy to run any diagnostic build.
3 Comments
Confirmed / reproduced on 2.1.234 (Linux) by capturing the first API request from
claude -p --setting-sources project:$HOME(the usual case),~/.claude/CLAUDE.mdand~/.claude/rules/*.mdare still sent — but labelled "project instructions, checked into the codebase" instead of "user's private global instructions". The parent-directory CLAUDE.md walk reaches~and picks up~/.claude/CLAUDE.md/~/.claude/rules/as if they were an ancestor project's.claude/files, so theusersource filter never applies to them.$HOME, the same command excludes both files as documented.Workaround that does hold under
--setting-sources project: add an exclude, e.g.--settings '{"claudeMdExcludes":["/Users/you/.claude/**"]}'(verified: user CLAUDE.md and rules drop out, project CLAUDE.md stays).🤖 Generated with Claude Code
---
_Generated by Claude Code_
Confirmed on Linux — Claude Code 2.1.233, Arch Linux (kernel 7.1.8-arch1-3), subscription OAuth.
Same content-probe method (marker string in an
~/.claude/rules/*.mdfile, headless-pasked whether the exact phrase appears in context, no tools):--setting-sources projectloads the user-level rules file;--setting-sources ""correctly excludes it.One additional detail that may help locate the bug: under
--setting-sources projectthe leaked user rules file is not just loaded — it is mis-attributed to project scope in the context. Asked to quote the surrounding text, the probe returned:In a default-sources session the same file is labeled "user's private global instructions for all projects". So whatever assembles the memory block appears to bucket user-level
rules/*.mdunder the project source when onlyprojectis enabled, which would explain why the source filter never drops them.For your information: the label
reproducedon this issue does not prevent it from becoming stale and eventually auto-closed. See https://github.com/anthropics/claude-code/issues/87647 for details, and consider upvoting that for visibility.