GNOME Shell extension¶

The Meta Package Manager project maintains a GNOME Shell extension.

A top bar indicator lists the outdated packages reported by mpm outdated across every package manager on the system, and lets you upgrade them one by one or per manager. The mpm CLI is installed separately: see Installation.

Each outdated package carries its version diff colored with the same convention as mpm outdated: unchanged prefix in gray, installed-version suffix in red, latest-version suffix in green.

The extension looks for mpm on the session PATH, then in well-known locations (~/.local/bin, /usr/local/bin, Linuxbrew), and a custom launcher (like uv run mpm) can be configured in its settings. mpm 6.4.0 or newer is required.

Requirements¶

  • GNOME Shell 46 to 50.

  • The mpm CLI, 6.4.0 or newer, reachable from the GNOME session.

  • For upgrades run in a terminal: any of xdg-terminal-exec, Ptyxis, Console (kgx) or GNOME Terminal, or a custom terminal command set in the extension settings.

Installation¶

From extensions.gnome.org¶

The extension is published at extensions.gnome.org/extension/10714/meta-package-manager, for GNOME Shell 46 to 50.

The Install button on that page needs GNOME Shell integration on the host. The site describes it as “two parts: browser extension and native host messaging application”. Most distributions package the second part as gnome-browser-connector. Without both, the button reports the integration as missing.

Two other routes reach the same catalog and need neither part. Extension Manager browses and installs it from a desktop application. gext, one of the managers mpm wraps, installs it from a shell:

$ gext install [email protected]

From a release zip¶

Every GitHub release carries the packed extension as a mpm-gnome-shell-extension.zip asset, next to the mpm binaries. Its provenance is attested, so you can verify it was built by this project’s release pipeline before installing:

$ gh attestation verify mpm-gnome-shell-extension.zip --repo kdeldycke/meta-package-manager --signer-repo kdeldycke/repomatic

Then install it:

$ gnome-extensions install --force mpm-gnome-shell-extension.zip

Important

A running GNOME Shell does not pick up a freshly installed extension, and gnome-extensions enable asks the shell rather than the disk. Run it too early and it answers Extension "mpm@kdeldycke.github.io" does not exist, however successful the install was. Restart the session first.

A Wayland session cannot restart the shell in place, so end the session and log back in:

$ gnome-session-quit --logout --no-prompt

An X11 session can restart the shell alone, from the Alt+F2 prompt: type r, then Enter.

Once the shell is back, enable the extension:

$ gnome-extensions enable [email protected]

State: ACTIVE confirms the shell loaded it:

$ gnome-extensions info [email protected]
[email protected]
  Name: Meta Package Manager
  (...)
  Enabled: Yes
  State: ACTIVE

Between releases, the bleeding-edge equivalent is produced on each extension change as a workflow artifact of tests-gnome-extension.yaml.

From a source checkout¶

$ git clone https://github.com/kdeldycke/meta-package-manager.git
$ cd ./meta-package-manager
$ glib-compile-schemas "gnome-shell/[email protected]/schemas/"
$ ln -snf "$(pwd)/gnome-shell/[email protected]" ~/.local/share/gnome-shell/extensions/

Restart the session as above, then enable it:

$ gnome-extensions enable [email protected]

Configuration¶

Settings live in the extension preferences window, also reachable from the indicator menu:

Setting

Description

Type

Default

group-by-manager

Group each manager’s packages into a section of its own.

Boolean

true

align-columns

Center each version pair around its arrow, monospaced.

Boolean

true

check-interval

Minutes between two package checks.

Integer

420

boot-wait

Seconds before the first check after login.

Integer

30

timeout

Seconds passed to mpm --timeout for background checks.

Integer

60

mpm-command

Custom mpm launcher, empty to autodetect.

String

Empty

mpm-options

Extra options for every mpm call, before the subcommand.

String

Empty

always-visible

Show the indicator even when everything is up to date.

Boolean

true

show-count

Show the outdated package count next to the icon.

Boolean

true

notify

Desktop notification when new outdated packages appear.

Boolean

false

upgrade-in-terminal

Run upgrades in a terminal window.

Boolean

true

terminal-command

Custom terminal emulator, empty to autodetect.

String

Empty

post-upgrade-recheck

Seconds before refreshing the list after an upgrade is started.

Integer

300

These settings drive the menu layout, the check cadence and how mpm is called: everything else comes from mpm’s own configuration file, which applies to every run the extension triggers. See Configuration for the search paths and the full schema.

mpm-options goes after the extension’s own options, so an option set twice takes the value given here. That includes --verbosity, which the extension sets to CRITICAL to list the outdated packages. A raised level never hides that list: only the exit status of mpm marks a check as failed. A successful check drops what mpm wrote to standard error. An upgrade run in a terminal shows its log there.

The About group at the foot of the window names two versions. The first is the extension’s own, compiled into its metadata.json. The second is the mpm release the extension resolved, with the command that answered it below. The two ship separately, so a bug report needs both.

The PATH the extension sees¶

GNOME Shell starts the extension with the environment of the session, which the systemd user manager builds from environment.d and, on some distributions, ~/.profile: it never reads .bashrc or .zshrc. A manager installed under the home directory, or a PATH entry exported from those files, is then invisible to mpm, and so is the global bin directory of pnpm, without which pnpm refuses its global commands.

The extension therefore passes --shell-env to any mpm from 8.0.0 on, for the checks and for the upgrade actions alike. mpm runs the login shell once, as an interactive login shell, adopts the environment it exports, and only then looks for managers. The shell has ten seconds to answer, past which mpm keeps the environment it started with. Add --no-shell-env to mpm-options to opt out.

The alternative fixing every desktop program at once is a ~/.config/environment.d/50-path.conf file carrying the PATH line, which systemd reads at login.

Panel icons¶

State

Adwaita

Yaru

Icon name

Shown when

Unknown

content-loading-symbolic

Before the first check of the session.

Checking

view-refresh-symbolic

While a check is running.

Up to date

selection-mode-symbolic

No selected manager reports an upgrade.

Updates available

software-update-available-symbolic

Packages can be upgraded. Also marks each Upgrade all row.

Error

software-update-urgent-symbolic

A check failed, or no runnable mpm was found.

Manager failed

dialog-warning-symbolic

On the sub-menu header of a manager that reported errors.

See the full Adwaita and Yaru icon lists.

Screenshots¶

Every layout, photographed from a real GNOME session driven by docs/gnome_screenshots_update.py and refreshed by docs-screenshots.yaml whenever the extension changes. Each one is captured in both shell appearances, so the two are there to be compared rather than picked for you: the shell restyles its menu with the desktop’s light or dark preference, and the version diff has to keep its colors legible on both. The tabs are synchronized, so switching one switches the other.

The report scrolls past a set height instead of growing the menu to the screen, and the flat captures show that as it is: the list stops at its fold, under a scrollbar, and the sections below it are reached with the wheel.

The extension's menu with one section per package manager, the first one unfolded, the failing one carrying a warning icon, each version pair centered on its arrow in a monospaced font
group-by-manager = true
align-columns = true
(default)
/_images/gnome-shell-grouped-table-rendering-light.png
The extension's menu with one section per package manager, the first one unfolded, the failing one carrying a warning icon, each version pair flush right in the menu font
group-by-manager = true
align-columns = false
/_images/gnome-shell-grouped-standard-rendering-light.png
The extension's menu listing outdated packages inline, one header per package manager, with one manager's error shown in red, each version pair centered on its arrow in a monospaced font
group-by-manager = false
align-columns = true
/_images/gnome-shell-flat-table-rendering-light.png
The extension's menu listing outdated packages inline, one header per package manager, with one manager's error shown in red, each version pair flush right in the menu font
group-by-manager = false
align-columns = false
/_images/gnome-shell-flat-standard-rendering-light.png
The extension's menu with one section per package manager, the first one unfolded, the failing one carrying a warning icon, each version pair centered on its arrow in a monospaced font
group-by-manager = true
align-columns = true
(default)
/_images/gnome-shell-grouped-table-rendering-dark.png
The extension's menu with one section per package manager, the first one unfolded, the failing one carrying a warning icon, each version pair flush right in the menu font
group-by-manager = true
align-columns = false
/_images/gnome-shell-grouped-standard-rendering-dark.png
The extension's menu listing outdated packages inline, one header per package manager, with one manager's error shown in red, each version pair centered on its arrow in a monospaced font
group-by-manager = false
align-columns = true
/_images/gnome-shell-flat-table-rendering-dark.png
The extension's menu listing outdated packages inline, one header per package manager, with one manager's error shown in red, each version pair flush right in the menu font
group-by-manager = false
align-columns = false
/_images/gnome-shell-flat-standard-rendering-dark.png

Development workflow¶

The extension lives in the gnome-shell/ directory of the mpm repository and shares its version, release cycle and issue tracker.

Its logic is split in two: extension.js owns the widgetry while mpm.js is shell-free (it never imports resource:///org/gnome/shell/* modules), so the latter runs under a bare gjs interpreter:

$ gjs -m tests/gnome/run-tests.js
ok 1 - parseVersion nominal
(...)

Static invariants (metadata, GSettings schema, stylesheet and icon drift) are enforced by tests/test_gnome_extension.py in the regular Python test suite. The tests-gnome-extension.yaml workflow runs the gjs suite, checks the sources with shexli (the static analyzer extensions.gnome.org applies to every upload), packs the installable zip with gnome-extensions pack, and proves it installs with a gnome-extensions install round-trip.

Todo

Drop the tree-sitter==0.25.2 pin the shexli job carries once the analyzer caps that dependency itself. shexli declares tree-sitter>=0.25.0 with no ceiling, so a fresh install pairs core 0.26.0 with the 0.25.0 grammar, the newest tree-sitter-javascript published, and that pair segfaults on this extension every time. Tracked upstream as Infrastructure/extensions-web#398.

Its eslint job holds the JavaScript to GNOME Shell’s own coding style, with the eslint-config-gnome rules declared by gnome-shell/eslint.config.mjs and pinned to the commit gnome-shell itself pins. No package.json or lockfile is committed: nobody would keep one refreshed, so the ESLint stack floats and a 7-day npm --min-release-age window gates the whole resolved tree, the same supply-chain guard mpm --cooldown applies to the packages mpm installs.

To exercise the extension in a real session, install it from your checkout (see above), then run a nested GNOME Shell so crashes and reloads stay contained:

$ dbus-run-session -- gnome-shell --nested --wayland

Logs are visible with:

$ journalctl --follow --output=cat /usr/bin/gnome-shell

Release process¶

The extension version is advertised through the version-name field of metadata.json, kept in lockstep with the mpm version by bump-my-version.

If the extension changed between releases, a fresh zip is uploaded to extensions.gnome.org for review. Reviews there are manual and can take a while.

Changelog¶

  • 8.0.2 (2026-09-28)

    • Publish the extension on extensions.gnome.org, for GNOME Shell 46 to 50.

    • Keep the sync progress trail out of the host app’s log, by turning it off on the refresh cycle.

  • 8.0.0 (2026-09-20)

    • Breaking: Rename the grouped-layout setting to VAR_GROUP_BY_MANAGER in the plugin and group-by-manager in the extension, from VAR_SUBMENU_LAYOUT and submenu-layout, and turn it on by default. A configuration still using the old name gets the default.

    • Pass --shell-env to mpm 8.0.0 and newer, so the menu lists the managers installed under the home directory and pnpm’s global packages.

    • Name the package of each upgrade action with a pURL of its manager, so mpm no longer looks it up in the installed packages first.

    • Offer uv tool install --upgrade meta-package-manager when no mpm is found, beside an entry opening the installation page for the systems uv does not answer for.

    • Split a version diff at the same point in both frontends, and highlight only the new token when one version is the other plus a whole token: 14ubuntu6 → 14ubuntu6.1 highlights .1 alone.

    • Center the menu’s version pairs around their arrow, mirroring the plugin’s VAR_ALIGN_COLUMNS, with an align-columns setting to switch it off.

    • Add an mpm-options setting, extra options spliced into every mpm call the extension makes, and report the resolved mpm release and command in the preferences window.

    • Render every panel state and menu marker with a stock symbolic icon, in place of four bundled SVGs and the 🆙 and ⚠️ emoji, and mark a running check with a refresh icon and a greyed Checking… row.

    • Render each package row’s version diff as one label instead of five, so a report of a thousand packages scrolls smoothly, and each version as one string, closing the gap that split 5.0.0~beta1-0ubuntu7.

    • Refresh the package list as soon as a background upgrade exits, instead of waiting out the re-check delay.

    • Scroll the package list with the wheel while a manager’s submenu is expanded, drop the expander arrow from a manager with nothing to report, and drop the blank band shown above Checking… before the first report.

    • Pack the extension from the commit being released, and bundle the license in it: v7.6.1 shipped a zip advertising 7.6.2.dev0 as its version-name.

    • Mark a package check as failed on the exit code of mpm only, so a --verbosity raised in the options no longer replaces the package list with log lines.

    • Fix a gnome-shell crash when a setting changed while a manager’s submenu was open in the grouped layout.

    • Fix a check still in flight outliving disable(), which left a main loop source free to fire on a locked session.

    • Publish the documentation at https://mpm.run, hosted on Cloudflare Pages. Every link in the readme, the benchmark, the packaging specs and both frontends points at the new origin, and the former kdeldycke.github.io URLs redirect to it.

    • Give each frontend page a release history of its own, built from the changelog entries scoped to it, and make each page self-contained: what a click runs, where its settings stop and mpm’s configuration starts, the version-diff colors.

    • Illustrate the extension’s page with screenshots of its menu in both layouts and both shell appearances, captured from a real headless GNOME session by the new docs-screenshots.yaml workflow.

    • Restart the GNOME session before enabling the extension, in the documented installation steps: gnome-extensions enable asks the running shell rather than the disk.

  • 7.6.0 (2026-08-10)

    • Add a GNOME Shell extension (GNOME 46 to 50) mirroring the SwiftBar/Xbar plugin: a top bar indicator lists outdated packages per manager, and every menu action runs mpm itself. Addresses #809.

    • Attach the packed extension to every GitHub release as an attested mpm-gnome-shell-extension.zip asset, built with gnome-extensions pack.

    • Lint the extension and its gjs test runner with ESLint against GNOME Shell’s own eslint-config-gnome ruleset, in a new eslint job installing the stack behind a 7-day npm --min-release-age cooldown.