Generate a change overview¶
lgtmaybe can post a change overview on a pull request: what the change is, what is risky about it, and what it touches. It is one comment, updated in place, that a reviewer reads before the diff. A separate concern from the review — the review finds bugs in the lines it reads, the overview describes the change as a whole.
Contents¶
- What you get
- High Impact Areas
- Structure and sequence
- On GitHub:
/diagramandauto_diagram - Locally:
lgtmaybe diagram - Why Mermaid (and what the ASCII is for)
- See also
What you get¶
Three focused model calls, run concurrently, compose one comment in reading order:
- a description — a suggested title, the change type, a short summary, a
per-file walkthrough, and a "does it do what it says" check when the PR
states an intent (
auto_describe); - High Impact Areas — the changes a reviewer must not
miss, in a bold-titled section (
high_impact); - up to two diagrams, each in two renderings — a Mermaid flowchart of the structure, a Mermaid sequence diagram of the run-time flow when the change alters one, and a plain-text rendering of each, which is what shows in a terminal and serves as the fallback if the Mermaid can't be rendered.
Three calls rather than one because a single prompt doing three jobs does all three worse. They run at the same time, so the overview costs about as much wall-clock as its slowest call rather than the sum of the three. Each section has its own switch, and the description and High Impact Areas sections are best-effort: if one of those calls fails, its slot says so and the rest of the comment still posts.
GitHub renders both Mermaid diagrams natively inside the comment — no image, no external hosting.
The flowchart is intentionally sparse: it uses at most six nodes, short
relationship labels, and Mermaid's automatic layout. Changed elements are
marked in their labels ((new) / (changed)), keeping labels and arrows clear
of neighbouring cards. Because GitHub's renderer offers zoom buttons but no
full-screen, the diagram is followed by an ⛶ Open full screen link that
renders the same diagram alone in a browser tab, with pan and zoom, on
mermaid.live. The source travels compressed in the URL
fragment, decoded in your browser, so nothing is sent anywhere until you click.
The diagram also stays honest about the diff being only a slice of the
codebase: relationships inferred from imports rather than shown in the diff
are called out in the notes.
Here is what the posted comment looks like for a PR that puts a Redis cache in front of a user service — the Mermaid renders in place, with the ASCII tucked in a collapsible "Text version" underneath:
Cache user lookups in Redis¶
Change type: feature
User reads now check Redis before PostgreSQL, and successful database reads populate the cache for later requests.
High Impact Areas¶
- Infrastructure — New ElastiCache cluster (
infra/redis.tf). Adds a managed dependency to the production VPC. Check: security group and failover settings.- Availability — Cache on the user read path (
api/users.py). User reads now depend on Redis, so a Redis outage takes reads down with it. Check: confirm a Redis error falls back to the database.- Backup and recovery — touched:
ops/backup_retention.tf(not assessed by the model)Structure¶
flowchart LR
client["Client"]
api["User API<br/>Python<br/>serves user reads"]
cache["Redis cache<br/>Redis<br/>caches rows (new)"]
db["User DB<br/>PostgreSQL"]
client -->|requests| api
api -->|checks| cache
api -->|on miss| db
⛶ Open full screen (the real link carries the diagram source compressed into the URL)
Text version
[Client] --> [User API] --check--> [Redis cache] (new)
|
+--miss--> [User DB]
Sequence¶
sequenceDiagram
participant client as Client
participant api as User API (changed)
participant cache as Redis cache (new)
participant db as User DB
client->>api: GET /users/{id}
api->>cache: read cached row
cache-->>api: miss
api->>db: SELECT user
api->>cache: store row, 60s TTL
api-->>client: user JSON
Text version
1. [Client] -> [User API (changed)]: GET /users/{id}
2. [User API (changed)] -> [Redis cache (new)]: read cached row
3. [Redis cache (new)] --> [User API (changed)]: miss
4. [User API (changed)] -> [User DB]: SELECT user
5. [User API (changed)] -> [Redis cache (new)]: store row, 60s TTL
6. [User API (changed)] --> [Client]: user JSON
The User DB link is inferred from an import, not shown in the diff.
High Impact Areas¶
A review reads the changed lines and tells you what is wrong in them. It cannot tell you that halving a node count removes your peak headroom, or that the PR quietly shortened a backup retention policy. High Impact Areas asks the other question — what could this change break beyond itself? — and answers it in one bold-titled section at the top of the overview.
Ten areas are checked:
| Area | What it covers |
|---|---|
| Infrastructure | IaC, Kubernetes/Helm, container images, CI/CD pipelines, deploy scripts, networking, DNS, load balancers, resource sizing |
| Security | Authentication, authorisation, IAM or permission scope, cryptography, secret handling, removed input validation, CORS/CSP/TLS, CI workflow permissions |
| Availability | Anything that could cause a production outage: startup and config defaults, timeouts, retries, circuit breakers, connection pools, rate limits, health checks, removed error handling, concurrency and locking, runtime or major dependency upgrades, hot-path performance, rollback and deploy ordering |
| Data migration | Schema or data migrations, destructive or irreversible data operations, backfills |
| Backup and recovery | Backup jobs, retention and lifecycle policies, snapshots, restore paths, disaster recovery, failover, replication |
| Compatibility | Breaking an external contract: HTTP APIs, event or message schemas, CLI flags, SDK surface, wire formats, feature-flag removal |
| Observability | Logs, metrics, alerts, dashboards, tracing, audit trails or runbooks being removed, silenced or changed |
| Dependencies | Supply chain: new dependencies, major bumps, loosened pins, lockfiles, base images, build toolchain |
| Cost | Autoscaling limits, instance types, provisioned capacity, storage classes, quotas |
| Compliance | PII or privacy handling, audit trails, data residency, licence changes |
Each call-out names the area, a short headline, the files it comes from, the blast radius, and the one thing a reviewer should verify.
The path floor¶
The model is not the only source. Before the call, lgtmaybe matches the PR's
changed paths against deterministic patterns per area — *.tf,
.github/workflows/, alembic/, anything named for backups or retention,
lockfiles, and so on. Those matches do two jobs:
- they are sent to the model as untrusted hints, saying where to look (never that anything is wrong);
- they floor the output. An area whose files the model said nothing about is
still listed, marked
(not assessed by the model), so a weak model cannot make your Terraform change invisible.
The floor is also the fallback: if the call fails or returns nothing usable, the section renders the path signals alone under a "model assessment unavailable" note. It degrades — it never disappears.
When nothing qualifies, the section says so and names what it checked, rather than silently vanishing:
High Impact Areas¶
None detected — checked: infrastructure, security posture, availability, data migrations, backups and recovery, compatibility, observability, dependencies, cost, compliance.
Turning it off¶
The section is on by default. To drop it and its model call:
high_impact: false
The description section has its own switch, auto_describe: false. With both
off, the comment is just the diagrams, and costs one call.
Structure and sequence¶
The two diagrams answer different questions, which is why lgtmaybe draws both:
| Answers | Best on | |
|---|---|---|
| Flowchart (structure) | What does this change touch, and what talks to what? | Structural PRs — a component added, a dependency introduced, a service split |
| Sequence | What happens at run time, in what order, and where did that change? | Behavioural PRs — a retry added, an ordering fixed, a signal now handled |
Most pull requests are behavioural, and structure alone under-describes them: a
PR that fixes terminal restoration on SIGTERM might touch two files and draw
three boxes, while its sequence diagram — signal, flag set, loop exit, guard
dropped, terminal restored — is the explanation of the fix. A PR that puts a
cache in front of a service is the opposite: the new box is the headline, and
the flow shows how a request now reaches it.
The sequence view is omitted entirely when the change has no meaningful run-time flow — documentation, configuration, formatting — rather than inventing one. Both diagrams share one model call, one PR comment, and the same six-component budget; the sequence view adds at most eight ordered steps.
On GitHub: /diagram and auto_diagram¶
Comment /diagram on a pull request to post (or update in place) the change
overview. It's an idempotent upsert — re-running edits the same comment instead
of stacking new ones. (/describe still posts a description as its own separate
comment, for when that is all you want.)
auto_diagram is on by default — no workflow input or .lgtmaybe.yml
needed — so the overview posts automatically when a PR is opened or reopened and
refreshes after later pushes, keeping every section current with the head
commit. To opt out of the whole comment, set it in your workflow:
- uses: MattJColes/lgtmaybe@v2
with:
provider: anthropic
model: claude-sonnet-4-6
auto_diagram: "false"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
or in .lgtmaybe.yml:
auto_diagram: false
The description and High Impact Areas sections are best-effort: a failure there is logged, leaves a visible note in its slot, and never blocks the rest. The diagram itself is a required completion step, so a failed diagram leaves the commit un-finished and the next run redoes it rather than silently skipping it.
Locally: lgtmaybe diagram¶
lgtmaybe diagram prints the change overview of your local changes — no GitHub
involved:
$ lgtmaybe diagram --provider ollama --model llama3
It diffs your branch against the base (the same base resolution as lgtmaybe
review; --base overrides, --working includes uncommitted edits,
--uncommitted reviews only the working-tree edits). The output is the same
body the /diagram comment carries — description, High Impact Areas, then each
diagram's Mermaid source and its text rendering — with one adaptation: a
terminal renders no HTML, so the collapsible "Text version" wrapper is flattened
into a plain labelled section:
$ lgtmaybe diagram --provider ollama --model llama3
### Sequence
```mermaid
sequenceDiagram
participant n0 as Order API (changed)
participant n1 as Payments
n0->>n1: POST /charge
n1-->>n0: 503 Unavailable
n0->>n0: backs off 200ms
```
Text version:
```
1. [Order API (changed)] -> [Payments]: POST /charge
2. [Payments] --> [Order API (changed)]: 503 Unavailable
3. [Order API (changed)] -> [Order API (changed)]: backs off 200ms
```
The Mermaid source stays in the output on purpose: your terminal can't draw it, but it is what you paste into a GitHub comment, mermaid.live, or a Markdown file to render it.
Why Mermaid (and what the ASCII is for)¶
GitHub renders Mermaid natively in comments and Markdown — both flowcharts
and sequence diagrams — so a mermaid fence renders in the comment with no
image to generate or host. That matters for a pull_request_target reviewer:
hosting an image would mean committing a file or calling an external service,
neither of which fits a fork-safe, idempotently-updated comment.
A terminal, though, can't render Mermaid — which is exactly why each diagram also comes as plain text. In the GitHub comment that text sits in a collapsible "Text version" block, out of the way of the rendered diagram; in the terminal the same block is flattened to a labelled section, because HTML tags are noise in a shell. Either way the text is what you actually read without a renderer, and it doubles as the fallback body, so a reviewer never sees a red "unable to render" box if a diagram comes back malformed.
The model never writes Mermaid. It returns typed graph data — components, relationships, ordered steps — and lgtmaybe renders the syntax itself, escaping every label, so a diff that tries to smuggle diagram source or markup into a label can't reach the fence.
D2 isn't used because GitHub doesn't render it in Markdown, so it would show as source anyway.