CLAUDE.md rules not propagated to Agent subagents and weakened after context compaction

Status Closed — not planned
Maintainer reply None cached
Activity 13 comments · opened May 15, 2026 · closed Jun 16, 2026

Summary

CLAUDE.md instructions and skill rules are not reliably followed in two specific scenarios:

  1. Agent subagents do not inherit the parent's CLAUDE.md rules
  2. After context compaction, rule adherence degrades significantly

Reproduction

I have a detailed CLAUDE.md with specific tool restrictions:

  • "Use rg or ugrep instead of grep"
  • "Never use python3 -c / perl -e for inline execution"
  • "Use Read/Edit/Write tools instead of Bash for file operations"

These rules are followed correctly at the start of a conversation, but are violated in the following conditions:

Case 1: Agent subagents don't inherit CLAUDE.md rules

When spawning subagents via the Agent tool (e.g., subagent_type: "Explore"), the subagent does not receive the parent's CLAUDE.md instructions. The subagent then uses unrestricted tools (e.g., grep instead of rg, or python3 -c for parsing).

The coordinator prompt passed to the agent does not and cannot reproduce the full CLAUDE.md rules. This makes any tool restriction rules effectively unenforceable when work is delegated to subagents.

Case 2: Rules weaken after context compaction

In long conversations where context is compacted, the detailed behavioral rules in CLAUDE.md (loaded at session start) appear to lose effectiveness. The model falls back to familiar patterns:

  • Using python3 -c to parse JSON instead of using the Read tool
  • Using grep instead of the configured rg/ugrep

This is especially noticeable when the model is focused on completing a task quickly and "forgets" the custom tool preferences.

Expected Behavior

  1. Agent subagents should inherit at minimum the CLAUDE.md rules from the parent session, or there should be a mechanism to pass key restrictions to subagents.
  2. After context compaction, CLAUDE.md rules should maintain their priority throughout the entire session, not just in the initial turns.

Environment

  • Claude Code CLI, model: Claude Sonnet 4
  • CLAUDE.md with extensive tool restriction rules and skill plugin rules
  • macOS Darwin 25.5.0

Workaround

Currently the only workaround is to manually correct the model each time it violates a rule, which defeats the purpose of having persistent instructions in CLAUDE.md.

View original on GitHub ↗

12 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/40459
  2. https://github.com/anthropics/claude-code/issues/19471
  3. https://github.com/anthropics/claude-code/issues/29423

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

hipvlady · 3 months ago

Confirming both failure modes against Claude Code v2.x with similar CLAUDE.md restrictions on tool selection. The two are the same root cause at different scales.

Case 1 (subagent inheritance): the parent session's CLAUDE.md is loaded into the parent's context but isn't propagated into the subagent's context payload. The subagent starts with a fresh context that doesn't include the CLAUDE.md instructions, so tool-restriction rules effectively don't exist for it. This is state-coordination, not instruction-following — each agent has its own view of "the rules," with no mechanism to ensure they agree.

Case 2 (post-compaction degradation): compaction is a checkpoint boundary that doesn't preserve the priority weighting of CLAUDE.md instructions. The rules survive textually but their effective priority shifts as the compacted summary takes precedence. Same family as the stale-state-across-checkpoint pattern in langchain-ai/langchain#36957 and recent LangGraph issues (#7714, #7780).

The three referenced duplicates (#40459, #19471, #29423) span 6+ months of the same report shape, which strongly suggests this isn't going to be fixed inside Claude Code itself. The structural answer probably needs to be external: a coordination layer that tracks "what version of CLAUDE.md is each agent operating against" and surfaces drift on the next tool call.

I've been working on exactly this layer (multi-agent state coordination) and a Claude Code plugin is in active development. Happy to compare notes if you're interested — repo is in my profile.

phpmac · 3 months ago

Interesting diagnosis. The state-coordination vs instruction-following distinction makes sense -- subagent context isolation and compaction priority drift being the same root cause at different scales tracks with what I've observed.

Quick check before I dig into your repo -- is this using Claude Code's hook mechanism (PreToolUse/PostToolUse) to intercept and re-inject CLAUDE.md rules, or a different approach? Curious whether you're solving this at the hook layer or somewhere else in the stack.

Happy to compare notes either way.

hipvlady · 3 months ago

Yes — hook-based. PreToolUse + PostToolUse + SessionStart, talking to a lazy-spawned local SQLite-WAL coordinator at the parent repo root. The mechanism is closer to surfacing drift than re-injecting rules:

  • SessionStart lazy-spawns the coordinator if it's not already running (fcntl lock on a pid file — first session wins, the rest connect).
  • PreToolUse Read on a tracked artifact (CLAUDE.md, plan/spec files; configurable allowlist) checks the coordinator: if your session has a stale version compared to what another session has committed, the response injects additionalContext with a warning. The agent typically re-reads on its own — no forced re-injection of rules, no permissionDecision: "deny" blocking. The warning is visible inside the agent's own context on the next tool call.
  • PreToolUse Edit|Write acquires EXCLUSIVE on the artifact (MESI single-writer invariant); PostToolUse commits or releases.

Your two cases map onto this directly:

  • Case 1 (subagent inheritance): the coordinator lives at the parent repo root, so subagents calling hooks hit the same registry as the parent. The subagent's first Read of CLAUDE.md fetches it through the coordinator (Shared state); any subsequent update by anyone in the workspace surfaces drift on its next tool call. Subagent doesn't need to inherit the content — it just needs the same coordinator view.
  • Case 2 (post-compaction): if compaction drops CLAUDE.md from your working context, the next tool call's PreToolUse still re-checks the coordinator and surfaces a warning to re-read. The version-mismatch surface doesn't depend on whether the textual rules survived compaction.

Not in v0.1: strict mode. I tested permissionDecision: "deny" empirically and Claude retries with a different tool_use_id rather than changing strategy → budget-cap loops. So v0.1 ships warn-only; strict mode is v0.2 with proper retry-loop handling.

v0.1 private alpha is shipping shortly (Python coordinator), then v0.1.1 marketplace-public on a 4-week deadline. Your setup is the canonical dogfood profile — extensive CLAUDE.md, subagent-heavy, long sessions hitting compaction, macOS. If you'd want a private-alpha invite once installable, reach out to public email on my GitHub profile.

hipvlady · 3 months ago

The "shipping shortly" from above shipped. Plugin repo: https://github.com/hipvlady/agent-coherence-plugin

v0.1 private alpha — install is two-step for v0.1 (Python coordinator + claude plugin), collapses to one-click in v0.1.1 (Node MESI-subset rewrite, 4-week hard deadline):

pip install agent-coherence
claude plugin install git@github.com:hipvlady/agent-coherence-plugin.git

What works today:

  • PreToolUse Read surfaces stale reads via additionalContext — the agent re-reads on its own
  • PreToolUse Edit|Write acquires EXCLUSIVE; PostToolUse commits or releases on tool failure
  • Stop hook releases any uncommitted grants at end-of-turn (so abandoned edits don't block peers for ~120s)
  • Lazy SQLite-WAL coordinator at parent repo root; fcntl-locked port file; auto-gitignored .coherence/ dir; shared-secret Bearer auth
  • macOS / Linux / WSL2

Not in v0.1: strict mode (permissionDecision: deny retries with fresh tool_use_id on v2.1.131 — deferred to v0.2 with proper handling), native Windows.

One thing worth verifying day-one: I claimed Task-tool subagents (subagent_type: "Explore") hit the same coordinator as the parent session — because hooks are workspace-level — which follows from how hooks.json loads but isn't empirically probed yet. Your repro is the canonical test case. If subagent hook firing differs from what I assumed, it's on the v0.1 critical path.

One question that would shape v0.1.1 before the marketplace cut: the default tracked-artifact set is CLAUDE.md, AGENTS.md, anything under docs/{specs,plans,brainstorms}/, and plan.md|task.md|spec.md at any depth. If you have tracked-file conventions in your own CLAUDE.md or workflow — runbook.md, architecture.md, anything outside docs/ — happy to fold the patterns into the defaults. Defaults shipped wrong are friction; defaults shipped right are invisible.

phpmac · 3 months ago

@hipvlady Interesting approach with the MESI coordinator. I was working on the same problem and found that the native SubagentStart + PreCompact hooks with additionalContext (added in v2.1.9) seem to cover the subagent rule propagation case pretty cleanly — just read CLAUDE.md and inject it on spawn, re-inject before compaction. ~40 lines of Python, no external dependencies.

Curious — have you compared the stateful MESI approach against a simpler fire-and-forget injection? I'd expect the overhead of per-file state tracking to matter more in concurrent multi-session scenarios, but for the single-workspace subagent case it seems like the hook injection might be sufficient? What's your take on where the tradeoff actually kicks in?

hipvlady · 3 months ago

You're right, and the test result is the proof — for the subagent-instruction-propagation case your bug actually describes, SubagentStart + PreCompact injection is the cleaner fix, and 40 lines beats a coordinator any day for that scope.

I read #59309 through the lens of state-coherence (the project I'd been building) and it now reads more naturally as instruction-propagation. The two problems share a symptom shape ("subagent did the wrong thing") but the cause is different — yours is "subagent didn't see the rule"; the case I built for is "two sessions disagree about the current version of a shared file."

Where MESI actually earns its weight: concurrent multi-session file coherence. Two Claude Code sessions in different worktrees both read plan.md at v1, one updates to v2, the other works to completion on the stale version and produces a PR or any output that reflects the wrong spec.

That's a real failure mode in Agent View and parallel claude --bg setups, and hook injection doesn't address it because the staleness is state-level (the file is genuinely older than another session's version), not instruction-level (the rule is absent from context).

Honest question back: have you seen the concurrent-multi-session case in practice — two sessions diverging on a shared file across worktrees — or is that mostly speculative from your seat? My discovery cohort is small and you're a leading data point.

kcarriedo · 3 months ago

Both failure modes here have shown up in our setup as well (long-running coordinator process driving Claude Code on a recurring schedule), and the framing in this thread — "instruction propagation vs. state coherence are the same symptom from different causes" — matches what we ended up modeling internally.

Two adjacent data points that may be useful for whoever's triaging this:

On the subagent inheritance case: the SubagentStart + PreCompact injection approach @phpmac described is what we landed on for the content problem (rules absent from the subagent's context). It is materially simpler than a coordinator and fully sufficient when the rule surface is rule-shaped (CLAUDE.md, tool restrictions, style guides). The 40-line implementation is the right shape if that's the whole problem.

The case that the hook-injection pattern doesn't cover cleanly is when the substance of CLAUDE.md changes mid-session — operator commits an updated CLAUDE.md, one running subagent never re-reads, ships work that violates the new rule because its injected snapshot is from 20 minutes ago. We see this on long-running cycles where the orchestrator process keeps spawning subagents across CLAUDE.md edits. The hook fires at spawn, but the spawn was already past the edit. Fixable by re-firing the injection on PreToolUse Read of CLAUDE.md, but at that point you're inching toward the coherence-tracking shape @hipvlady's plugin codifies.

On the post-compaction degradation: matching observation. The textual rules survive compaction (you can see them in the compacted summary), but their priority weighting drifts — the model treats them as historical context rather than active constraints. Same thing happens with operator directives ratified in conversation that get summarized into past tense ("the user said X"). Mitigation that's worked: write hard constraints to a DECISIONS.md file the agent re-reads on every major step, and reference it explicitly in CLAUDE.md as the source of truth for "rules that override anything else." Treats operator rulings as code rather than conversation. CLAUDE.md is the wrong file for this because it grows unboundedly; a dedicated append-only ledger does better.

Where the "shared coherence layer" earns its weight: the concurrent-multi-session case @hipvlady asked about. We hit it concretely when two Claude Code sessions in separate worktrees both read the same plan.md, one updates to v2, the other runs to completion on the stale v1 and produces a PR that ships the wrong spec. Hook injection doesn't catch this because the file is in context — just out of date. The MESI-style approach (track which version each session has open, surface drift on next tool call) is the right primitive for that failure mode specifically. The two solutions don't compete; they sit at different layers of the same problem.

The deeper structural framing in this thread is the load-bearing observation: "tools/rules appear available nominally, the runtime can't honor them, the LLM completes the call as text rather than surfacing an error" is the same anti-pattern as #59907 (auto-distributor pseudo-teammate injection), #59968 (skill tool not inheriting Agent grant), and the recently-reopened #54595 (foreground dispatch silently removed). Closing that one anti-pattern at the runtime layer — explicit hardFailure errors when a nominally-available capability can't be honored, regardless of whether the gap is tool-grant or rule-propagation — would cover this issue family in one fix.

Worth +1ing the runtime-side mitigations over plugin-side ones if Anthropic triages: hooks are the right escape hatch but the structural cost is that every operator running multi-agent workflows has to re-derive the same patterns from scratch, and a non-trivial fraction of them never close the loop on stale-state cases because the symptoms are subtle.

hipvlady · 3 months ago

Thanks for the substantive triage — the framing in your second-to-last paragraph is sharper than what I had. A few things worth picking up:

The mid-session CLAUDE.md edit case is exactly the bridge I was missing in my reply to @phpmac. Static hook injection works for "rule absent from spawn context" but breaks for "rule changed after spawn." The cleanest read is that hook injection treats CLAUDE.md as constant-during-session and the coherence approach treats it as a versioned artifact. Re-firing the injection on PreToolUse Read of CLAUDE.md technically works, but at that point you're solving a per-rule-class version of the same versioning problem inline — owning the versioning explicitly ends up cleaner than re-deriving it per artifact.

The DECISIONS.md append-only ledger pattern is interesting and I hadn't seen it written down. Treating operator rulings as code rather than conversation is the right structural move; the unbounded-growth problem with CLAUDE.md is real and the dedicated-ledger split addresses it cleanly. I'd be curious whether the coherence layer is the right mechanism to track which ledger entries each agent has acted on — same primitive applied to a different artifact shape. If it's useful I'd want to talk about it outside the thread.

The plan.md scenario you described is verbatim the failure mode the plugin I've been building targets. PreToolUse hook surfaces the version drift inline — additionalContext warning naming the other session, the version delta, the holder's last-write timestamp — so the stale session sees the change before its next tool call lands. MESI-shaped underneath; practically a coordinator-per-workspace, lazy-spawned, SQLite-backed, no daemon. Currently in private alpha. If it'd be useful for your setup, happy to share install instructions and treat your feedback as primary signal — the operator-driving-Claude-Code-on-a-schedule shape is exactly the case I'd want to validate against.

On the structural anti-pattern argument: agree the runtime-side hardFailure path is the right long-term fix and worth +1ing. Narrow caveat — even if Anthropic ships it for the rule-grant case, the concurrent-multi-session state-coherence case doesn't go away. hardFailure tells you when a capability can't be honored; it doesn't tell you when two parallel sessions disagree about the current state of a shared artifact. The two layers serve different failures. So: +1 the runtime advocacy for the structural family AND continue iterating on the coherence layer for the case the runtime fix doesn't reach.

Reading #59907 / #59968 / #54595 next — the issue-family observation is the unlock.

Claudeverse looks directly in this territory — would be worth comparing notes properly. Email you?

kcarriedo · 3 months ago

Confirming both behaviors from independent reproduction (different toolchain, similar restriction style in CLAUDE.md — rg over grep, Read/Edit over cat/sed, no inline python3 -c).

A few notes that may help narrow the root cause:

Case 1 (subagents don't inherit CLAUDE.md):

The behavior is consistent with the documented "Agent tool subagents start with a fresh context window" design, but the user-facing surprise is that CLAUDE.md is documented as a project rule file, not as a parent-context fact. Users reasonably expect project rules to be project-wide invariants, not session-local conventions. The mental model break is the bug, even if the implementation is by design.

Two workarounds I've validated:

  • Inject CLAUDE.md into the subagent prompt at dispatch time. Concretely: read CLAUDE.md from disk in the parent, prepend <project_rules>...</project_rules> to the prompt parameter of every Agent(...) call. Costs tokens on every dispatch, but it's the only thing that makes restrictions actually stick. The fragility: any tool restriction you add to CLAUDE.md must also be added to the wrapper that does this prepending.
  • Encode the most security-sensitive restrictions as settings.json permissions.deny rather than CLAUDE.md prose. python3 -c "*" and perl -e "*" can be denied at the permission layer, which subagents do inherit. CLAUDE.md prose is a soft norm; permissions.deny is a hard wall. The wall is the one that holds.

Case 2 (rules weaken after compaction):

This one is harder to work around and matches what I've seen too. The compaction summary preserves recent message content but tends to drop "ambient setup" — and CLAUDE.md, loaded at session start as a system-style message, falls into the ambient-setup bucket. After compaction, the agent has the conversation but not the rules.

Two things that helped:

  • Re-emit CLAUDE.md after /compact (a hook on the Stop event, or a manual reminder) — brittle, but it works.
  • Move tool restrictions out of prose and into settings.json wherever they're expressible there. Permission rules survive compaction; prose rules don't.

Neither workaround is a fix — they're patches for the structural issue that rules-as-prose are subject to context economics, and any system where the rule is more fragile than the policy is going to leak. Worth flagging that the same failure mode applies to skill instructions and slash-command prompts loaded at session start.

Happy to share the compaction-survival test fixture I'm using if it'd help triage.

hipvlady · 3 months ago

The rules-as-prose vs rules-as-config distinction is the right structural framing — "any system where the rule is more fragile than the policy is going to leak" is the load-bearing one-line summary of the whole thread. permissions.deny IS the right home for tool-class restrictions (rg over grep, no python3 -c, etc.) — prose was always the wrong substrate for those.

What's left in the prose layer after the config-able rules move out: architectural context, design constraints, project state, active-work artifacts (plan.md, spec.md, runbook.md). Those can't be permissions.deny — they're descriptive, not prescriptive. Which is also why they're the hardest to keep coherent: they degrade silently via compaction within a single session, propagate inconsistently to subagents on spawn, and (the case I've been building for) drift across parallel sessions in different worktrees.

The plugin I'm working on targets that residue: not "all CLAUDE.md rules need coherence," but the prose subset that survives config-ification still needs versioning, and the cross-session case is where the hook-injection pattern can't reach. Stripping the config-able rules out of CLAUDE.md is good hygiene that makes the remaining surface smaller AND sharper — your workaround #2 is the right move regardless of whether anyone runs a coherence layer alongside it.

Would value the compaction-survival fixture if you're willing to share. Unit 9 of my v0.1 build is a behavior-change harness — do agents actually re-read when a stale-read warning lands? — and a curated "rules degraded via compaction" fixture would be high-leverage for measuring whether re-injection restores behavior, not just rule presence. Credit and follow-up findings shared back.

Reachable at email at my GitHub profile public email if there's anything worth taking offline.

github-actions[bot] · 2 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

Showing cached comments. Read the full discussion on GitHub ↗