Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Merge rules

When a pull request conflicts with what landed and the merge engine is on (see Workflows), the sheltie-merge workflow merges it on your runner:

  1. Structural merge. Conflicted source files go to mergiraf, which merges by syntax tree. It is GPL-3.0 and only ever runs as a separate program.
  2. Derived files are regenerated instead of merged.
  3. Declared rules merge files that have a known shape.

The result is verified like any other change before it lands. Files no tier can resolve return the pull request to its author, or go to intent replay if it is enabled.

Rules live in .sheltie/merge.toml on the default branch. Sheltie never reads them from the pull request being merged. They are parsed strictly: unknown keys, invalid globs or regular expressions, files over 64 KB and more than 100 rules are rejected.

[[derived]]          # regenerate instead of merging
paths = ["Cargo.lock"]
regenerate = "cargo update -w --offline"

[[set]]              # order-insensitive lines: union of both sides
paths = ["config/feature_flags.txt"]

[[sequence]]         # numbered files: renumber the later side on collision
paths = ["migrations/*.sql"]
key = "^(\\d+)_"

[[derived]]

Files generated from others, such as lockfiles. The engine takes one side, then runs regenerate (one line, at most 500 characters, run with sh -c in the checkout). This also happens when both sides changed the file without a textual conflict. A command shared by several conflicted files runs once.

[[set]]

Files whose lines form an unordered set (feature flags, allow lists, CODEOWNERS-style lists). Conflicts are resolved with a three-way union of lines: lines either side added are kept (ours first), lines either side removed are dropped, and duplicate lines are removed.

[[sequence]]

Numbered files, such as database migrations, where both sides added a file with the same number. key is a regular expression whose first capture group is the number; the file the later side added is renumbered to the next free number.

Two changes that each add a file matching the same rule conflict even when their file names differ (the adapter gives them a shared seq: target), so they always go through the merge engine and never land with the same number.

When more than one rule matches a path, [[derived]] wins over [[set]], which wins over [[sequence]].

[replay]

Settings for tier 4, re-deriving a change with an agent: enabled, the test commands (test_command, and test_commands per language), the model and the limits. See Replay.

[estimates]

Assumptions for the dashboard’s time-saved estimate. Both are optional, in minutes (at most 1440). See Dashboard.

[estimates]
minutes_per_conflict = 15   # an author fixing a conflict the merge engine resolved
minutes_per_replay = 30     # an author redoing a change Sheltie re-derived

The server reads this file from the default branch every 10 minutes.

[[agents]]

Names the agents behind pull requests, for the agent scorecards. Each rule has a name, an optional model, and at least one condition; every condition given must match, and the first matching rule wins.

[[agents]]
name = "codex"
model = "gpt-5-codex"   # optional, shown next to the name
branch = "codex/"       # the head branch starts with this

[[agents]]
name = "claude"
label = "agent: claude" # the pull request has this label (case-insensitive)

[[agents]]
name = "release-bot"
author = "acme-release[bot]"  # the author's login (case-insensitive)

Without a matching rule, a pull request opened by a bot account counts as that bot (claude[bot] becomes claude), and pull requests opened by people are grouped as “People”. Names are at most 40 characters; at most 50 rules. The server reads this file from the default branch every 10 minutes, and the rules apply to past pull requests too.