# Why your AI agent ignores the rules you wrote

> Source: <https://dev.to/arseni_1c552e9dc5349dc6b4/why-your-ai-agent-ignores-the-rules-you-wrote-9lf>
> Published: 2026-06-14 07:58:51+00:00

You wrote the rule. The agent read it. It broke the rule anyway.

Here's one from a React Native project. My config said:

Never use

`pnpm add`

for native packages.

Clear enough. The agent ran `pnpm add`

on a native package in the next session regardless. The build broke without an error message: pnpm resolved `react-native@0.79`

instead of the `0.76`

the project was pinned to, the JS kept compiling, and the native module failed at runtime with a message that pointed nowhere useful. That cost me an hour.

The agent wasn't being disobedient. The rule was bad. It said what to avoid and nothing else, so the first time a situation didn't match the picture in my head, the agent treated it as a soft preference and grabbed the obvious tool.

This is probably the most common reason agent configs don't do much, and it's fixable.

When you write "never use X," the agent has to guess where the rule starts and stops. Does it apply here? This case looks a little different, maybe it's fine. An LLM is built to find plausible readings of things, so it finds the one where your rule doesn't quite reach.

Add the reason and the rule stops being a fence to find gaps in. Now it's something the agent can reason from.

``` php
<!-- Before -->
- Never use `pnpm add` for native packages.

<!-- After -->
- Never use `pnpm add` for native packages.
  Why: pnpm's hoisting pulls react-native@0.79 instead of the
  pinned 0.76, and the native build breaks with no error. The JS
  compiles fine and the app crashes at runtime with something that
  looks unrelated. Use `npm install --save-exact` in the package
  workspace instead.
```

The longer version earns its length. The "why" is where the real edge of the rule lives. An agent that knows the failure mode is silent version drift will also catch the cases you never wrote down: a different package manager that hoists the same way, a transitive dependency bumping the version, a teammate's lockfile doing it for you. You can't list every variation. You can explain the mechanism once and the agent fills in the rest.

So write fewer prohibitions and more mechanisms.

**Keep one source of truth.** If a fact lives in two files, one of them is probably already wrong and you don't know which. Your schema is in the migrations. Your types are in one place. Don't restate them in `CLAUDE.md`

, because the copy goes stale and eventually the agent reads the stale one and builds on it with full confidence. Point it at the real file instead: "types are in `src/types/`

, read them" works better than a pasted snippet that rots in a week.

**Use a few specialized agents instead of one that knows everything.** A pipeline engineer and a mobile engineer have different checklists and different things that bite them. Put both in one prompt and you get something average at both that keeps forgetting whichever half isn't relevant to the current file. Split by domain and load the right one for the right files. The mobile agent doesn't need your migration rules taking up space while it edits a component.

**Make "done" a command, not a feeling.** "Looks good" isn't a finish line. The agent calls it done the moment the code looks reasonable, because reasonable-looking is the thing it's actually good at producing. Give it something to check instead:

``` php
<!-- Vague -->
- Verify the feature works before finishing.

<!-- Verifiable -->
- Done when: `npm run typecheck` exits 0, `npm test -- auth.test.ts`
  passes, and `curl localhost:3000/health` returns {"status":"ok"}.
```

Now done is something the agent can confirm rather than something it can convince itself of.

Most of them look like one of these:

```
## Our stack
We use React Native, Supabase, TypeScript, Effector.

## Rules
- Always use TypeScript.
- Never use var.
- Prefer functional components.
```

One is a list of technologies. The other is a list of rules with no reasons attached. Between them they tell the agent what you use and what to steer clear of, and nothing about how to approach a task or why any of it matters. So the agent learns your stack and keeps making the same mistake every session. It "always uses TypeScript" and types everything as `any`

, because nothing told it what TypeScript was for. It does what the rule literally says and still misses what the rule was for.

Fixing it isn't complicated. Fewer rules, each with the reason attached. One place for each fact instead of three copies. The right specialist for the file in front of it. And a finish line you can actually run. It takes more effort the first time you write it. It takes a lot less than fixing the same mistake for the fortieth session in a row.

I put all of this into a template. The source files aren't tied to one tool and convert into Claude Code and Antigravity formats, and there's a short checklist for auditing a config you already have before you move it over: [github.com/Guck111/agent-config-template](https://github.com/Guck111/agent-config-template). It's MIT, so use whatever's useful and ignore the rest.

The template is the smaller part though. The thing worth doing costs nothing: open your agent config and find a rule with "never" or "always" in it. If it doesn't say why, the agent is already working out when it doesn't apply.
