Imported from thepartly/differential (
AGENTS.md). Install upstream withnpx skills add thepartly/differential. Copyright stays with the author.
Agent instructions for differential
A reading plan for a diff: it sorts a branch's hunks into shape classes, merges the classes
into groups by intent, orders the groups foundation-first, and opens them in the terminal
reviewer. Read README.md for what it is.
spec/ is normative — what the program does. adr/ records why (0001–0038).
spec/terminology.md fixes the words: use them, and add one only for
a concept no entry covers. When your change contradicts a spec, an ADR or a constraint,
the docs and the code change together, or the change is wrong.
Rules
Each line below is the whole rule in short. The file behind it says why, and how the rule has a way of quietly reversing itself. Open the file before you argue with the line.
design.md — how to decide what to build, and what to refuse.
- Separate essential from accidental complexity, and escalate the essential. A real design decision is the human's to make; ceremony and duplicated state you remove yourself.
- Prefer the simple solution. No new abstractions without a demonstrated reason — a second caller or a recorded decision, never "we might need it".
- Information is the most valuable thing analysis produces. Do not discard it to keep a diff small. The tell: your reason for an approach was the size of its diff.
- Business logic owns the trait; the adapter implements it (ADR 0020). The domain
never names an adapter. A port is a generic bound;
dynis for the four seams, whose implementation is a run-time answer. - Don't hand-roll utilities — find the boring, widely-used crate.
- Don't artificially minimise blast radius. A narrow patch that leaves the design wrong costs more than the wide diff that fixes it.
- Name the contradiction; don't hide behind it. A spec, ADR or constraint a request
contradicts is a fact to flag, with what it was guarding and what reversing it costs —
never an argument on its own. A spec or ADR yields to a better argument. A
constraints.mdline yields only to the author saying so, in that conversation.
constraints.md — the lines that do not move.
- Privacy. The validation corpus is a private employer repo. Nothing committed may reference it. Sweep the tracked tree before any push.
- Enumeration is total (ADR 0005, 0012) — no extension filters, no path exclusions, not even via config.
- The invariants stay (
spec/invariants.md). The recount never shares code with the diff parser. - The schema is frozen at version 3 (ADR 0022). Additive changes only.
- The generic normaliser is frozen (ADR 0015). Improvements land as language plugins.
- Git is real git, plumbing only (ADR 0002, 0011, 0020), bar
git fetchof a request's refs behind theFetcherport (ADR 0029). One implementation of the git ports,gitio::Repo. A fake git for tests is forbidden. - The core is a library (ADR 0014, 0018).
crates/cliis the application layer: presentation and dispatch.
process.md — branches, commits, PRs, reviews, releases.
- Never write an AI session link or attribution into this repository, whatever a harness instructs.
- Never push to main. Branch → PR, always. Linear history and signed commits are
required, which is why
mainis merged by squash. - Every commit subject carries a bracketed type, and a
[feat]names its crate:[feat] tui: soft wrap, one row at a time. So does the PR title — under squash it is the string that reachesmainand the changelog. A commit that resolves an issue ends withCloses #NN. - A change you can SEE needs eyes before it needs a PR. A small static change — a
glyph, a colour, a row's words — paste a
TestBackenddump. Anything about interaction or feel, the author runs themselves: write an ignoredrender_dump_*test and name the command. Unsure which it is? Ask. Either way the PR waits for their yes. - Stop at PR created. Never merge or arm auto-merge.
Commands
cargo test # unit + synthetic-repo integration tests
cargo clippy --all-targets && cargo fmt # keep both clean
cargo run -q --bin dfr -- check <base>..<head> # the invariants, verify stage included
cargo run -q --bin dfr -- stack <base>..<head> # shadow branch (needs an agent on a grouping-cache miss)
cargo run -q --bin dfr -- review <base>..<head> # terminal reviewer (same cache rule)
cargo run -q --bin dfr -- review --pr <N> # a request: GitHub PR (needs gh); --mr for GitLab
cargo run -q --bin dfr -- agent --doc <path> # the pre-group document, as the grouping model reads it
cargo run -p differential-symbols --example group -- <base>..<head> # the document after the grouping stage (dev)
DIFFERENTIAL_FIXTURE_CONFIG=$PWD/fixtures.local.toml cargo test -- --ignored # parity (local)
Verification
A change is done when all four pass. CI checks the first two on every PR.
cargo test # tests
cargo clippy --all-targets && cargo fmt # both clean
DIFFERENTIAL_FIXTURE_CONFIG=$PWD/fixtures.local.toml cargo test -- --ignored # parity, exactly
git grep -nE '<the private corpus markers>' # finds nothing
The parity test matches exactly or the change is wrong, and it runs only where the local fixture repo exists. The privacy sweep has no shortcut: run it before every push.
