# Configuration Reference
This document covers the full configuration options for PR Bro. For a quick-start guide, see the [README](../README.md).
Configuration file location: `~/.config/pr-bro/config.yaml`
## Full Configuration Example
```yaml
# Theme: "auto" (default, detects terminal), "dark", or "light"
theme: auto
# Auto-refresh interval in seconds (default: 300 = 5 minutes)
auto_refresh_interval: 300
# Global scoring configuration (applies to all queries unless overridden)
scoring:
base_score: 100
age: "+1 per 1h" # Adds 1 point per hour of age
approvals: "+10 per 1" # Adds 10 points per approval
size:
exclude: ["*.lock", "package-lock.json"]
buckets:
- range: "0-9"
effect: "x10" # Extremely small PRs get a huge boost
- range: "10-99"
effect: "x5" # Small PRS get a decent boost
- range: "100-249"
effect: "x1" # Medium PRs: no change
- range: "250-499"
effect: "x0.5" # Large PRs get a decent penalty
- range: ">=500"
effect: "x0.25" # Extremely large PRs get a huge penalty
labels:
- name: "highest priority"
effect: "x10"
- name: "wip"
effect: "x0.5"
previously_reviewed: "x2.5" # Previously reviewed PRs get a boost
draft: "x0.1" # Deprioritize draft PRs
# Queries to execute (at least one required)
queries:
- name: "foo/bar PRs needing my attention"
query: "is:pr is:open review-requested:@me repository:foo/bar"
scoring: # Per-query scoring (merges with global)
base_score: 50
age: "x1.5 per 1d" # Gets a x1.5 boost per day of age
approvals: "+5 per 1"
```
## Scoring Factors
Each scoring factor is optional and can use addition (`+N`) or multiplication (`xN`) effects.
### Age
Format: `"+N per DURATION"` or `"xN per DURATION"`
Duration uses humantime format: `1h`, `30m`, `1d`, `1w`
Examples:
- `"+1 per 1h"` — adds 1 point per hour of age
- `"x1.1 per 1d"` — multiplies score by 1.1 per day of age
### Approvals
Format: `"+N per 1"`, `"xN per 1"`, `"+N"`, or `"xN"`
This is NOT bucket-based — the effect applies per approval count.
Examples:
- `"+10 per 1"` — adds 10 points per approval
- `"x2 per 1"` — doubles score per approval
- `"+50"` — adds 50 points if any approvals exist
### Size
Bucket-based configuration with optional file exclusions.
**Range formats:**
- `"<N"` — less than N lines
- `"<=N"` — less than or equal to N lines
- `">N"` — greater than N lines
- `">=N"` — greater than or equal to N lines
- `"N-M"` — inclusive range from N to M lines
**Effect formats:**
- `"+N"` — add N points
- `"xN"` — multiply score by N
**Important:** Size bucket ranges must NOT overlap. The validator will reject configurations with overlapping ranges at startup.
Example:
```yaml
size:
exclude:
- "*.lock"
- "package-lock.json"
- "yarn.lock"
buckets:
- range: "<100"
effect: "x5" # Small PRs: 5x multiplier
- range: "100-500"
effect: "x1" # Medium PRs: no change
- range: ">500"
effect: "x0.5" # Large PRs: 0.5x penalty
```
**Exclude pattern behavior:**
- Patterns match against the **filename only** (basename), not the full file path. For example, `*.lock` will match `Cargo.lock` and `subdir/package-lock.json`.
- When exclude patterns are configured, PR Bro fetches per-file diff data from the GitHub API to determine which files to exclude. This adds 1-2 API calls per PR (paginated at 100 files per page).
- If the per-file data fetch fails (e.g., rate limit), PR Bro falls back to the aggregate size from the PR summary (no exclusions applied).
- Without exclude patterns, no extra API calls are made.
- Invalid glob patterns are caught at startup during config validation.
### Labels
Optional. Applies score effects based on GitHub labels on the PR. Multiple matching labels compound their effects sequentially (not first-match). Label matching is **case-insensitive**.
```yaml
labels:
- name: "urgent"
effect: "+10" # Add 10 points for urgent PRs
- name: "wip"
effect: "x0.5" # Halve score for work-in-progress
- name: "critical"
effect: "x2" # Double score for critical PRs
```
A PR with both "urgent" and "critical" labels gets both effects: score + 10, then x2.
Each matching label appears as a separate entry in the score breakdown detail view (press `b`).
### Previously Reviewed
Optional. Applies a score effect when the authenticated user (the user whose token is configured) has previously submitted a review on the PR.
If your team is using review requests via GitHub to ask for reviews when a PR is ready to review, this configuration plays well with it, as you can then use `review-requested:@me` filter in the GitHub query to fetch PRs needing your review.
That workflow, paired with this configuration, means that when they need you to re-review such a PR, you could prioritize it using
```yaml
previously_reviewed: "x2.5" # Prioritize already-reviewed PRs
```
### Draft
Optional. Applies a score effect when a PR is marked as a draft. Useful for deprioritizing PRs that aren't ready for review yet.
```yaml
draft: "x0.1" # Heavily deprioritize draft PRs
```
## Effect Syntax Summary
| Syntax | Meaning |
|--------|---------|
| `+N` | Add N points |
| `xN` | Multiply score by N |
| `+N per DURATION` | Add N points per time unit (age only) |
| `xN per DURATION` | Multiply by N per time unit (age only) |
| `+N per M` | Add N points per M units (approvals only) |
| `xN per M` | Multiply by N per M units (approvals only) |
Labels, previously_reviewed, and draft use flat effects (`+N` or `xN`), not per-unit effects.
## Per-Query Scoring
Queries can override individual fields of the global scoring configuration. When a PR appears in multiple queries, the **first query's scoring is used** (first-match-wins). Per-query scoring merges with global scoring at the **leaf level** — only the exact sub-fields you specify in a query override the global values; everything else is inherited. This means setting `scoring.size.exclude` in a query does **not** replace the entire `size` block; global `size.buckets` are preserved (and vice versa).
Example:
```yaml
scoring:
base_score: 100
age: "+1 per 1h"
approvals: "+10 per 1"
size:
buckets:
- range: "<100"
effect: "x5"
- range: "100-500"
effect: "x1"
- range: ">500"
effect: "x0.5"
labels:
- name: "urgent"
effect: "+20"
- name: "wip"
effect: "x0.5"
queries:
- name: urgent
query: "is:pr label:urgent"
scoring:
age: "+10 per 1h" # Override: urgent PRs age faster
size:
exclude: ["*.lock"] # Add exclude — inherits global buckets
labels:
- name: "urgent"
effect: "+50" # Override: stronger urgent boost for this query
# base_score, approvals — inherited from global
# size.buckets — inherited from global (not overridden)
# label "wip" — inherited from global (not mentioned here)
- name: other
query: "is:pr org:myorg"
# No scoring block — uses global scoring entirely
```
In this example, the "urgent" query:
- **Overrides** `age` to `"+10 per 1h"` (urgent PRs age faster).
- **Adds** `size.exclude` with `["*.lock"]`. Because merging is leaf-level, global `size.buckets` are inherited — setting `size.exclude` does NOT replace the entire `size` block.
- **Overrides** the "urgent" label effect from `"+20"` to `"+50"`. Labels merge by name (case-insensitive): the query's "urgent" label wins over the global one. The global "wip" label is preserved because the query does not mention it.
- **Inherits** `base_score`, `approvals`, `previously_reviewed`, and `draft` from the global config (not specified in the query, so global values apply).
### YAML Merge Keys
YAML merge keys (`<<:`) are supported by the YAML parser for reducing duplication within your config file. This is a YAML feature processed when reading the file, independent of the runtime merge that combines global and per-query scoring. Note that because PR Bro validates config structure strictly (`deny_unknown_fields`), YAML anchors must be placed inside fields that expect the anchored structure, not at the top level. For advanced YAML anchor/merge-key usage, refer to the [YAML specification](https://yaml.org/type/merge.html).
## Theme
PR Bro supports light and dark color themes. The default is `auto`, which detects your terminal's background color at startup and selects the appropriate palette.
```yaml
theme: auto # Detect terminal background (default)
theme: dark # Always use dark theme
theme: light # Always use light theme
```
If auto-detection fails (e.g., over SSH or in tmux), it falls back to the dark theme.
## Config Validation
PR Bro validates your configuration at startup with clear error messages:
- **Unknown YAML keys** are rejected (catches typos like `approvalls` instead of `approvals`)
- **Overlapping size bucket ranges** are rejected (prevents ambiguous scoring)
- **Invalid effect syntax** is caught with helpful messages
- **Empty label names** are rejected
- **Invalid glob patterns** in `size.exclude` are caught (e.g., unclosed character classes like `[invalid`)
- **Invalid label effects**, **invalid previously_reviewed effects**, and **invalid draft effects** are caught at startup
Validation errors will show exactly what's wrong and where, so you can fix configuration issues quickly.