CLAUDE.md, AGENTS.md and Cursor rules: why none of them enforce anything
TL;DR
- A rules file is text placed in a context window.
CLAUDE.md,AGENTS.mdand Cursor rules all describe themselves that way, on their own pages, in their own words.- The delivery is documented and it is not what people assume:
CLAUDE.mdarrives as a user message after the system prompt, wrapped in a note saying the context may or may not be relevant.- Something does enforce, and it is not a file. A deny rule removes the tool from the model's context, so there is nothing to refuse.
- Every quotation is from a vendor's own page or a person who published what they found. No performance numbers, ours or anyone's.
Storage is not enforcement. A rule held in CLAUDE.md, in AGENTS.md, or in a Cursor rules file is text delivered into a context window, and text does not enforce.
If you have written a rule down, watched your agent read it back to you, and then watched it do the thing anyway, nothing was ever stopping it. That is not a bug report. It is how the mechanism works, and it is documented.
Before anything else: we build Mnemoverse, a memory layer for AI agents that connects over MCP. So this is written by a vendor in the category it is about. Nothing of ours appears anywhere in it. Every quotation below is from public documentation, a public specification, or a person who published what they found, all linked, so you can check any line of it without taking our word for anything. The conclusion partly argues against buying anything from us.
There are no performance numbers in this article. Ours are frozen pending our own measurement harness, and we are not borrowing anyone else's to fill the gap.
The same walk-through exists on video, with every mechanism animated rather than described: eleven minutes, chaptered, for anyone who would rather watch it move. The text below stands on its own and goes wider than the film does, because the video quotes Anthropic's pages only and this page quotes all three vendors.
The vendor says it first
From the memory documentation:
Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.
That is the whole answer, stated by the people who built it, on the page about the feature. What follows is the mechanism underneath it, because knowing that memory is not enforcement is less useful than knowing why, and knowing why tells you what to reach for instead.
The thing people call memory, the thing people call rules, and the thing people call project instructions are the same thing mechanically. They are text that arrives in a context window.
Three rules files, three vendors, the same sentence
This is not one product's quirk, and the fastest way to show it is to read what each one says about itself.
CLAUDE.md. From the memory documentation, already quoted above:
Claude treats them as context, not enforced configuration.
AGENTS.md, the open format used by over 60k open-source projects:
A simple, open format for guiding coding agents
Think of AGENTS.md as a README for agents: a dedicated, predictable place to provide the context and instructions to help AI coding agents work on your project.
Guiding. Context and instructions. A README is a document you hope someone reads.
Cursor rules. From Cursor's own documentation, and this is the most mechanical of the three:
Large language models don't retain memory between completions. Rules provide persistent, reusable context at the prompt level. When applied, rule contents are included at the start of the model context. This gives the AI consistent guidance for generating code, interpreting edits, or helping with workflows.
Included at the start of the model context. Guidance. Same mechanism, same word, different company. The same page also tells you the two formats are interchangeable:
If you prefer plain markdown, use AGENTS.md instead.
Three vendors, three file names, one description of what happens: the file's contents are placed in the context window, and the model is guided. None of the three claims the file binds anything, and none of them is being coy about it. The claim that a rules file enforces a rule is not something any of them makes. It is something we assume because the file is called rules.
Four people, in their own words
The documentation says what the mechanism is. These are people meeting it.
claude-code#87825, open at the time of writing. The title:
Persistent memory rules are decorative — Claude ignores them before destructive actions, repeatedly, across sessions
And from the body:
The rule was in memory. Claude had read it. Claude pushed directly to main three times.
claude-code#75334, a different person on a different day, also open:
Memories are written but not acted on
Literally anybody with a CLAUDE.md has seen the behavior over and over and over.
And on the OpenAI forum, about a different vendor's tool entirely:
even after I have explicitly emphasized the same constraints more than 20 times. It fails to respect project-specific rules, loses track of context, and makes decisions that actively put the structure of my project at risk.
The instruction was stored. The instruction was read. The instruction was not binding, because storing something and binding something are different operations and only one of them was performed.
How is a rule actually delivered to the model?
Same documentation page, and this is the mechanical answer:
CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. Claude reads it and tries to follow it, but there's no guarantee of strict compliance
Read that again for the part that gets skipped. A user message. Not a system instruction. Not a configuration value. A message, in the conversation, arriving the same way the rest of the conversation arrives and competing on the same terms as everything else in the window.
Which means the strength of your rule is the strength of a sentence. Not a gate, not a check. A sentence, sitting next to other sentences, some of which are your actual task and some of which are a file somebody else committed.
What does the wrapper around your rules say?
The audience found this part before any vendor explained it. Someone put a proxy between the client and the model, read what actually goes across, and published what they saw. Your instructions arrive inside a wrapper, and the wrapper ends with this:
IMPORTANT: this context may or may not be relevant to your tasks
That is the last thing the model reads before your rules. It is not a mistake and it is not hidden. It is one sentence doing an obvious job: the client cannot know which of your standing instructions matter for the request you just typed, so it says so.
But sit with what it means for the sentence you wrote. You wrote never push directly to main. It arrives as a user message, after a note explaining that it may or may not be relevant.
Why does a registered memory tool never get called?
The same shape appears one layer down, with tools. You connect a memory server, the client says connected, the tools are listed, and the model never calls them.
So look at what the protocol says a tool description is for. This is interface Tool in the MCP schema, which is the protocol's source of truth, at revision 2026-07-28. The doc comment on description:
A human-readable description of the tool.
This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a "hint" to the model.
Their scare quotes, not ours. A hint.
And look at the field declaration itself:
description?: string;The question mark means optional. A tool can be registered with nothing but a name and an input schema, and the specification is fine with that. inputSchema is the only required member of the interface. Not the description, not the annotations, not the output schema.
One thing this section is not about. Search this question and you will find bug reports where tools never reached the model at all: a server connects, the list comes back, nothing surfaces. Those are real, they are closed, and they are a different failure. This is about a tool that arrived correctly and was not chosen.
What does a model see when it decides to call a memory tool?
Three things. A name. A schema describing the arguments. And a hint, written by whoever wrote the server, which may not exist.
That is the whole basis for the decision. There is no relevance score, no priority field, no required flag, no this-one-matters marker. The author of the server writes a sentence, the model reads it alongside every other tool's sentence, and decides.
There is one case where the tool genuinely is not there, and it is worth separating because it looks identical from where you sit. In VS Code, MCP tools are active in Agent mode only. In Ask mode the panel still shows them and the schemas are never put into the context. So the model is not declining. It cannot see them.
Absence and decision look the same from your chair and they have completely different fixes. Check which one you have before you change anything.
What actually enforces a rule?
Something does, and the same documentation says which. From the memory page:
Settings rules are enforced by the client regardless of what Claude decides to do. CLAUDE.md instructions shape Claude's behavior but are not a hard enforcement layer.
And here is how that works, which is the most useful sentence in this whole subject. From the permissions page:
As a deny rule, both forms remove the tool from Claude's context.
Removed from the context. The model is not told no. The model is not shown the tool at all. You cannot call what you cannot see.
Deny also wins over allow, unconditionally, same page:
A broad deny rule like
Bash(aws *)blocks every matching call, including calls that also match a narrower allow rule likeBash(aws s3 ls), so a deny rule can't carry allowlist exceptions.
So there are two different operations and we have been using one word for both:
| what it does | where it runs | |
|---|---|---|
| a memory or a rules file | adds text to the window asking for something | inside the model's decision |
| a deny rule or a hook | subtracts a capability | outside it, regardless of the decision |
One is a request. The other is arithmetic.
When is a rules file better than a memory layer?
This is the part where we argue against our own product, and it is not decorative.
If what you need is for something to not happen, no memory layer will do it. Not ours, not anyone's. Storage is not enforcement no matter whose storage it is, and a vendor telling you otherwise is describing a feature that does not exist. Use a hook. Use a deny rule. Those run outside the model and they do not care what it decides.
If what you need is the same instructions in front of the model every session, a file in your repository does that. It is free, you can read it, your team can review it in a pull request, and it is already installed. For a lot of people that is the entire answer and there is nothing to buy.
A memory layer is for a narrower thing: facts that accumulate, that you did not write by hand, that need to be there in a session you have not started yet, and in a tool you were not using at the time. That is a real problem and it is not this one.
A two minute test: is your agent reading, or obeying?
Reading and obeying are separable, they fail differently, and they have different fixes. So test them separately.
First, ask it to state your rule back to you. If it cannot, the rule is not arriving, and that is a delivery problem: wrong file, wrong scope, wrong directory, excluded by a setting. Fix it there and stop, because nothing downstream matters until this passes.
Second, and only if the first one passed, put it in the situation the rule governs and watch. If it states the rule correctly and then does the thing anyway, delivery works and nothing is enforcing.
That second outcome is not a malfunction. There is no obedience layer to malfunction. There is a context window with your sentence in it, competing with everything else in there, and a model deciding.
If the decision has to go your way every time, then the decision cannot be the mechanism, and you need the layer that runs outside it.
— Olga Timoshina · Last updated 2026-08-25
