Skip to main content

dms-plugin-dev

Develop plugins for DankMaterialShell (DMS), a QML-based Linux desktop shell built on Quickshell. Supports widget (bar, dock + Control Center), daemon (background service), launcher (search + actions), desktop (draggable desktop widgets), dash (dash tab), dashCard (dash overview card), and composite (multi-surface) plugins. Covers manifest creation, QML component development, startup checks, settings UI, data persistence, theme integration, PopoutService usage, IPC runtime discovery, and external command execution. Use when the user wants to create, modify, or debug a DMS plugin, or asks about the DMS plugin API.

Datos de origen

Repositorio
AvengeMedia/DankMaterialShell
Última actividad en el origen
17 de septiembre de 2026 a las 20:51
Idioma detectado de SKILL.md
inglés
Estrellas
8400
Forks
547

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
29 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
dms-plugin-dev
description
Develop plugins for DankMaterialShell (DMS), a QML-based Linux desktop shell built on Quickshell. Supports widget (bar, dock + Control Center), daemon (background service), launcher (search + actions), desktop (draggable desktop widgets), dash (dash tab), dashCard (dash overview card), and composite (multi-surface) plugins. Covers manifest creation, QML component development, startup checks, settings UI, data persistence, theme integration, PopoutService usage, IPC runtime discovery, and external command execution. Use when the user wants to create, modify, or debug a DMS plugin, or asks about the DMS plugin API.
compatibility
Designed for Claude Code (or similar products)
metadata
{"author":"DankMaterialShell","version":"1.2","domain":"qml-desktop-development","framework":"DankMaterialShell","languages":"qml, javascript"}
allowed-tools
Bash Read Write Edit
# DankMaterialShell Plugin Development ## Overview DMS plugins extend the desktop shell with bar and dock widgets, background services, launcher integrations, desktop widgets, and dash tabs and cards. Plugins are QML components discovered from `~/.config/DankMaterialShell/plugins/`. **Minimum plugin structure:** ``` ~/.config/DankMaterialShell/plugins/YourPlugin/ plugin.json # Required: manifest with metadata YourComponent.qml # Required: main QML component YourSettings.qml # Optional: settings UI *.js # Optional: JavaScript utilities ``` **Plugin registry:** Community plugins are available at https://plugins.danklinux.com/ **Plugin types:** | Type | Purpose | Base Component | Bar/dock pills | CC integration | |-------------|--------------------------------|----------------------------|----------------|----------------| | `widget` | Bar or dock widget + popout | `PluginComponent` | Yes | Yes | | `daemon` | Background service | `PluginComponent` (no UI) | No | Optional | | `launcher` | Searchable items in launcher | `Item` | No | No | | `desktop` | Draggable desktop widget | `DesktopPluginComponent` | No | No | | `dash` | Tab in the dash popout | `DashTabComponent` | No | No | | `dashCard` | Card in the dash overview grid | `DashCardComponent` | No | No | | `composite` | Multi-surface plugin | One component per surface | Optional | Optional | ## Step 1: Determine Plugin Type Choose the type based on what the plugin does: - **Shows in the bar or a dock?** - Use `widget`. Displays a pill in DankBar or a dock (same component), optionally opens a popout or an attached dock panel, optionally integrates with Control Center. - **Runs in background only?** - Use `daemon`. No visible UI, reacts to events (wallpaper changes, notifications, battery level, etc.). - **Provides searchable/actionable items?** - Use `launcher`. Items appear in the DMS launcher with trigger-based filtering (e.g., type `=` for calculator, `:` for emoji). - **Shows on the desktop background?** - Use `desktop`. Draggable, resizable widget on the desktop layer. - **Full page in the dash?** - Use `dash`. A tab in the dash popout, id `plugin_<pluginId>`. - **Small tile on the dash overview?** - Use `dashCard`. A resizable card in the overview grid. - **Needs multiple surfaces?** - Use `composite`. A single plugin that registers any combination of the above (e.g., a daemon + bar widget + desktop widget). Each surface gets its own QML component file. ## Step 2: Create the Manifest Create `plugin.json` in your plugin directory. See [plugin-manifest-reference.md](references/plugin-manifest-reference.md) for the full schema. **Minimal manifest:** ```json { "id": "yourPlugin", "name": "Your Plugin Name", "description": "Brief description of what your plugin does", "version": "1.0.0", "author": "Your Name", "type": "widget", "capabilities": ["your-capability"], "component": "./YourWidget.qml" } ``` **With settings, startup check, and permissions:** ```json { "id": "yourPlugin", "name": "Your Plugin Name", "description": "Brief description", "version": "1.0.0", "author": "Your Name", "type": "widget", "capabilities": ["your-capability"], "component": "./YourWidget.qml", "icon": "extension", "settings": "./Settings.qml", "startupCheck": "./StartupCheck.qml", "requires_dms": ">=0.1.0", "dependencies": ["mytool"], "permissions": ["settings_read", "settings_write"] } ``` **Composite plugin (multi-surface):** ```json { "id": "myComposite", "name": "My Composite Plugin", "description": "Daemon + widget + desktop from one plugin", "version": "1.0.0", "author": "Your Name", "type": "composite", "capabilities": ["daemon", "dankbar-widget", "desktop-widget"], "icon": "extension", "components": { "daemon": "./MyDaemon.qml", "widget": "./MyBarWidget.qml", "desktop": "./MyDesktopWidget.qml" }, "settings": "./Settings.qml", "permissions": ["settings_read", "settings_write"] } ``` **Standalone dash tab or card:** same single file form, `"type": "dash"` or `"type": "dashCard"` plus `"component"`. A tab and a card together (or with a bar widget) use `components` with the keys `dash` and `dashCard`. Both accept an optional `dash` block for labels, card size and options. See [dash-plugin-guide.md](references/dash-plugin-guide.md). **Key rules:** - `id` must be camelCase, matching pattern `^[a-zA-Z][a-zA-Z0-9]*$` - `version` must be semver (e.g., `1.0.0`) - Provide either `component` (single-surface) or `components` (multi-surface), not both - `component` / component paths must start with `./` and end with `.qml` - `type: "launcher"` (or a `components` object with a `launcher` key) requires a `trigger` field - `settings_write` permission is **required** if the plugin has a settings component - `dependencies` replaces the deprecated `requires` field ## Step 3: Create the Main Component ### Widget ```qml import QtQuick import qs.Common import qs.Widgets import qs.Modules.Plugins PluginComponent { property var popoutService: null horizontalBarPill: Component { StyledRect { width: label.implicitWidth + Theme.spacingM * 2 height: parent.widgetThickness radius: Theme.cornerRadius color: Theme.surfaceContainerHigh StyledText { id: label anchors.centerIn: parent text: "Hello" color: Theme.surfaceText font.pixelSize: Theme.fontSizeMedium } } } verticalBarPill: Component { StyledRect { width: parent.widgetThickness height: label.implicitHeight + Theme.spacingM * 2 radius: Theme.cornerRadius color: Theme.surfaceContainerHigh StyledText { id: label anchors.centerIn: parent text: "Hi" color: Theme.surfaceText font.pixelSize: Theme.fontSizeSmall rotation: 90 } } } } ``` See [widget-plugin-guide.md](references/widget-plugin-guide.md) for popouts, CC integration, and advanced features. ### Launcher ```qml import QtQuick import qs.Services Item { id: root property var pluginService: null property string trigger: "#" signal itemsChanged() function getItems(query) { const items = [ { name: "Item One", icon: "material:star", comment: "Description", action: "toast:Hello!", categories: ["MyPlugin"] } ] if (!query) return items const q = query.toLowerCase() return items.filter(i => i.name.toLowerCase().includes(q)) } function executeItem(item) { const [type, ...rest] = item.action.split(":") const data = rest.join(":") if (type === "toast") ToastService?.showInfo(data) else if (type === "copy") Quickshell.execDetached(["dms", "cl", "copy", data]) } } ``` See [launcher-plugin-guide.md](references/launcher-plugin-guide.md) for triggers, icon types, context menus, and image tiles. ### Desktop ```qml import QtQuick import qs.Common Item { id: root property var pluginService: null property string pluginId: "" property bool editMode: false property real widgetWidth: 200 property real widgetHeight: 200 property real minWidth: 150 property real minHeight: 150 Rectangle { anchors.fill: parent radius: Theme.cornerRadius color: Theme.surfaceContainer opacity: 0.85 border.color: root.editMode ? Theme.primary : "transparent" border.width: root.editMode ? 2 : 0 Text { anchors.centerIn: parent text: "Desktop Widget" color: Theme.surfaceText } } } ``` See [desktop-plugin-guide.md](references/desktop-plugin-guide.md) for sizing, persistence, and edit mode. ### Daemon ```qml import QtQuick import qs.Common import qs.Services import qs.Modules.Plugins PluginComponent { property var popoutService: null Connections { target: SessionData function onSomeSignal() { console.log("Event received") } } } ``` See [daemon-plugin-guide.md](references/daemon-plugin-guide.md) for event-driven patterns and process execution. ### Dash Tab ```qml import QtQuick import qs.Common import qs.Widgets import qs.Modules.Plugins import qs.Modules.DankDash DashTabComponent { id: root property date now: new Date() implicitHeight: DashMetrics.tabMinHeight Timer { interval: 1000 repeat: true running: root.live onTriggered: root.now = new Date() } StyledText { anchors.centerIn: parent text: root.now.toLocaleTimeString(I18n.locale()) color: Theme.surfaceText } } ``` ### Dash Card ```qml import QtQuick import qs.Common import qs.Widgets import qs.Modules.Plugins DashCardComponent { id: root tone: options.tone ?? "" StyledText { anchors.centerIn: parent text: I18n.trFor("myPlugin", "Hello") color: root.contentColor } } ``` Gate timers and animations on `live`; the dash content stays alive after the popout closes. Cards must lay out for every size in their manifest range. Use the card colors (`accentColor`, `contentColor`, `mutedColor`) so tones work. See [dash-plugin-guide.md](references/dash-plugin-guide.md). ### Composite For composite plugins, create a separate QML file per surface. Each surface uses the same base component as the corresponding single-surface type (PluginComponent for widget/daemon, Item for launcher, etc.). All surfaces share the same `pluginId` and `pluginService`. ``` MyCompositePlugin/ plugin.json MyBarWidget.qml # PluginComponent (widget surface) MyDaemon.qml # PluginComponent (daemon surface) MyDesktopWidget.qml # Item with desktop widget properties Settings.qml # Shared settings for all surfaces ``` `pluginService.availablePlugins[pluginId].surfaces` lists the surfaces a plugin registered. ## Step 4: Add Startup Check (Optional) Gate plugin activation on dependency checks by providing a `startupCheck` component. This runs before the plugin loads and blocks activation if a required tool or condition is missing. Create a `StartupCheck.qml` (non-visual QtObject): ```qml import QtQuick import qs.Common QtObject { function check(done) { Proc.runCommand("myPlugin.depCheck", ["sh", "-c", "command -v mytool"], (stdout, exitCode) => { if (exitCode === 0) { done(null); return; } done({ "title": I18n.tr("mytool is required"), "details": I18n.tr("Install 'mytool' and re-enable this plugin.") }); }); } } ``` The `done` callback accepts: - `null` - allow activation - A string - block with a short error message - `{ title, details }` - block with a title and expandable details body A synchronous variant (no `done` parameter, return the result directly) is also supported. Failed checks show a toast error and store the error in `pluginService.pluginLoadErrors`. Add to your manifest: ```json { "startupCheck": "./StartupCheck.qml", "dependencies": ["mytool"] } ``` ## Step 5: Add Settings (Optional) Wrap settings in `PluginSettings` with your `pluginId`. All settings auto-save and auto-load. ```qml import QtQuick import qs.Common import qs.Widgets import qs.Modules.Plugins PluginSettings { pluginId: "yourPlugin" StringSetting { settingKey: "apiKey" label: "API Key" description: "Your API key" placeholder: "sk-..." } ToggleSetting { settingKey: "enabled" label: "Enable Feature" defaultValue: true } SelectionSetting { settingKey: "interval" label: "Refresh Interval" options: [ { label: "1 min", value: "60" },
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub