Skip to main content
roe reads an optional config file named roe.json, roe.yaml, or roe.yml. It’s resolved by walking up from the analysis root to the nearest directory containing one (like .eslintrc/tsconfig.json), or pointed to explicitly with --config:
If a directory contains more than one candidate, roe warns and roe.json wins. An explicit --config path that’s missing or malformed is a hard error.

Fields

roe.json
Unknown fields are rejected, so a typo fails loudly instead of being silently ignored.

Dupes options

Every field under dupes is optional and corresponds to a flag on roe dupes: This block is what calibrates a combined run: roe check takes no dupes flags of its own, so raising minTokens here is how a one-line CI gate learns the threshold your codebase needs.

Health thresholds

Every field under health is optional and corresponds to a flag on roe health: Committing these is usually better than passing six flags on every CI invocation, and it keeps local runs and CI in agreement. baseline names a baseline file and is resolved relative to the config file’s own directory, the way ignore globs are — so "roe-baseline.json" means the one sitting next to roe.json, no matter which subdirectory the run starts in. Setting it here rather than passing --baseline is also what makes a bare roe and roe check honour it, since neither takes health flags of its own. A path that doesn’t exist is a hard error, not a silent full-backlog run.

Entry-point files

entryPoints is the file-level counterpart to roots: where roots names one symbol by its fully-qualified name, an entry-point glob keeps a whole file’s contents alive. Every declaration in a matching file becomes a root, so the file is never flagged and everything it references counts as used — unlike an ignore glob, which only drops the findings in the matching file itself. Use it for files that are consumed in ways roe can’t see: a plugin host loading them by path, string-based reflection, or an external tool reading the file directly.
roe.json
Patterns resolve relative to the config file’s own directory with the same rules as ignore globs — a trailing / matches the whole directory, and .. is unsupported. A pattern that matches no file at all is reported as a note in the output, so a stale path can’t silently drop the protection it promised.

Ignore globs

ignore patterns are resolved relative to the config file’s own directory. A trailing / matches the whole directory, so "Generated/" needs no **. Patterns containing .. are unsupported and produce a warning. The top-level ignore list applies to all three commands — including roe dupes and roe health’s circular dependencies, which span multiple files and don’t map cleanly onto a single-line inline suppression comment. Each command’s section takes an ignore list of its own with the same rules, unioned with the top-level list and applied only to that command. That keeps a suppression as narrow as the exception it accepts: ignoring an intentional duplicate through dupes.ignore doesn’t cost the file its dead-code and health coverage.
roe.yaml
A scoped list only ever adds patterns — it can’t re-include a file the top-level list ignores — and an empty one is a no-op.

Precedence

Every setting follows the same order: an explicit command-line flag wins, otherwise the config file’s value applies, otherwise the built-in default. For aggressive, roots, and libraryProjects that means an explicit --aggressive, --root, or --library flag beats the config, falling back to false / no extra roots / no extra library projects. Two nuances: --aggressive can only turn the setting on — there is no --no-aggressive to override a config’s "aggressive": true. And passing --root or --library replaces the config’s list wholesale rather than merging with it. Health thresholds work the same way, per field: --max-complexity 12 overrides "maxComplexity" for that run, while every threshold you don’t pass still comes from the config. Like --aggressive, --exclude-tests can only turn the setting on. Dupes settings follow the same per-field order: --min-tokens 100 overrides "minTokens" for that run, and the rest still come from the config. --mode carries a value, so unlike --aggressive and --exclude-tests it has no on-only nuance — --mode exact overrides a config’s "semantic" cleanly. Ignore lists and entryPoints sit outside this order entirely: neither has a CLI flag, and a command’s own ignore list is unioned with the top-level one rather than replacing it. To confirm a config-only excludeTests or ignore actually applied, read the roe health footer: the scanned counts narrow by whatever was excluded, and an excluded: line names it. See What “scanned” counts.