skip to content

In RuboCop, what does rubocop --auto-gen-config write into .rubocop_todo.yml, and how do you keep that todo file shrinking instead of rotting?

level: seniorimportance: should knowfreq 50%

answer

  1. inherit_from: .rubocop_todo.yml added
  2. Exclude lists up to --exclude-limit 15
  3. then Enabled: false for the cop
  4. Metrics cops get a raised Max
  5. --report-unused-todo-entries fails on stale entries

basics

~20 s

--auto-gen-config writes .rubocop_todo.yml, which excludes each offending file per cop (up to 15, then disables the cop) or raises Metrics Max values, and links it via inherit_from. Delete entries as you fix code; --report-unused-todo-entries fails on stale ones.

solid answer

~50 s

`rubocop --auto-gen-config` runs every cop, then writes `.rubocop_todo.yml` and adds `inherit_from: .rubocop_todo.yml` to `.rubocop.yml`, so the next run passes. For each cop with offenses it writes one of three things: an `Exclude` list of the offending files; `Enabled: false` once more than `--exclude-limit` files offend (default 15); or, for `Metrics` cops, a `Max` just high enough. If every file uses one style, it writes that `EnforcedStyle` instead. Each entry carries `# Offense count:` and whether the cop supports safe or unsafe autocorrection. To shrink it, move real style decisions into `.rubocop.yml`, fix one entry at a time and delete it, and run `rubocop --report-unused-todo-entries` (1.90+) in CI: it fails when an entry no longer matches any offense. `--regenerate-todo` rebuilds the file with the same options, but it also absorbs new offenses, so it stays a deliberate local step.

code

bash · 3 lines
bash
bundle exec rubocop --auto-gen-config --no-exclude-limit --auto-gen-only-exclude --no-auto-gen-timestamp
bundle exec rubocop --report-unused-todo-entries   # in CI: fail on stale entries
bundle exec rubocop --regenerate-todo              # locally, reviewed

go deeper

for a junior

Recall that --auto-gen-config writes .rubocop_todo.yml and links it through inherit_from so a legacy codebase passes today.

for a middle

Explain the three entry shapes, Exclude, Enabled: false past the exclude limit, and a raised Max for Metrics, and the flags that change each.

for a senior

Generate with --no-exclude-limit and --auto-gen-only-exclude, run --report-unused-todo-entries in CI, and keep --regenerate-todo a reviewed local step.

for a principal

Treat the todo file as tracked debt with an owner and a trend, not as configuration, and decide which cops must never be switched off wholesale.

## Why the todo file exists Turning RuboCop on in a large existing codebase produces thousands of offenses. The team wants the gate to start protecting **new** code today, and to pay down the **old** offenses gradually. `--auto-gen-config` records the current offenses as configuration so that the next run is green, and leaves a list of work behind. ## What `--auto-gen-config` writes Running `rubocop --auto-gen-config`: 1. inspects the project with every enabled cop; 2. writes **`.rubocop_todo.yml`**, starting with a header naming the exact command, a timestamp and the RuboCop version; 3. adds **`inherit_from: .rubocop_todo.yml`** to `.rubocop.yml`, creating it if needed. For each cop that found offenses, the todo file gets one entry, preceded by comments such as `# Offense count: 42` and `# This cop supports safe autocorrection (--autocorrect).` The entry takes one of these shapes: | Situation | What is written | Option that changes it | |---|---|---| | offenses in up to 15 files | `Exclude:` with those files | `--exclude-limit COUNT` | | offenses in more files than the limit | `Enabled: false` | `--no-exclude-limit` keeps listing files | | a `Metrics` cop | `Max:` raised just enough | `--auto-gen-only-exclude` excludes files instead | | one consistent style everywhere | `EnforcedStyle:` set to that style | `--no-auto-gen-enforced-style` | `--no-offense-counts` and `--no-auto-gen-timestamp` drop the comments that change on every regeneration and make diffs noisy. ## The trade-off in each shape - **`Exclude`** keeps the cop active for every other file, including new ones. This is what you want. - **`Enabled: false`** turns the cop off for **all** code, including files written tomorrow. For cops that matter, generate with `--no-exclude-limit` so the cop stays on and only today's files are listed. - **A raised `Max`** applies everywhere, so a new 60-line method passes if some legacy method has 60 lines. `--auto-gen-only-exclude` excludes the long files instead and keeps the limit for new code. ## Working the list down - **Promote decisions.** The comments above an entry show its configurable parameters. If the team actually prefers the style the code uses, move that setting to `.rubocop.yml` and delete the entry. - **Fix and delete.** Pick an entry, fix the files (often `rubocop -a --only Cop`), delete the entry, and run the suite. - **Catch stale entries.** Files get fixed or deleted as a side effect of other work, and nothing notices. `rubocop --report-unused-todo-entries` (RuboCop 1.90+) reports every `Exclude` entry whose cop no longer flags that file, and fails the run if any are found. New offenses still fail as usual, so it is safe on every CI build and only ever lets the file shrink. - **Regenerate on purpose.** `rubocop --regenerate-todo` reruns generation with the options recorded in the header. It removes stale entries, but it also **absorbs every new offense**. Run in CI, it would legalise each new violation, so it belongs in a reviewed local commit. ## A realistic adoption sequence 1. Agree on the handful of settings the team actually wants (quote style, line length) and put them in `.rubocop.yml` first, so the todo file does not record them as debt. 2. Run `rubocop -a`, review, run the tests and commit, so safe fixes never enter the todo file. 3. Generate the todo file with `--no-exclude-limit --auto-gen-only-exclude` and commit it on its own. 4. Turn on the CI gate, with `--report-unused-todo-entries`. 5. Each sprint, remove a few entries and fix the files they list, starting with cops whose corrections are safe. The size of `.rubocop_todo.yml` is then a trend the team can watch fall. ## Todo comments instead of a todo file `rubocop -a --disable-uncorrectable` takes a different route: it applies safe corrections and inserts `# rubocop:todo Cop` comments next to each offense it could not correct. Since 1.90 it does the same for unsafe corrections that `-a` skipped. The debt then lives beside the code, which suits cops enabled one at a time. ## Common mistakes - Editing a generated entry by hand and later regenerating, which silently throws the edit away. - Leaving the todo file untouched for years, so it becomes the real configuration. - Generating once and then disabling the new cops each upgrade brings, instead of deciding them.

  • Why is running rubocop --regenerate-todo in CI a bad idea?
    Regeneration rewrites the whole todo file from the current offenses, so any offense introduced in the change under test is added to the file instead of failing the build. The gate would accept every new violation. `--report-unused-todo-entries` is the CI-safe alternative: new offenses still fail, and stale entries fail too until removed.
  • Why can the default exclude limit of 15 weaken the gate for new code?
    When more than 15 files offend, the generated entry becomes `Enabled: false`, which turns the cop off for every file, including ones added later. Generating with `--no-exclude-limit` keeps listing files, so the cop stays active for anything not on the list.

saying these in an interview costs you the question

  • The todo file fixes the offenses; it just hides the report.
  • --auto-gen-config only excludes files and never disables a cop.
  • Running --regenerate-todo in CI keeps the todo file honest.
  • New files are automatically covered by the todo file's exclusions.
  • A raised Metrics Max in the todo file affects only the legacy methods.