PR Lens

Reference

Configuring PR Lens with .github/pr-lens.yml

Every option in .github/pr-lens.yml: lenses, branding, the four map corrections, and github.comment.collapsed. What the hosted App reads, and what only the CLI reads.

Lane names and node labels are the two things a config file exists to fix.

PR Lens reads .github/pr-lens.yml from your repository. The file is optional, and so is every field in it except schemaVersion. There are four things in it: lenses, which lenses to draw; branding, whether the footer appears; map, a set of corrections to the diagram PR Lens inferred; and github, one setting for the hosted App's comment. That is the entire surface as of contract version 0.1.1. Anything you have seen elsewhere is not in this file.

The hosted GitHub App reads the file from the pull request's head commit, so a change to it takes effect on the same push. The CLI reads it from your working tree, and the GitHub Action picks it up for map corrections too. If you have landed here without meeting the product, what is PR Lens is the page to read first.

The whole file

# .github/pr-lens.yml
schemaVersion: 0.1.1
lenses: [architecture, data-flow]
branding: true
map:
  rename:
    - match: functions/src/broadcast/sendBroadcastBulk.ts
      to: Broadcast sender
  exclude:
    - "**/*.test.ts"
    - scripts/**
  lane:
    - match: packages/broadcast-lib/**
      lane: functions
  group:
    - match: id:build-bulk-payload
      group: broadcast-lib
github:
  comment:
    collapsed: false

Nothing above is required except the version, and most repositories that commit one of these use two or three rules under map and nothing else.

For editor autocomplete, point at the published JSON Schema. There is no install involved:

{ "$ref": "https://unpkg.com/@coldtea/pr-lens-schema/json-schema/config.schema.json" }

Where the file goes

At .github/pr-lens.yml, in the repository root's .github directory. The CLI looks there first and falls back to .github/pr-lens.yaml if the first is absent; the hosted App reads the .yml spelling only.

The App reads it from the pull request's head commit rather than from your default branch, so a rule you add in the same pull request takes effect on that pull request. The file has a size cap of 64 KiB, which no honest config file goes near.

If the file is missing, everything runs on defaults: both lenses, branding on, no corrections, comment open. That is the state most repositories stay in, and it is a fine place to stay. Reach for this file when a diagram keeps saying something you know is wrong.

schemaVersion

The contract version your corrections are written against, currently 0.1.1. The CLI requires it, because a repository's corrections have to keep their meaning as the contract moves and a file with no version is a file nobody can date. The hosted App fills in the current version when the field is missing, so an App-only repository can leave it out and still be understood.

Selectors: an id or a path glob

Every correction under map matches nodes the same way. A match beginning with id: addresses exactly one node, as in id:build-bulk-payload. Anything else is a repository-relative path glob matched against the file paths backing a node.

Prefer the glob. Ids come from inference and can change when the code does, while a correction keyed to a path survives the model naming the node differently on the next run. Reach for id: when no path distinguishes the node, or when the node has no files at all, which is the case for an external service or a queue.

The four map corrections

RuleWhat it does
renameReplaces the inferred label
excludeDrops matching nodes, and every edge and flow step that hung from them
laneMoves matching nodes into a lane, creating it when the document declares no such id
groupClusters matching nodes under a sub-group inside their lane

Up to 128 of each. They are about intent rather than structure. There is no way here to add a node or draw an edge, and the only thing a correction can bring into existence is a lane, a band your repository wants that inference did not find. A created lane takes its id for its label, because the id is the only name this file carries, so write lane: infrastructure rather than lane: l3.

exclude is the one with reach. Removing a node takes with it every edge and flow step that touched it, every drill-down view left pointing at nothing else, every layout hint naming something gone, and every walkthrough step whose diagram or last focused element went too. A walkthrough cut below two steps goes whole, because one step is a caption. Half an arrow is worse than no arrow.

Four recipes cover most of what people actually want:

# Stop showing me test files
map:
  exclude: ["**/*.test.ts", "**/__tests__/**"]
 
# That node is called the wrong thing
map:
  rename:
    - match: server/lib/broadcast/createBroadcastSendTask.ts
      to: Send task
 
# These belong in a band of their own, which need not exist yet
map:
  lane:
    - match: infra/**
      lane: infrastructure
 
# Keep the shared library together
map:
  group:
    - match: packages/broadcast-lib/**
      group: broadcast-lib

lenses

Which lenses to render, one to eight values from architecture and data-flow, defaulting to both. Setting lenses: [architecture] is how a repository says its changes are structural and it does not want sequence diagrams.

The CLI's analyze command reads this to decide which lenses to ask a model for, so it narrows what gets inferred rather than only what gets drawn. The difference between the two lenses, and which question each one answers, is in architecture, sequence or data-flow diagram.

branding

A boolean, default true. It controls the "Rendered by PR Lens" footer on a composed comment. The CLI's comment command reads it, and --no-branding on that command overrides the file.

github.comment.collapsed

A boolean, default false. Set it to true and the hosted App's comment starts with its diagrams and details in a closed disclosure. Drawing still runs automatically; the reader just opens the section when they want it. This is the option for repositories where a large diagram at the top of every pull request is more than the team wants by default.

This is the only setting the hosted App reads from your file.

What the App reads, and what the CLI reads

SettingHosted AppCLI
github.comment.collapsedyesno
map.rename, exclude, lane, groupnoyes, applied at draw time
lensesnoyes, in analyze
brandingnoyes, in comment

The App reads the file at the pull request's head commit and falls back to defaults when it cannot read or parse it, so a broken YAML file degrades to the default behaviour rather than stopping the run. It does not log the parse error's contents, because YAML errors include source excerpts and a source excerpt from a repository file is a place secrets end up.

The Action picks the same file up for map corrections, applied over whatever the latest analysis inferred. The PR Lens GitHub Action post covers the rest of its setup.

Corrections are an overlay

This is the part worth understanding before you write a rule. The graph document PR Lens generates is regenerated on every run, so editing it is pointless. Corrections are an overlay, and inference never writes back into your file. Every run reapplies your rules on top of whatever the latest analysis inferred.

That is what makes a correction durable. The model can rename a node between two runs and your rename still lands, because it matched a path rather than a name. The document on disk stays the honest record of what was inferred, and your file stays the honest record of what you disagreed with. The document itself, field by field, is in the PR Lens graph document explained.

Check it, and check whether it still matches

Validate the file with the same command that validates a document:

pr-lens validate .github/pr-lens.yml

Then, separately: pr-lens render reports any correction that changed nothing about the document it drew. That is a config that has drifted, usually because the file a selector named has moved or been deleted. Nothing stops and it is not an error, but it is worth fixing, because a correction matching nothing is a correction nobody is getting.

If you would rather not write YAML at all, the agent skill route works: tell the coding agent you already have open that the diagram named something wrong, and have it write the rule. That path is in PR Lens as an agent skill.

What you cannot set here

Worth stating, because people look for these. There is no way to add a node, draw an edge, or set a colour. There is no model selection, no prompt, and no threshold. There is no findings, severity or security section, because a PR Lens document has no field for a bug or a risk and one that invents one is rejected rather than trimmed.

If the map is wrong in a way these four corrections cannot express, the fix belongs in the analysis rather than in this file. The four run out at exactly the point where you would be redrawing the diagram by hand, which is the thing the whole tool exists to avoid.

Questions people ask

How do I configure PR Lens?

Commit a .github/pr-lens.yml file to your repository. The file is optional and so is every field in it except schemaVersion. It holds four things: which lenses to draw, whether to show the PR Lens footer, a map section of corrections to the inferred diagram, and one GitHub comment setting.

How do I stop PR Lens drawing my test files?

Add a map.exclude rule with a path glob, for example "**/*.test.ts". Excluding a node takes with it every edge and flow step that touched it, every drill-down view left pointing at nothing, and every walkthrough step whose last focused element went with it. You can have up to 128 exclude rules.

Can I rename a node in a PR Lens diagram?

Yes, with a map.rename rule. Match the file path the node comes from rather than its id where you can, because ids come from inference and may change when the code does, while a path correction survives that. The rule replaces the inferred label and is reapplied on every run.

Does PR Lens write back into my config file?

No. The config is an overlay applied over fresh inference every run, and inference never writes into it. That is why a correction keeps holding as the code moves and as the model names things differently between runs.

Sources

Keep reading

Turn it on

Install the App and every pull request in the repositories you pick gets drawn. Or hand the prompt to the agent you already have open.

Add to GitHub