Skip to main content
Version: 2.2

Overview

Dux Modular Shell

Overview

Dux Modular Shell's plugin system allows extending the desktop with custom widgets, dash tabs and cards, launchers, automation, and integrations through QML components.

Plugin Location​

Plugins are installed to ~/.config/dms/plugins/. Each plugin is a directory containing a plugin.json manifest and QML components.

Official plugins: github.com/duxlabs-dev/dux-plugins Plugin registry: plugins.duxlabs.dev Registry source: github.com/duxlabs-dev/dux-plugin-registry Example plugins: github.com/duxlabs-dev/dux-shell/tree/master/quickshell/PLUGINS

The plugin directory ranks plugins by community 👍 upvotes. Each plugin has a tracking issue in the registry you can upvote and discuss — see Contributing to the Registry.

Plugin Types​

Dux Modular Shell supports the following plugin types, defined in plugin.json. The plugin directory filters by the registry capability of each type, and several types can be combined (/plugins?type=dash-tab,dash-card).

Typeplugin.json typeRegistry capabilityDirectory
Bar widgetwidgetdankbar-widgetBrowse
Control center widgetwidgetcontrol-centerBrowse
LauncherlauncherlauncherBrowse
DaemondaemondaemonBrowse
Desktop widgetdesktopdesktop-widgetBrowse
Dash tabdashdash-tabBrowse
Dash carddashCarddash-cardBrowse
Compositecompositeone per surface

1. Bar Widget (type: "widget")​

Widgets that appear in the bar and in docks. Define horizontalBarPill and verticalBarPill components for different bar orientations. In a dock, a widget can also open an attached panel inside the dock instead of a popout.

Capabilities:

  • dankbar-widget - Appears in the bar and docks

Example use cases: System monitors, media controls, weather widgets, clock displays

2. Control Center Widget (type: "widget")​

Widgets that appear in the Control Center quick settings panel. Define ccWidget* properties for toggle buttons and detail panels.

Capabilities:

  • control-center - Appears in Control Center

Example use cases: VPN toggles, custom shortcuts, service controls

3. Launcher Plugin (type: "launcher")​

Extends the application launcher with custom searchable items. Define getItems() and executeItem() functions.

Capabilities:

  • launcher - Adds items to Spotlight search

Required fields:

  • trigger - Trigger string for filtering (e.g., "#", "!", "" for always-visible)

Example use cases: Emoji picker, calculator, web search, custom actions

4. Daemon (type: "daemon")​

Background services with no UI. Run automation, monitoring, or provide services to other plugins.

Capabilities:

  • daemon - Background service
  • watch-events - React to system events

Example use cases: Battery alerts, wallpaper automation, notification handlers

5. Desktop Widget (type: "desktop")​

Widgets that render directly on the desktop background layer using Wayland's wlr-layer-shell protocol. Users can drag them anywhere and resize via corner handles.

Capabilities:

  • desktop-widget - Appears on the desktop layer and can be added to the lock screen

Features:

  • Free positioning anywhere on desktop
  • Resizing with minimum size constraints
  • Multi-monitor support with independent positions per screen
  • Position/size persistence across sessions
  • Reusable on the lock screen with separate instances and geometry (see Lock Screen)

Example use cases: Desktop clock, system monitor, weather widget, sticky notes

6. Dash Tab (type: "dash")​

A full tab in the dash popout, next to Overview, Media, Wallpapers and Weather. It shows up in the tab bar as soon as the plugin is enabled, and you can hide or reorder it under Settings → Dashboard.

Capabilities:

  • dash-tab - Adds a dash tab

Example use cases: Timers, dashboards for a service, notes, anything that needs more room than a popout

7. Dash Card (type: "dashCard")​

A card in the dash Overview grid. Add it from the dash (three-dot menu → Edit → Add widget), then drag and resize it like the built-in cards.

Capabilities:

  • dash-card - Adds an overview card

Example use cases: At-a-glance stats, progress, counters, quick actions

Dash tabs and cards require DMS ≥ 2.0.0. A plugin can ship both; clicking the card then opens the tab.

8. Composite Plugin (type: "composite")​

A single plugin that provides several of the above surfaces at once — for example a daemon plus a bar widget plus a desktop widget. Instead of one component, it declares a components map pointing each surface at its own QML file.

Features:

  • Any combination of widget, desktop, daemon, launcher, dash, and dashCard surfaces
  • One settings UI and one settings namespace shared across all surfaces
  • Shared runtime state via plugin global variables or the daemon instance

Example use cases: A monitor daemon that also shows a bar pill and a desktop tile; an integration that exposes both a launcher and a background watcher; a timer with a bar pill, a dash tab and an overview card

Composite plugins require DMS ≥ 1.5.0. See the development guide for details.

Installation​

From GitHub​

mkdir -p ~/.config/dms/plugins
cd ~/.config/dms/plugins
git clone https://github.com/author/plugin-name
dms restart

From Plugin Registry​

Browse plugins.duxlabs.dev for installation links and documentation.

From the Plugin Browser​

Open Settings → Plugins and click Browse. The browser lists every plugin of the configured registries and installs one with a click.

Finding a plugin

  • Pick of the week and Pick of the day highlight one plugin each. They are chosen from the registry list on your machine and change by themselves.
  • Three shelves sit above the full list: For you (plugins close to the ones you already installed: same categories, same authors), Trending (recent upvotes and updates) and New (latest arrivals).
  • Quick filters narrow the list: Hide installed, Installed first, Works here (plugins that support your compositor), New & updated and Official only.
  • Search forgives typos, so walpaper still finds wallpaper plugins. When nothing matches, Did you mean offers the closest plugins.
  • Cards carry new and updated marks, and tell you when a plugin targets another compositor.

Everything above is computed locally from the registry list. Nothing about your installed plugins is sent anywhere.

The detail page

Click a card to open its detail page:

  • This plugin can lists the permissions the plugin declares, in plain words.
  • Needs lists the commands the plugin requires and marks the ones that are not found on your machine.
  • The links open the source, the discussion, a pre-filled problem report, or copy a link to the plugin.
  • Click the author to list all of their plugins.

Upvoting

The 👍 count on a card and on the detail page is a button. With the GitHub CLI installed and logged in (gh auth login), a click adds your upvote to the plugin's tracking issue and a second click takes it back. Without it, DMS opens the tracking issue in your web browser instead.

Undoing an uninstall

After you uninstall a registry plugin, the Plugins page shows <name> uninstalled, Undo for a few seconds. Undo installs the plugin again from the registry and turns it back on if it was enabled.

Reproduce Managed Plugins​

DMS keeps ~/.config/dms/plugins.lock.json synchronized when registry plugins are installed, updated, or removed. The lockfile records each Git repository, optional monorepo path, and exact commit.

# Refresh the lockfile and optionally export a copy
dms plugins lock
dms plugins lock --output ~/plugins.lock.json

# Install or reset plugins to the exact locked commits
dms plugins restore ~/plugins.lock.json

# Also remove managed plugins that are absent from the lockfile
dms plugins restore ~/plugins.lock.json --prune

The lockfile covers DMS-managed Git plugins. It does not include system plugins, plugin settings, enablement state, or local plugin directories without Git provenance.

Enable Plugin​

  1. Open Settings → Plugins
  2. Click Scan for Plugins
  3. Toggle the plugin on
  4. Add to bar layout if applicable
  5. Restart shell: dms restart

Custom Registries​

DMS fetches installable plugins and themes from registries — Git repositories containing plugins/ and/or themes/ directories in the registry format. The official registry is always active and additional registries can be added alongside it, unless an administrator disables registries.

Requires DMS ≥ 1.6.0.

Managing Registries​

GUI: Settings → Plugins → Registries — add a registry by name and Git URL, or remove one. The official registry cannot be removed.

CLI:

# Show configured registries
dms registry list

# Add a registry by name and Git URL
dms registry add myregistry https://github.com/user/my-registry.git

# Remove a registry
dms registry remove myregistry

Additional registries are stored in ~/.config/dms/registries.json. Names are short lowercase identifiers (letters, digits, hyphens) and become the local cache directory for that registry.

Resolution Order​

Registries are consulted in declaration order, official first. When two registries provide the same plugin or theme ID, the first occurrence wins — a custom registry cannot override an official entry. An unreachable registry is skipped so the remaining registries keep working.

Registry Format​

A registry is a Git repository with either or both of:

  • plugins/*.json — one plugin manifest per file
  • themes/<theme-id>/theme.json — one directory per theme

A registry can provide only plugins, only themes, or both. See dms-plugin-registry for the manifest schema.

Plugins run with full desktop session permissions. Only add registries you trust.

Disabling Registries​

An administrator can turn off every registry, the official one included, with the disable_registries key in /etc/dms/cli-policy.json:

{
"policy_version": 1,
"disable_registries": true
}

Distributions can ship the same key in /usr/share/dms/cli-policy.json; when both files set it, /etc/dms/cli-policy.json wins.

With the key set, DMS never clones or pulls a registry. Installed plugins and themes keep working, and dms plugins update still updates plugins that have their own Git checkout or a lockfile entry. Browsing, installing from a registry and registry-based update checks, including the update buttons in Settings, stop working. Registries added with dms registry or in Settings stay in registries.json but have no effect.

Requires DMS ≥ 2.0.0.

Administrator Lock Policy​

An administrator can stop DMS's own interfaces from ending or weakening a lock with these keys in /etc/dms/cli-policy.json. Each key is off unless set to true:

{
"policy_version": 1,
"disable_lock_ipc_unlock": true,
"disable_logind_unlock": true,
"disable_custom_lock_pam": true,
"disable_user_plugins": true,
"disable_settings_ipc_set": true
}
KeyWhen true
disable_lock_ipc_unlockdms ipc call lock unlock, forceReset and demo do nothing, and the keybind editor no longer offers Lock Screen: Demo.
disable_logind_unlockA logind Unlock (loginctl unlock-session, SetLockedHint(false) or the DMS socket's loginctl.unlock) neither ends nor cancels a lock.
disable_custom_lock_pamPassword unlock uses /etc/pam.d/dankshell, or /etc/pam.d/login when it is missing. Fingerprint uses only /etc/pam.d/dankshell-fprint and security keys only /etc/pam.d/dankshell-u2f; a factor whose service is missing is unavailable, so AND mode then unlocks with the password alone and logs a warning. Custom PAM sources, Use system PAM authentication and the generated stack in the user state directory are ignored.
disable_user_pluginsOnly plugins in /etc/xdg/quickshell/dms-plugins load. The user plugin directory is neither read nor watched; plugins installed from the plugin browser are written there and do not load.
disable_settings_ipc_setdms ipc call settings set returns SETTINGS_SET_DISABLED and changes nothing. get, dump and dumpSession keep working, and the Settings UI and settings.json still apply.

Distributions can ship the same keys in /usr/share/dms/cli-policy.json; when both files set a key, /etc/dms/cli-policy.json wins. dms run reads the keys each time it starts the shell, so a change applies at the next shell start or restart. If either file exists but cannot be read or parsed, every key above is treated as true.

With disable_lock_ipc_unlock, dms ipc call lock unlock is no longer a way out of a lock that cannot authenticate, so test the PAM setup before setting it.

With disable_custom_lock_pam, the administrator provides the services. dms auth sync writes dankshell and dankshell-u2f, except on NixOS, and never writes dankshell-fprint; base that one on the bundled assets/pam/fprint in the shell directory and keep its max-tries=1 timeout=90. The shell checks which services exist when it starts, and checks dankshell-u2f again at each lock. Keep a root shell open while testing.

These keys constrain DMS's own interfaces. They are not a boundary against other programs running as the same user, and a shell started without dms run does not see them.

Available starting with the DMS release following 2.0.0.

Managed Lock Settings​

The lock_settings object holds values for lock settings that the user cannot change. Its keys are DMS setting names:

{
"policy_version": 1,
"lock_settings": {
"lockBeforeSuspend": true,
"loginctlLockIntegration": true,
"customPowerActionLock": "",
"acLockTimeout": 300,
"batteryLockTimeout": 300,
"enableFprint": true
}
}
SettingValue
customPowerActionLockCommand run instead of the DMS lock screen; "" uses the lock screen
lockBeforeSuspendtrue or false
loginctlLockIntegrationtrue or false
lockAtStartuptrue or false
acLockTimeout, batteryLockTimeoutIdle seconds before locking; 0 never locks
fadeToLockEnabledtrue or false
fadeToLockGracePeriodSeconds
enableFprinttrue or false
maxFprintTriesFingerprint attempts
enableU2ftrue or false
u2fMode"or" lets the security key unlock on its own, "and" requires it after the password or fingerprint

A managed setting:

  • wins over settings.json and every file in config.d, including edits made while DMS runs;
  • is never written to a settings file. A value the user set before stays in its file and applies again once the setting is no longer managed;
  • shows in Settings as Managed by administrator policy, with its control disabled;
  • makes dms ipc call settings set return SETTINGS_SET_MANAGED, whether or not disable_settings_ipc_set is set;
  • is left alone by the migration of a legacy session.json.

On the DMS socket, loginctl.setLockBeforeSuspend refuses any value but a managed lockBeforeSuspend, and loginctl.setSleepInhibitorEnabled refuses any value but the one a managed lockBeforeSuspend and loginctlLockIntegration decide. Manage both to keep lock before suspend in force.

Settings in /usr/share/dms/cli-policy.json apply first, and /etc/dms/cli-policy.json overrides them one setting at a time; null counts as not set. Other keys in lock_settings are ignored, and so is a value whose type differs from the setting's default, such as "true" for lockBeforeSuspend; both are logged as warnings. If either file exists but cannot be read or parsed, DMS logs an error and manages no setting, so the user's settings apply; the disable_* keys still all turn on.

Available starting with the DMS release following 2.0.0.

Official Plugins​

Maintained by the Dux Modular Shell team at dms-plugins:

  • Dank Actions - Scriptable bar buttons and control center tiles
  • Dank Hooks - Event-based automation triggers
  • Dank Pomodoro Timer - Focus timer with notifications
  • Dank Battery Alerts - Battery threshold warnings

Community Plugins​

Third-party plugins submitted to the registry at plugins.duxlabs.dev:

  • WallpaperShuffler - Automatic wallpaper rotation
  • WorldClock - Multi-timezone clock widget
  • PowerUsage - Real-time power consumption monitor
  • Calculator - Launcher-based calculator

Always review plugin source code before installation. Plugins run with full desktop session permissions.

Development​

See Plugin Development for the complete development guide including:

  • Plugin manifest structure (plugin.json)
  • Component architecture
  • PluginService API
  • Settings components
  • Bar, dock and Control Center integration
  • Dash tabs and overview cards
  • Launcher plugin development
  • Global variables and state management
  • Plugin translations (translations/ + I18n.trFor)

Translations​

Plugins carry their own translations — a translations/ directory in the plugin repo with one JSON file per locale. DMS picks the file matching your locale automatically and updates live when you switch languages in Settings → Locale. Nothing to configure as a user; if the plugin ships your language, you get it.

For plugin authors: see Translations in the development guide for the file format and the I18n.trFor API. Registry plugins can also apply for central translation through the same POEditor project that translates DMS itself.

Example Plugins​

Reference implementations in the main repository:

Plugin Registry Submission​

To add your plugin to the registry:

  1. Create a public GitHub repository
  2. Include plugin.json, README, and screenshots
  3. Validate manifest against plugin-schema.json
  4. Submit PR to dms-plugin-registry
  5. Site rebuilds automatically on merge

Troubleshooting​

Plugin not detected:

  • Verify plugin.json syntax with jq .
  • Check directory is in ~/.config/dms/plugins/
  • Click "Scan for Plugins" in Settings

Plugin won't load:

  • Check logs: dms kill && dms run from terminal
  • Verify component paths in plugin.json
  • Ensure dependencies are installed

Settings not working:

  • Add "permissions": ["settings_write"] to manifest
  • Use PluginSettings wrapper component
  • Check PluginService is injected properly

Next Steps​