Dev Tool Experiences
All articles

· 7 min read

Write Project Rules Your Coding Agent Can Actually Follow

By D. Pham

  • tools

Yes: put a short, testable AGENTS.md at the repository root, then put the exceptions beside the code they describe. The rules agents follow best are not style manifestos; they are a map of where to work, what not to touch, and the exact command that proves the change is done.

If your agent keeps adding a new state library, runs the full integration suite for a CSS edit, or “cleans up” generated files, that is usually an instructions-design problem before it is a model problem. You gave it a preference. It needs an operational constraint.

Start with a portable root file

Use AGENTS.md for the stuff a competent new engineer would need in their first 10 minutes: package manager, repository layout, the narrowest useful verification command, generated-file boundaries, and the one or two architectural constraints that actually cause expensive review comments. It is increasingly the common denominator: Codex reads AGENTS.md while walking from the Git root to the working directory; Cursor CLI reads root AGENTS.md and CLAUDE.md; GitHub Copilot CLI discovers AGENTS.md, CLAUDE.md, and GEMINI.md alongside its own instruction files.

Don’t copy your CONTRIBUTING guide wholesale. A 900-line instruction file is not a more serious version of a 90-line one. It competes with the task, the diff, the errors, and the source files for attention. OpenAI’s own Codex team describes its short AGENTS.md as a map—roughly 100 lines—with deeper documentation elsewhere. That is a useful ceiling, not an invitation to fill 100 lines.

# AGENTS.md

## Working agreement
- Use pnpm. Do not create package-lock.json or yarn.lock.
- Keep changes inside the affected package unless the task explicitly needs a shared API change.
- Do not edit `packages/api/src/generated/**`; update the schema or generator input instead.

## Before editing
- For web changes, inspect `apps/web/src/components` for an existing component before adding one.
- For API changes, read `docs/api-versioning.md` before changing a public route or response shape.

## Verification
- Changed files in `apps/web/**`: `pnpm --filter web lint && pnpm --filter web test`
- Changed files in `packages/api/**`: `pnpm --filter api test:unit`
- Run `pnpm format:check` before finishing.

## Done means
- Add or update a focused test when behavior changes.
- Report commands run and any checks deliberately not run.

Every line above gives the agent a decision it can make. “Use pnpm” prevents lockfile churn. “Do not edit generated code” gives it a boundary and an alternative. The path-to-command mapping stops it from burning 12 minutes on a monorepo-wide test run when a package test is enough. “Report checks not run” makes an incomplete run visible instead of quietly optimistic.

Replace preferences with observable rules

The weak version says, “Write clean, maintainable code and follow our conventions.” The agent will agree with this sentence and then invent its own definition of clean. The useful version names an existing artifact, a forbidden action, or a command with a pass/fail result.

  • Instead of “reuse components,” write “Before adding a component under apps/web/src/components, search for an existing primitive in ui/; compose it rather than duplicating its focus, loading, or error states.”
  • Instead of “don’t break compatibility,” write “Do not rename or remove fields in packages/contracts/src/public.ts without updating docs/api-versioning.md and the compatibility tests.”
  • Instead of “test your work,” write “For a parser change, run pnpm --filter parser test -- --runInBand; add a regression fixture under fixtures/ for every fixed input.”
  • Instead of “be careful with migrations,” write “Never modify an applied migration. Create a new timestamped migration with pnpm db:migration:create <name> and run pnpm db:migration:check.”

The command is important because it is both instruction and feedback loop. Agents are decent at acting on an error emitted by a command they just ran. They are much worse at intuiting that an unspoken convention exists somewhere in a wiki, especially when the happy-path implementation compiles.

Scope the weird rules instead of making everyone carry them

A root file should not explain your React rendering policy, database migration process, protobuf compatibility rules, and Terraform account layout on every task. Put the root rule in charge of navigation: “For infrastructure work, read infra/AGENTS.md first.” Then put the precise infrastructure rules there.

This is not merely tidy documentation. Tool support is now explicitly path-aware. Cursor Project Rules can be attached by glob and nested under subdirectories. GitHub Copilot supports path-specific *.instructions.md files using an applyTo glob. AGENTS.md itself is useful in monorepos because tools that support hierarchical discovery can pick up instructions nearest the files being changed. Put the deployment freeze rule under infra/, not in a root file that a documentation edit must carry.

Do not create a nested rule for every folder. Make one when the folder has a different toolchain, a distinct definition of done, generated outputs, security constraints, or a convention that routinely produces bad diffs. If the rule would only matter once a quarter, keep it in the relevant runbook and point to it when the task requires it.

Use tool-specific files as adapters, not a second constitution

AGENTS.md is a good baseline, but it does not mean every tool reads it in every mode. Keep one shared source of truth and add vendor-specific instructions only for capabilities you actually use. For example, GitHub Copilot repository instructions belong in .github/copilot-instructions.md, while path-specific Copilot files go under .github/instructions/ and use applyTo. Cursor’s richer rule types—always, auto-attached, agent-requested, and manual—belong in .cursor/rules when you need them.

Avoid duplicating the same prose in all three places. Either reference the shared file where the tool supports references, or make the vendor file a tiny adapter: “Follow AGENTS.md; for **/*.sql, also follow the database review checklist below.” GitHub warns that its CLI combines applicable instruction files without defining a general precedence order, so overlapping copies are how you create a rule conflict nobody can debug.

Test the rules like you test the code

Open a fresh agent session and give it three boring prompts: “Add a nullable field to the public API,” “fix this web test,” and “create a migration.” Before it writes code, check whether it identifies the right package, reads the linked documentation, avoids generated files, and selects the intended command. In Copilot CLI, /instructions shows the files discovered for the current session and lets you disable one; use it when a rule seems ignored. In Cursor, check the rule type and glob before blaming the model.

Then make a deliberately conflicting request: “Update the generated client directly so this is faster.” A good rule does not make the agent incapable of complying with an explicit task, but it should force a useful pause: explain the boundary, propose updating the source schema, and ask before bypassing it. If it silently edits generated output anyway, your instruction was probably a suggestion disguised as a rule.

Finally, prune after real failures. Every time you type the same corrective sentence twice—“use the package test, not the root test,” “don’t touch the snapshot,” “that endpoint is versioned”—either encode it as an exact rule or decide it is not important enough to keep enforcing. Project rules are not the culture document. They are the small set of constraints worth paying context for on every agent run.

Sources & citations

  1. [1]OpenAI — Harness engineering: leveraging Codex in an agent-first world
  2. [2]OpenAI — Unrolling the Codex agent loop
  3. [3]AGENTS.md — open format and examples
  4. [4]Cursor documentation — Rules
  5. [5]Cursor documentation — Using Agent in CLI
  6. [6]GitHub Docs — Adding custom instructions for GitHub Copilot CLI
  7. [7]GitHub Docs — Comparing GitHub Copilot CLI customization features