---
title: "mehen top-offenders"
description: "Walk one or more paths and rank the worst-offending files by one or more metrics."
keywords: ["mehen top-offenders", "ranking", "code health", "cli"]
---

`mehen top-offenders` walks one or more paths, computes head-only metrics, and emits a deterministic
sorted list of the worst-offending files. It is the right tool for repository health dashboards,
prioritization reports, and "where do we spend time?" planning.

```text
mehen top-offenders [OPTIONS] --metric <METRICS> <PATHS>...
```

| Argument | Description |
|---|---|
| `<PATHS>...` | One or more files or directories to analyze. |

| Flag | Default | Description |
|---|---|---|
| `-M, --metric <METRICS>` | required | Metric to rank by. Repeatable — first is primary key, next breaks ties, etc. Prefix with `+` for higher-is-better or `-` for lower-is-better. |
| `--max-results <N>` | `10` | Maximum number of offenders to return. |
| `-O, --output-format <FMT>` | `markdown` | `markdown` or `json`. |
| `-I, --include <GLOB>` | — | Glob to include files. Repeatable. |
| `-X, --exclude <GLOB>` | — | Glob to exclude files. Repeatable. |
| `--no-ignore` | off | Disable ignore-file and Git-attribute filtering. Hidden children remain excluded. |
| `-j, --num-jobs <N>` | platform default | Number of parser jobs. |
| `-l, --language-type <LANG>` | auto | Language type override (skip auto-detection). |
| `--config <PATH>` | discovered | Pin a [configuration file](/configuration) instead of discovering `mehen.toml` upward from the working directory. |

## File discovery

Directory walks respect `.gitignore`, `.ignore`, `.git/info/exclude`, parent ignore files, and the
user's global Git excludes by default. Ignored directories are pruned before their files are
scheduled for analysis. This keeps generated and vendored trees such as `node_modules`, `target`,
`dist`, and `cdk.out` out of the parser workload when the repository ignores them.

Within Git repositories, mehen also reads the normal Git attribute hierarchy, including nested
`.gitattributes`, `.git/info/attributes`, and configured global attributes. Nested repositories use
their own hierarchy. Files with any of these attributes set, or assigned the value `true`, are
excluded before parser dispatch:

- `linguist-generated`
- `linguist-vendored`
- `binary`

An attribute explicitly unset or assigned `false` does not exclude the file.

Pass `--no-ignore` to disable both ignore-file and Git-attribute filtering. Hidden children are
still skipped. An explicit file path is always considered, even when an ignore rule or attribute
matches it, so a deliberately targeted file can still be measured.

## Known metric names

`cyclomatic`, `cognitive`, `nom.functions`, `loc.lloc`, `mi.original`, `mi.sei`, `mi.visual_studio`,
`halstead.volume`, `abc`, plus every other key the analyzers publish onto a file's root metric set —
the full LOC family (`loc.sloc`, `loc.ploc`, …), aggregate spellings (`cognitive.max`,
`loc.lloc.avg`, `nom.functions.max`), `nargs`, `nexit`, `npa.*`, `npm.*`, `wmc`, the git history
family (`history.churn.abs`, `history.churn.relative`, `history.age_months`, `history.authors`,
`history.minor_contributors`, `history.ownership`, `history.commit_frequency`, `history.hotspot`,
`history.sum_of_coupling`, `history.twr`, `history.bugfix_commits` — these require a full,
non-shallow git clone (e.g. a CI checkout with `fetch-depth: 0`) and walk the history of `HEAD`),
plus the full Markdown family from [Markdown metrics](/metrics/markdown/overview). These are the
same names a [`mehen.toml`](/configuration) threshold accepts.

## Polarity

Each metric has a default direction. mehen knows that higher cognitive complexity is worse, higher
maintainability index is better, etc. Override with the prefix:

- `--metric +mi.visual_studio` — rank highest MI first (best at top).
- `--metric -cognitive` — rank highest cognitive first (worst at top).
- `--metric cognitive` — same as `-cognitive` because cognitive's default polarity is "lower is better".

## Examples

<Tabs>
  <Tab title="Worst by cognitive">
    ```bash
    mehen top-offenders src --metric cognitive --max-results 20
    ```
  </Tab>
  <Tab title="Multi-key sort">
    ```bash
    mehen top-offenders crates \
      --metric cognitive --metric loc.lloc --metric halstead.volume
    ```
  </Tab>
  <Tab title="Filter to one tree">
    ```bash
    mehen top-offenders . \
      --include 'crates/**' --exclude '**/tests/**' \
      --metric cognitive --output-format json
    ```
  </Tab>
  <Tab title="Markdown docs only">
    ```bash
    mehen top-offenders docs \
      --include '**/*.md' --include '**/*.mdx' \
      --metric md.filler_lazy_risk --metric md.dmi
    ```
  </Tab>
</Tabs>

## Determinism

The output ordering is fully deterministic: same visible paths, ignore configuration, metrics, and
head ref → byte-identical report. Tie-breaking falls back to the next `--metric`, then to the
repository-relative path. There is no sampling and no file-system-order dependence.

## Configured thresholds

When a [`mehen.toml`](/configuration) is present, the configured limits for the selected
`--metric` names are checked against **every analyzed file** — not just the displayed top N, so a
violation cannot hide below `--max-results`. The ranking still prints in full; crossed limits then
print a grouped report on stderr and the command exits `1`.

## Exit codes

| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | IO, parser-fatal, or unsupported-language error. Also: a [configured metric threshold](/configuration) crossed, after the ranking is emitted. |

## See also

- [`mehen metrics`](/commands/metrics) — single-file analysis.
- [`mehen diff`](/commands/diff) — compare two revisions.
- [Code metrics](/metrics/code/overview), [Markdown metrics](/metrics/markdown/overview) — the
  metric catalog you can rank by.
