Rules
rules/ holds the conventions an agent follows without being asked, such as commit format or test style. Sync writes each rule in every tool's own format: Cursor .mdc files, Claude Code rules, AGENTS.md sections. Write short instructions. Put multi-step procedures in a skill.
Write one
agnostic-ai new rule conventional-commits creates rules/conventional-commits.md with globs: "**/*" and alwaysApply: true.
---
name: conventional-commits
description: Always use Conventional Commits format.
globs: "**/*"
alwaysApply: true
---
Use `feat:`, `fix:`, `docs:`, etc. Subject under 72 chars.
A rule that loads when the agent works on matching files:
---
name: react-components
description: Conventions for React components.
globs: "src/**/*.{ts,tsx}"
---
Write function components. Keep one exported component per file.
A rule for one directory. Create it with agnostic-ai new rule payments-context --scope services/payments, or place the file at rules/services/payments/payments-context.md:
---
name: payments-context
scope: services/payments
---
Use integer minor units for monetary values.
Claude Code gets a rule that applies only there. Codex gets services/payments/AGENTS.md. Cursor gets its own .mdc rule, unless a tool like Codex needs the shared AGENTS.md, which Cursor then reads too. Gemini gets services/payments/GEMINI.md. Directory-specific instructions lists every tool and the selector limits.
Headings in merged files
When several rules share a file, such as Codex's AGENTS.md or Gemini's GEMINI.md, each rule gets a ### <name> section, and sync moves the body's headings down together so its top heading is at least ####. A body with ### Doc versioning and #### Details becomes #### Doc versioning and ##### Details.
- The
outputs.claude.rules-filelayout writes## <name>sections, so there the top body heading is at least###. - Headings already deep enough keep their levels. No heading goes past
######, so when a body's deepest heading is more than two levels below its top one (three in the Claude layout), the deepest levels merge at######, and import cannot separate them again. - The section's source comment records the shift, as in
<!-- source: .agnostic-ai/rules/content.md headings: +1 -->, and import moves the headings back.
Edge cases for heading shifts
- Fenced code (including fences inside lists) and raw HTML blocks keep their headings as written.
- Link reference definitions stay separate from underlined (Setext) headings.
- List items followed by a thematic break remain lists.
- Raw HTML blocks follow CommonMark. A line such as
<b>Note:</b> read firstis paragraph text, so a---under it forms a heading that nests too. - A rule file written on its own, or a nested file with one rule and no section wrapper, keeps its heading levels.
- An underlined (Setext) heading comes back from import as a
#heading. Hard line breaks in its text become<br>tags. - Headings and source-comment examples inside fenced code and raw HTML stay in their rule body. They do not start another rule.
- When a rule leaves a code or HTML block open, its source comment also records
body-lines: <count>, which sync updates and import uses to find the next section.
Fields
| Field | Required | Default | Description |
|---|---|---|---|
name | no | filename | Rule identifier. |
description | no | empty | Short summary. |
scope | no | project-wide | A project-relative directory and everything under it. It wins over the rule's folder. A folder that names a project directory scopes a rule without scope; any other folder only groups rules. A scope inside node_modules is refused. See scoped context. |
globs | no | depends on the tool; new rule seeds **/* | Project-relative patterns, as a comma-separated string ("*.go,*.mod") or a list. A comma inside a brace set does not separate patterns, so "src/**/*.{ts,tsx}" is one pattern. With scope, applies to the whole scope directory and every matching file. new rule --scope omits it. |
paths | no | unset | Another name for globs, the form Claude Code writes. Every tool reads it as globs. Set only one of them; validate rejects a rule whose paths and globs name different patterns. See selector limits. |
alwaysApply | no | false with globs, else depends on the tool; new rule seeds true | Asks the tool to always load the rule. Unset on a rule with globs, it is false in every tool that has an activation field, so the rule loads only on matching files; a catch-all such as **/* keeps it always-on. With scope, the rule stays within the scope plus patterns. new rule --scope omits it. |
A rule with neither globs nor alwaysApply loads differently per tool; each target page says when. Set alwaysApply: true when a rule must load everywhere.