AGENTS.md for a Rails app
September 24, 2026
Keep reading
- Rails vs Rust in 2026, after HEY moved its backend
- Is Rails token efficient code? Counting what an agent has to read
- Testing what an agent wrote
- Reviewing Rails an agent wrote
- Pencils down: what DHH actually said at Rails World 2026
- Cursor rules for a Rails codebase
- Convention over configuration is a context argument now
- Claude Code in a Rails codebase
An agent opening your Rails app for the first time can infer a great deal and guess wrong about the rest.
ApplicationControlleris obvious. Whether your team puts a three-step Stripe flow in a service object, a form object or a fat controller is not, and neither is the command that has to be green before you will look at the diff. AGENTS.md is where that goes.The format is framework-agnostic by design, which is why the query people actually type is rails agents md rather than agents md: the spec tells you the file exists and says nothing about what a Rails codebase owes it.
The format, and who is behind it
AGENTS.md came out of work by the teams behind OpenAI Codex, Amp, Google's Jules, Cursor and Factory, and is now stewarded by the Agentic AI Foundation, a Linux Foundation project. The site at agents.md calls it "a simple, open format for guiding coding agents" and claims adoption by more than 25 agents and IDEs and over 60,000 open-source projects. Take the second number as the project's own, since nobody else counts it.
What the specification requires is the interesting part: nothing. There are no required fields, no front matter and no schema. It is standard Markdown, placed at the repository root, and agents read whatever headings you wrote. That is a real design decision rather than an unfinished one, and it has a consequence people discover late. A format with no schema cannot be validated, so a stale AGENTS.md fails the way a stale comment fails, silently and for months.
Monorepos get nested files, one per subpackage, and the rule the site states is that the closest AGENTS.md to the edited file wins. Every tool below implements that sentence slightly differently.
Three tools, three loading rules
Reading the three implementations side by side is worth twenty minutes, because the differences decide whether your file is read at all.
Codex builds an instruction chain once per run. It reads
AGENTS.override.mdfrom~/.codexif present and otherwise~/.codex/AGENTS.md, then walks from the project root down to your working directory taking at most one file per directory, and concatenates them root first. Files nearer the working directory therefore land later in the prompt and override what came before. The cap isproject_doc_max_bytes, 32 KiB by default, and Codex stops adding files once the combined size reaches it. A root file that fills the budget silences the nested ones underneath it.Claude Code ships AGENTS.md support as a mod whose default mode is
claude-md-or-agents-md: a project with no instruction files of its own gets its AGENTS.md files instead, loaded exactly where and how CLAUDE.md would be. ACLAUDE.md,.claude/CLAUDE.mdorCLAUDE.local.mdin any directory from the root down to the working directory hands the whole project back to the engine and the mod stays out. Two other modes exist,claude-md-and-agents-mdandclaude-md, if you want both files or neither. One detail is easy to miss: nested AGENTS.md files attach on a textReadonly, which is narrower than the engine's own handling of CLAUDE.md.Cursor documents AGENTS.md as a plain-Markdown alternative to the
.cursor/rulesdirectory, without the front matter an.mdcrule carries, and applies a subdirectory's file automatically to work on files in that directory or below.The practical reading: write one root file, assume it is the only one anybody loads, and treat nested files as an optimisation you add when the root file is too big. What to put in .cursor/rules that does not belong in AGENTS.md and Claude Code in a Rails codebase take the two tools one level further down.
What Rails does not imply
Convention over configuration means a large share of a Rails app needs no explanation to anybody, human or otherwise.
app/models/user.rbholdsUser,db/schema.rbis generated, the request goes through a controller. None of that belongs in your file.What belongs is every decision your team made that Rails permits but does not choose. Reading LaunchKit, the Rails 8.1 boilerplate this site sells, the list is short and none of it is guessable:
app/forms/holds form objects, and multi-field input plus validation plus the write live there rather than in the controller.Onboarding::ProfileFormis the pattern to copy.app/services/holds one-job service objects namespaced by domain, so a new Stripe step is aBilling::*class next toBilling::CreateCheckoutSession, not a private controller method.config/locales/en.ymland is rendered witht(...). A literal string in an.erbis a defect, and an agent writing idiomatic Rails will produce one on its first try.Feature.enabled?(:ai), defined inapp/models/feature.rb, and a new toggleable module has to guard its routes, its nav and its views or it half-disappears.AppConfiginconfig/app_config.rb, neverENVscattered in code.Each of those is a rule an agent will violate while writing perfectly reasonable Rails, which is the test for whether a line belongs in the file at all. Conventions are the context argues the general case: the thing you are selling an agent is a codebase it does not have to guess in.
The commands, read off bin/ rather than remembered
The single highest-value section of an AGENTS.md is the one that says how to check the work, and it is the section most often wrong, because people write it from memory.
In LaunchKit,
bundle exec rspecruns the specs andbin/ciruns the gate. They are not the same thing, andconfig/ci.rbsays so in seven lines:An agent told "run the tests" runs RSpec, reports green and has skipped five gates, one of which is
zeitwerk:check. That one matters more than it sounds: a misnamed constant in a new service object loads fine in development and takes the app down on boot in production, and RSpec will not notice.The same applies to setup.
bin/setupinstalls gems, enables the versioned pre-commit hook, bootstraps per-environment credentials and prepares the database, and the hook it installs then runs RuboCop, Zeitwerk, Brakeman, bundle-audit and RSpec on every commit. An agent that does not knowSKIP_HOOKS=1 git commitexists will sit there for minutes wondering why a commit is slow, and an agent that does know will reach for it far too readily, so say which one you meant. What to test when an agent wrote the code covers the part after the command is right.What an agent may not touch
Off-limits directories are a better use of the file than most prose, because the cost of getting them wrong is high and the rule is one line each.
In a Rails app of this shape the list is
db/schema.rb, which is generated by migrations;config/credentials/*.yml.encand the master keys, which are encrypted and are written by the/admin/setupwizard or bybin/rails credentials:edit;Gemfile.lock, which is edited bybundle; and anything understorage/,tmp/orvendor/.Add the ones specific to your codebase. LaunchKit has two. The
launchkit:*generator toolkit stays branded afterbin/newrenames the app, so it is not a leftover to tidy up. The documentation engine underengines/boilerplate_documentation/needs a Markdown file and a matching entry inapp/models/boilerplate_documentation/page.rb, and editing one without the other produces a page that exists and is unreachable.The file this repository would want
The whole file, written for LaunchKit and short enough that a reader reaches the end of it, looks like this. Order matters more than completeness: commands first, because that is the part an agent needs before it can check its own work, then layout, then the rules that Rails permits and this codebase does not, then the list of files nobody edits by hand. Anything a
grepwould have answered in ten seconds is left out on purpose.Roughly 60 lines. Every line is either a command, a path or a rule that Rails does not imply, and the ratio is the thing to protect as the file grows.
Where it goes wrong: a second source of truth
The failure this file is most prone to is not being wrong, it is disagreeing with the README.
LaunchKit's AGENTS.md as it stands today says local development is dockerized and that
docker compose upbrings up the whole stack. The README's quick start saysgit init,bin/new,bin/setup, against a Postgres on the host. Both work. Neither document mentions the other, andbin/ciandbin/doctorappear in the README and in neither line of the AGENTS.md.What an agent does with that is pick one, usually the one it read most recently, and never say so. The diff looks identical either way. You find out when a spec that needed the dockerized Postgres fails on someone else's machine, or when a commit lands having never been through the Zeitwerk check.
The fix is not to write more. Name one canonical setup in AGENTS.md and let the README be the prose version of the same sequence, or write one sentence saying which document wins. This is a case where the second-best answer is fine and the absence of an answer is not.
What restating the Rails guides costs
Position first: an AGENTS.md longer than about 150 lines is usually a net loss, and the extra lines are almost always a paraphrase of the Rails guides.
The cost is concrete. Codex re-reads the chain once per run and stops adding files at 32 KiB, so a root file explaining MVC is literally crowding out the nested file that would have said something specific about
app/services/. Claude Code loads it where CLAUDE.md would load, which means the start of every session. Nobody pays for it once.The subtler cost is that a file with ten obvious lines and one important one reads as documentation, and documentation gets skimmed. A file made entirely of things the model could not have known reads as configuration.
What would change my mind: tools that load instruction files lazily rather than up front. Claude Code's nested handling already points that way, attaching a subdirectory's AGENTS.md on a text
Readrather than at session start. If that becomes the norm across tools, a long file costs only when it is relevant and the length argument weakens considerably. Today it does not hold. Writing Rails an agent can read cheaply makes the same argument about the code rather than the instructions.What this page leaves alone
Keeping CLAUDE.md and AGENTS.md in sync, which has an obvious symlink answer and a set of non-obvious problems with it, is not covered here and deserves its own page.
Nor is the question of whether the file worked. There is no metric offered above, because the only honest one is reading the diffs, and Reviewing Rails an agent wrote is where that goes. Everything here is checkable against a repository or against a tool's own documentation, and it stops there.