magnate is a local package relationship graph visualizer. It reads the installed package database, builds a reverse dependency index, and opens a browser UI with an interactive Cytoscape.js graph.
It supports:
- Debian/Ubuntu packages through
dpkg-query(plusapt-cachefor not-installed packages) - Arch packages through
pacman - RPM-based systems through
rpm - Alpine packages through
apk - FreeBSD packages through
pkg - Experimental Nix store graph support through
nix-store - Dependency, reverse-dependency, and combined graph views
- Graphs that traverse into packages that are available in your repositories but not installed (deb), drawing them with a dashed outline
- Frozen system snapshots so you can explore another machine's package database without it
- A local Flask server bound to
127.0.0.1 - Ranked search/autocomplete over installed and available packages, a random-package button, package info, rich metadata, changelog, man page, tldr, and an optional AI summary tab
- Inline "package not found" errors with did-you-mean suggestions
- Progressive help through hover/focus tooltips and a compact data-source popover that shows the active resolver or snapshot
- Light/dark theme toggle that follows the system preference until a user chooses a theme
- Text commands for dependency trees, package info, docs, and metadata enrichment
Install the released package into an isolated environment with pipx:
pipx install magnateOr with pip:
python -m pip install magnateFor development, install from a checkout in editable mode with the test extras:
python -m pip install -e ".[dev]"Check the installed version with magnate --version.
Runtime dependencies are Python 3.11+, Flask, Typer, and Rich. Browser graph assets are vendored in magnate/server/static/, so the UI does not need a network connection after install.
The graph itself is local-first. Repology lookup, tldr page fetches, and AI changelog summaries are optional network features and degrade gracefully when unavailable. Set MAGNATE_OFFLINE=1 to prevent tldr network fetches. AI summaries require either ANTHROPIC_API_KEY or OPENAI_API_KEY; set MAGNATE_AI_PROVIDER=openai or MAGNATE_AI_PROVIDER=anthropic to choose when both are configured. Models are overridable with MAGNATE_OPENAI_MODEL and MAGNATE_CLAUDE_MODEL. The AI tab is hidden until you opt in from the ? menu in the UI.
On Debian/Ubuntu, magnate also reads apt-cache repository metadata, so the graph can expand into packages that are available in your configured repositories but not yet installed. Those packages are mapped without installing anything and are drawn with a dashed outline; if apt-cache is missing, graphs simply stay limited to installed packages.
Open the browser graph:
magnate less
magnate less --rdeps
magnate less --both --depth 6
magnate less --port 7337Use text output:
magnate deps less
magnate rdeps libc6 --depth 2
magnate info less
magnate changelog less
magnate manpage less
magnate tldr less
magnate repology less
magnate summarize lessManage the reverse dependency index:
magnate index status
magnate index buildResolver detection prefers deb, rpm, pacman, apk, freebsd, then nix. Use --resolver deb, --resolver rpm, --resolver pacman, --resolver apk, --resolver freebsd, or --resolver nix on commands that support it.
Instead of reading the live machine, magnate can use a frozen copy of another system's package database as its data layer. Capture one on the source machine (the resolver defaults to the detected host package manager):
magnate snapshot create --out laptop.tar.gz
magnate snapshot info laptop.tar.gzThe bundle captures the installed package database and the package-manager cache of available, not-installed packages, so the graph can still traverse into dependencies that aren't installed. No package manager actions are taken; capture is read-only.
Pass --snapshot to any data command to use a bundle instead of the host:
magnate open less --snapshot laptop.tar.gz
magnate deps bash --snapshot laptop.tar.gz --depth 3
magnate info htop --snapshot laptop.tar.gzA bundle is extracted once into the cache (keyed by its snapshot id) and reused thereafter; its reverse dependency index is namespaced separately so it never overwrites the live host's. Loading a snapshot still needs the matching package-manager binary present (e.g. dpkg-query/apt-cache for a deb bundle), since magnate redirects the real tool at the captured tree rather than reimplementing it.
| Resolver | What is captured | Redirection used |
|---|---|---|
deb |
dpkg status + info/*.list + apt package lists |
dpkg-query --admindir, apt-cache -o Dir::* |
pacman |
local/ database + sync/ databases |
pacman --dbpath |
rpm |
rpm database directory | rpm --dbpath |
apk |
lib/apk/db (installed database) |
apk --root |
freebsd |
local.sqlite + repo-*.sqlite |
pkg -o PKG_DBDIR= |
Nix is intentionally unsupported: its data layer is the content-addressed /nix/store referenced by absolute paths, which can't be relocated into a portable bundle the way a single database directory can.
Reverse dependency indexes live under:
~/.cache/magnate/<resolver>/rdep_index.sqlite
The cache stores the package database mtime and rebuilds when the local package DB changes. You can force a rebuild with magnate index build. Snapshots get their own namespace, ~/.cache/magnate/<resolver>-snapshot-<id>/, and are extracted under ~/.cache/magnate/snapshots/<id>/.
Optional enrichment caches live under:
~/.cache/magnate/repology/
~/.cache/magnate/tldr/
For dev/demo use from a checkout, run the source tree directly with one command:
./run-magnate
MAGNATE_DEMO_PACKAGE=bash ./run-magnate
./run-magnate deps lessWith no arguments, the runner opens a graph for less; set MAGNATE_DEMO_PACKAGE to choose a different default. The runner creates .venv when needed, installs runtime dependencies into it, and runs python -m magnate with the checkout on PYTHONPATH. It does not install magnate itself. During an interactive browser session, press r in the runner terminal to force the reverse dependency index to rebuild and restart the same command. If you already have dependencies available, python -m magnate ... also works from the repo root.
If the input is not an installed package name, magnate tries to treat it as an executable command and opens the package that owns it. For example, ./run-magnate top opens the package that installed top when the local package manager can report file ownership.
Run tests:
pytestThe current tests use fixture-style resolver data and parser samples so they do not require a specific Linux distribution. Future integration tests should be skipped when the matching package manager is unavailable.
magnate is read-only. It does not install, remove, or upgrade packages.
