Rails has twenty years of accumulated idioms in training data, and a large share of them were removed years ago, so an agent's confident answer is often a Rails 4 answer. The frontend story in particular forked several times, from Sprockets to Webpacker to importmaps and Hotwire, and picking the wrong one produces code that never loads. An agent also needs to understand that the schema file is generated output and that ActiveRecord callbacks are the default place agents hide side effects.
Scoped read and write access to the application directory.
Rails convention means the right file location is usually inferable, but only if the agent can actually see app/ and config/ rather than assume them.
History, diffs, and blame across the repository.
Gemfile.lock history is the reliable way to establish which Rails and Ruby versions the codebase is actually on.
Schema inspection and read queries.
It lets the agent verify what the database really contains rather than trusting a schema.rb that may have been hand-edited.
Drives a real browser through the running app.
Turbo Frames and Turbo Streams behave differently from full page loads, and only a browser session shows which one actually fired.
Reads issues and stack traces from Sentry.
Background job failures in ActiveJob are invisible locally and are usually the first place a callback side effect blows up.
These are the failures that repeat across sessions, so each one belongs in .mcp.json.
When a nested attribute fails to save, the shortest fix an agent finds is params.require(:user).permit! or passing params directly to update, which re-opens mass assignment across every column including role and admin flags. It always makes the immediate error disappear. Add to your rules file: 'Strong parameter methods list permitted keys explicitly. permit! is never acceptable, and nested attributes are permitted by naming their keys.'
Agents write where("name LIKE '%#{params[:q]}%'") because string interpolation is the natural Ruby reflex and the result reads fine. That is a SQL injection hole, and it appears most often in search and sort code where the input is user supplied by definition. Write: 'ActiveRecord conditions always use hash conditions or positional placeholders. Never interpolate a variable into a SQL string, including ORDER BY clauses built from params.'
A controller returns Article.all and the view renders article.author.name plus article.comments.size, quietly issuing several queries per article. Rails makes this so ergonomic that it survives code review. Add: 'Controllers pass fully preloaded relations to views using includes or preload. Add the Bullet gem in development and treat its warnings as failures rather than logging noise.'
Asked to notify a user after a record is created, agents add an after_create that sends mail, charges a card, or posts to a webhook. It then fires from seeds, from every factory in the test suite, and from console fixes, and it cannot be skipped without skipping validations too. Write: 'Callbacks may set derived attributes on the same record only. Notifications, payments, and outbound requests are dispatched explicitly from a service object or ActiveJob in the controller or job that owns the flow.'
When schema.rb does not match what an agent expects, it edits the file directly instead of writing a migration, which produces a schema that no migration can reproduce and a version number that lies. The app boots, so nothing complains until the next deploy. Add: 'db/schema.rb is generated. All schema changes go through rails generate migration, and schema.rb is only ever updated as a side effect of running migrations.'
before_filter, attr_accessible, render :text, and Webpacker configuration all still appear in agent output, and each was removed or replaced several major versions ago. The failure mode ranges from a deprecation to a NoMethodError at boot. State your versions: 'Rails 7 or later on Ruby 3.x, using importmaps and Hotwire. Use before_action, strong parameters, and render plain. Never add Webpacker, attr_accessible, or before_filter.'