Whatever your release process looks like, at some point the release gets summarised as a list of work items. It might be read out in a sign-off meeting, pasted into a handover to the ops team, or attached to a change ticket. Mine is a handover document. The list is useful, but it’s essentially a list of intentions. A title says what a story set out to do. It doesn’t say which parts of the system the code touched, what depends on those parts, or that the some component has been quietly hiding away in there.
I wrote [ ChangeAtlas ] to take the guesswork out of that, after combining some experiments that I had been trying out. You point it at the tracker query for a release (an ADO query in my case) and it gives you one HTML file: a dependency graph of your system, coloured in by what the release did to it. This is the sample that ships with it, a made-up web shop:



AI once, deterministic forever
You use your own AI agent (Claude Code, Cursor, Copilot — the repo ships the prompts) to scan your repos and produce a JSON graph of components and dependencies: the atlas. You curate it by hand, check it in, and it never regenerates behind your back. From then on, every release is deterministic: work items, pull requests, and changed file paths go in; shading comes out. Same input, same map. No AI at render time means no hallucinated components in a report you’re signing releases off against; and nothing sent to a model at render time either.

Five tiers, and what they refuse to count
Every component lands in exactly one tier, decided by production files only:
- Changed – enough production files matched to call it a real change (threshold is tunable).
- Touched – some production evidence, below the threshold.
- Test-only – test files moved, production didn’t. Worth a raised eyebrow either way.
- Peripheral – not modified, but one dependency edge away from a changed component. This amber ring is your regression shortlist.
- Untouched – dimmed, but still on the map, because shape is context.
Just as telling is what deliberately doesn’t shade. A NuGet version bump never lights a component up – lockfiles and project manifests don’t count as evidence. Database nodes shade only on schema evidence (migrations, SQL, model snapshots), never on ordinary data-access churn. And a repo’s catch-all glob can’t spread the peripheral ring, so one sprawling repo doesn’t turn the whole map amber. False alarms are how testers learn to ignore a dashboard; the refusals matter as much as the shading.
There are three views – the impact map, a plain system-architecture view, and a keyboard-navigable list view (the page targets WCAG 2.2 AA; the list view is the accessible equivalent of the canvas). Legend pills toggle tiers into the background rather than deleting them, there’s a dark/light theme that follows your OS, and an Export to Obsidian button that turns the current view into a vault – one wikilinked note per component, with graph-view colour groups preset to match the map. You can also export to PNG to embed into other collateral.

Try it in two lines
No pip installs, no tokens — the sample runs entirely offline:
git clone https://github.com/jholsgrove/ChangeAtlas && cd ChangeAtlaspython -m changeatlas --sample
Or skip even that: the [ live demo ] is the same sample, rebuilt from main on every push. Azure DevOps is supported out of the box; any other tracker works by producing one documented JSON file. There’s also an --anonymize flag that keeps a real release’s shape while replacing every name and link – handy for demos of maps you can’t show.
Or set it up with your agent. Whatever set up you have, get your agent to work with it and submit a pull request.
The honest caveats
The map is only as good as the atlas. The AI-drafted graph needs human curation, it is worth spending time here to get it right, and the file-to-component glob map needs maintaining as the codebase moves – there’s a --check-map validator, but it’s a gardening job, not a one-off. And tier thresholds are judgement calls: three production files might be a real change in one codebase and noise in another, which is why it’s a flag and not a constant.
ChangeAtlas is MIT-licensed and on GitHub. If you try it on your own system’s atlas, let me know how it goes. I would love to invite collaborators to submit pull requests so that it supports all kinds of different set ups.
Update
Newly added large system mode. Check out the demo here: [ 100 repo system ]



















