---
title: .izri/scope.yml
description: The checked-in config that teaches the scope signal your project's modules, categories, and sensitive paths.
order: 10
---

# `.izri/scope.yml`

`.izri/scope.yml` is the vocabulary the scope analyzer reasons against: what your modules are called, what kinds of change your PR types allow, and which paths deserve a second look.

It lives in your repository, at the PR head. That's the important part — it is checked in, code-reviewable, and versioned alongside the code it governs.

## Resolution precedence

Four steps, in order:

| # | Condition | Source |
| --- | --- | --- |
| 1 | Valid `.izri/scope.yml` at the PR head | `in_repo` |
| 2 | Malformed `.izri/scope.yml` | falls back, **and emits an `info` finding** |
| 3 | No repo file, dashboard config exists | `dashboard` |
| 4 | Neither | `defaults` |

**In-repo wins on purpose.** If the dashboard could override a checked-in file, the file in your repository would silently disagree with what actually ran — and the file is the thing your team reviews.

### A malformed file degrades, it does not fail

A `.izri/scope.yml` that doesn't parse falls back to the dashboard config or defaults and emits an `info`-level finding saying so. Your build does not break because of a YAML typo.

The tradeoff: a broken config is easy to miss, because `info` findings don't block. If scope results look wrong, check the resolved source first — the delta report records which of the four cases applied.

## Schema

Three top-level keys: `modules`, `categories`, `sensitive`.

```yaml
modules:
  - name: billing
    paths:
      - src/billing/**
      - packages/payments/**
  - name: auth
    paths:
      - src/auth/**

categories:
  - label: feature
    expects:
      - src/**
    requires_test_change: true
  - label: docs
    forbids:
      - src/**
      - migrations/**
    requires_intent_statement: false

sensitive:
  - name: payment handling
    paths:
      - src/billing/charge.ts
  - name: migrations
    paths:
      - migrations/**
```

### `modules`

Named groups of paths. This is the vocabulary findings are phrased in — without it, scope can only talk about file paths.

| Field | Required | Type |
| --- | --- | --- |
| `name` | yes | string |
| `paths` | yes | string[] |

### `categories`

What each kind of change is allowed to touch. `label` matches the PR's declared type, typically from its conventional-commit prefix.

| Field | Required | Type | Effect |
| --- | --- | --- | --- |
| `label` | yes | string | The PR type this rule applies to. |
| `expects` | no | string[] | Paths this type normally touches. |
| `forbids` | no | string[] | Paths this type must not touch. **Emits `pr_type_forbidden_category` at `error` — a hard rule that fails the umbrella.** |
| `requires_intent_statement` | no | boolean | Require a body explaining the change. |
| `requires_test_change` | no | boolean | Require the diff to include test changes. |

**`forbids` is the only user-configurable hard gate.** Everything else in scope is advisory. If you want a rule that genuinely blocks a merge, express it as `forbids` on a category — not as a sensitive path.

### `sensitive`

Paths worth a human glance.

| Field | Required | Type |
| --- | --- | --- |
| `name` | yes | string |
| `paths` | yes | string[] |

Touching one emits `sensitive_path` at **`info`**. It does not block, and it is not meant to — it points a reviewer at something. Teams reliably assume this gates a merge. It doesn't. Use `forbids` for that.

## Auto-derivation

You don't have to write this by hand. Izri derives an initial config from your repository's file tree and metadata. The stored config records its origin:

| Source | Meaning |
| --- | --- |
| `derived` | Generated by Izri. |
| `user` | Edited in the dashboard. |
| `merged` | Derived, then hand-adjusted. |

Read the current one with the `get_scope_config` [MCP tool](/docs/install/mcp), or from the dashboard. Export it to `.izri/scope.yml` when you want it under version control.

## Worked example: a minimal config

Start here. Sensitive paths alone are useful before you formalize categories:

```yaml
modules: []
categories: []
sensitive:
  - name: auth
    paths:
      - src/auth/**
  - name: migrations
    paths:
      - migrations/**
```

## Worked example: enforcing a boundary

Stopping a docs PR from carrying a schema migration:

```yaml
categories:
  - label: docs
    forbids:
      - migrations/**
      - src/**
```

A PR titled `docs: update readme` that also edits `migrations/0042_add_column.sql` now fails the umbrella, regardless of how clean every other signal is.

## Related

- [`izri/scope`](/docs/signals/scope) — the signal this configures.
- [Signals overview](/docs/signals/overview) — severities and hard rules.
