---
title: "Thresholds and diffs"
description: "How mehen.toml thresholds and `mehen diff` gating compose in CI."
keywords: ["thresholds", "diff", "gating", "ci", "mehen.toml"]
---

mehen offers two per-metric gating mechanisms: repository-local
[`mehen.toml` thresholds](/configuration) evaluated inside the binary against **absolute values**,
and the [GitHub Action](/guides/github-action)'s `thresholds` input evaluated against **per-file
deltas**. This page explains how they differ, how they compose with the JSON output of
`mehen diff`, and how to write your own gating logic in CI.

## Repository thresholds (mehen.toml)

A `mehen.toml` at the repository root gates every command — locally, in pre-commit hooks, and in
any CI system:

```toml
[thresholds]
cognitive = 15
"loc.lloc" = 500

[languages.python.thresholds]
cognitive = 10
```

`mehen metrics`, `mehen diff` (head side), and `mehen top-offenders` exit `1` when a reported
metric crosses its limit, after a grouped stderr report that names the config table to adjust.
Limits bound where a metric may *be*: a file over the limit fails the gate even if the current
change didn't move it. Full reference: [Configuration](/configuration).

## Action threshold input

```yaml
- uses: ophi-dev/mehen@v1
  with:
    paths: src
    thresholds: |
      cyclomatic=5
      cognitive=4
      loc.lloc=120
```

The action runs `mehen diff` and then evaluates each per-file delta against the supplied limits. A
violation:

- Counts toward the `violations` output.
- Fails the action when `fail-on-threshold: true` (default).

Delta limits bound how far a single PR may move a metric in the adverse direction; they say
nothing about the absolute level a file already sits at. Combine them with
[`mehen.toml` thresholds](/configuration) to bound both.

## Adverse direction

Each metric has an adverse direction. Thresholds limit how far in the adverse direction a per-file
delta is allowed to go:

| Metric | Adverse | Example threshold |
|---|---|---|
| `cyclomatic` | ↑ | `cyclomatic=5` blocks a per-file increase by more than 5. |
| `cognitive` | ↑ | `cognitive=4`. |
| `loc.lloc` | ↑ | `loc.lloc=120`. |
| `mi.visual_studio` | ↓ | `mi.visual_studio=10` blocks a per-file decrease by more than 10. |
| `halstead.volume` | ↑ | `halstead.volume=200`. |

mehen knows the direction for the standard metrics and applies the threshold accordingly.

## Composition with diff JSON

If you want richer logic than the action provides, run `mehen diff -O json` yourself and pipe the JSON
into a CI script:

```bash
mehen diff --from "$BASE_SHA" --to "$HEAD_SHA" --paths src \
           --output-format json > metrics-diff.json
jq '.files[] | select(.deltas.cyclomatic.delta > 5)' metrics-diff.json
```

`jq` and the JSON shape give you full control. The downside: you reimplement adversity rules.

## See also

- [Configuration](/configuration) — `mehen.toml` reference: absolute thresholds, per-language
  overrides, the violation report.
- [GitHub Action](/guides/github-action) — full input/output reference.
- [Commands → diff](/commands/diff) — `mehen diff` CLI reference.
- [Output formats](/concepts/output-formats) — JSON shape.
