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.

Informações da origem

Repositório
AvengeMedia/DankMaterialShell
Última atividade na origem
17 de setembro de 2026 às 20:51
Idioma detectado do SKILL.md
inglês
Estrelas
8.400
Forks
547

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
29 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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 no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub