[BUG] Claude Code repeatedly violated explicit project rules (AGENTS.md, .claude/rules/) despite them being loaded into context

Resolved 💬 3 comments Opened Apr 6, 2026 by james-belva Closed Apr 10, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

Claude Code repeatedly violated explicit project guardrails defined in AGENTS.md and .claude/rules/ despite these files being loaded into conversation context and even surfaced via <system-reminder> tags during edits.

What happened

User asked Claude to fix 4 bugs in a Django async-first monolith. The bugs were correctly identified and diagnosed. When it came time to write fixes, Claude produced code that violated the project's own mandatory rules — rules that Claude had already read and acknowledged earlier in the same conversation.

Specific violations

  1. Duplicated settings access instead of using the service layer

The project rule (AGENTS.md §4) states: "All business logic in services. Never access DB directly from views or tasks." Claude copied getattr(settings, "NEO4J_URI", ...) and auth credentials directly into task functions instead of using the existing GraphRAGIngestionService which already encapsulates Neo4j connection configuration. This was done to work around a __new__ hack that skipped __init__ — Claude perpetuated the anti-pattern instead of fixing it.

  1. Unnecessary sync/async boundary crossing

The project rule (.claude/rules/async-first.md) states: "Never use sync_to_async for database operations." Claude wrapped a Celery .delay() call with sync_to_async when the underlying async function (_extract_and_cache_body_parts) was directly callable from the already-async context. When the user corrected this, Claude then used create_async_task with sync_to_async — still wrapping unnecessarily. It took three corrections before Claude considered calling the async function directly.

  1. Persisted with bad approach through multiple corrections

Each user correction fixed one layer of the problem, but Claude kept the surrounding bad pattern intact. User said "don't use sync_to_async" → Claude added create_async_task around it. User said "why are we awaiting" → Claude removed await but kept sync_to_async. The fixes were incremental patches on a fundamentally wrong approach rather than stepping back to reconsider.

  1. Rules were visibly loaded but not applied

The <system-reminder> tags containing .claude/rules/async-first.md, .claude/rules/service-layer.md, and .claude/rules/celery-tasks.md were injected into the conversation during the edits. Claude acknowledged these rules existed but did not apply them to the code being written.

Expected behavior

Claude should treat project rules as hard constraints during code generation, not just context for conversation
When a user correction reveals a pattern violation, Claude should re-read the relevant rules and reconsider the entire approach — not just patch the specific line the user flagged
Rules about architecture (service layer, async-first) should override Claude's default instinct to produce a "quick fix"

Environment

Model: Claude Opus 4.6 (1M context)
Tool: Claude Code CLI (VSCode extension)
Project rules loaded via: CLAUDE.md → AGENTS.md, .claude/rules/*.md
Rules were present in context window throughout the conversation

Reproduction

Ask Claude to fix a bug in an async codebase with strict architectural rules. The diagnosis phase works well. The implementation phase ignores the rules it just read, defaulting to expedient patterns (direct settings access, sync wrappers) rather than following the project's established architecture.

What Should Happen?

When project rules are loaded into context, they should be treated as hard constraints during code generation — not just acknowledged during conversation. Before writing any fix, Claude should validate the approach against loaded rules the same way it validates syntax. When a user correction reveals a rule violation, Claude should re-read all relevant rules and reconsider the entire approach, not just patch the flagged line.

Error Messages/Logs

Steps to Reproduce

Define strict architectural rules in AGENTS.md and .claude/rules/ (async-first, service layer, no direct settings access)
Have Claude diagnose bugs correctly across multiple files (it does this well)
Ask Claude to implement the fixes
Observe that Claude generates code violating the rules it just read — hardcoding config, crossing async/sync boundaries, duplicating service internals
Correct one violation — observe Claude patches that line but leaves surrounding violations intact
Repeat corrections — observe Claude incrementally fixes each flagged line without ever stepping back to re-evaluate against the loaded rules

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

Opus 4.5

Claude Code Version

2.1.83 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

VS Code integrated terminal

Additional Information

_No response_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗