Project rules are durable instructions that live in the repository and apply automatically. They are stored in a dedicated directory and require their own format with a header: an ordinary markdown file there is simply ignored because it has no fields by which a rule is attached. That detail catches almost everyone at first setup - the file is in place, it looks right, and it does not apply. The failure is silent: no message appears, the rule simply takes no part in the work, and the only way to notice is by behavior.
There are four ways of applying a rule, and the choice among them decides everything. A rule can apply always; it can be picked up by the agent from its description when the agent finds it relevant; it can attach to file paths; it can be invoked only manually by name. The difference is not cosmetic: an always-on rule pays with context in every task, while a path rule pays only where you are actually working with those files. In a large repository that difference is measured not in percentages but in whether room is left for the task's own code.
It helps to see a rule in full once. Below is a header with a description and a path pattern plus a short body: validate input at the service boundary, return structured errors, read the sample before creating a new service. Note the length: a rule is a contract rather than documentation. The shorter and more specific it is, the higher the chance the model will follow it. Note the last item too: a reference to an exemplary file works better than a retelling of what is written in it, because the sample does not go stale together with the rule's text.
The combination of header fields defines the behavior and is worth keeping in mind. The always-apply flag turns the rule on unconditionally and makes the description and patterns meaningless. Without it but with patterns, the rule attaches to matching files. Without it but with a description, the agent decides. If there is neither a description nor patterns, the rule is available only by an explicit call. That is exactly four combinations, and each is a deliberate choice of cost and coverage: from a permanent fee for a guarantee to no fee and no guarantee at all.
| Header fields | Behavior |
|---|---|
| alwaysApply: true |
| Always; the description and path patterns are ignored |
| alwaysApply: false with path patterns | Attaches to matching files |
|---|
| alwaysApply: false with a description | The agent picks it by relevance |
|---|
| Neither a description nor patterns | Only an explicit call by name |
|---|
Next to that there is an alternative in the form of a plain markdown contract file. It is simpler: it requires no special format and reads to a human like ordinary documentation. Nesting is supported - an instruction closer to the working file gets a narrower scope. That is a convenient model for a monorepo: shared invariants at the top, package specifics next to its code. The command line additionally reads the root conventions file of another agent tool, so one repository can serve several tools without duplicating the meaning.
Team rules stand apart because they are managed centrally and take priority over project and user ones. An enforced rule cannot be switched off locally, and that is its point: the organization fixes a mandatory minimum. The flip side is that such rules must be written especially carefully: what cannot be switched off will get in the way in every project where it does not belong. A good team rule describes an invariant equally true for all repositories rather than one team's habit.
A rule that does not fire is diagnosed in order rather than by trial. First the format: is the file in the right directory with the right extension, does it have a header. Then the mode: a pattern rule will not switch on if the open file does not match the pattern, and a description rule will not switch on if the description names a capability rather than an occasion. The wording call conventions for backend services gives the agent an occasion; the wording useful advice does not. And only after that is it worth suspecting the content: an over-long rule gets lost among the rest of the context even once it has attached.
The most important limitation of this part of the configuration: rules steer but do not block. The phrase never read secrets in a rule replaces neither the ignore file, nor file-system restrictions, nor a hook. Besides, their scope differs: user rules apply to the conversation with the agent but not to a pointed edit, and they do not govern editor suggestions at all. Expecting a guarantee from text is the most common mistake here, and it is the more dangerous because a rule looks obeyed right up to the case where breaking it costs something.
Hence a practical manner of writing rules. One rule is one requirement, phrased so that the code shows whether it was met. Validate input at the service boundary is checkable; write quality code is not. A rule lives next to the code, changes together with it and goes through review like code: if a requirement is obsolete, it is deleted rather than kept just in case. A set of a dozen short checkable rules works better than one long document about how things are done here.
The typical failures are predictable. Putting plain markdown into the rules directory and not understanding why it does not apply. Making all rules always-on and paying for them with context in every task. Writing a description about a capability instead of an occasion and getting a rule the agent never picks. Writing a security requirement into a rule instead of a deterministic mechanism. And expecting a user rule to affect editor suggestions.
---
description: RPC conventions for backend services
globs: services/**/*.ts
alwaysApply: false
---
- Validate inputs at the service boundary.
- Return structured errors with a code and a message.
- Read @services/example-service.ts before creating a new service.