Services
Service APIs are version-sensitive and can mutate the user's session.
Start from the installed-version type index, not from a remembered recipe.
Inspect local *.qmltypes files when the installed module and web docs may differ.
PipeWire
The retained default-sink shape is:
import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
PanelWindow {
id: root
anchors { top: true; left: true; right: true }
implicitHeight: 30
readonly property var sinkAudio: Pipewire.defaultAudioSink ? Pipewire.defaultAudioSink.audio : null
PwObjectTracker {
objects: [Pipewire.defaultAudioSink]
}
Text {
anchors.centerIn: parent
text: `${Math.floor((root.sinkAudio ? root.sinkAudio.volume : 0) * 100)}%`
}
}
For a slider, keep the service-to-control binding declarative and write only user movement:
Slider {
value: root.sinkAudio ? root.sinkAudio.volume : 0
onMoved: if (root.sinkAudio) root.sinkAudio.volume = value
}
Verify the tracker and node properties against the installed PipeWire module before extending this shape.
Notifications
Creating NotificationServer attempts to become the session notification daemon.
Do not run it alongside the user's real notification daemon during tests.
Capability properties advertise behavior to clients.
Set actionsSupported, persistenceSupported, inlineReplySupported, markup, hyperlinks, images, or action icons to true only when the UI implements that behavior.
Receiving a property from Notification does not mean the daemon implements its presentation or interaction.
A received notification must be marked tracked in onNotification if it should remain in trackedNotifications.
Notification.expireTimeout is expressed in seconds in the installed-version docs checked for this skill.
Use expire() for timeout expiry and dismiss() for an explicit user dismissal because they report different close reasons.
Re-check these semantics for the installed version.
The bundled notification example intentionally renders only plain summary and body text. It does not advertise actions, persistence, inline reply, markup, hyperlinks, or images.
PAM
Never send the PAM prompt text back as the response.
The prompt is display state.
The response comes from the user's input and may be sent only while responseRequired is true.
Honor responseVisible when deciding whether user input may be shown.
Do not use an abbreviated PAM recipe for a lockscreen.
Read the complete installed-version PamContext page and official lockscreen example.
Do not run live PAM or lockscreen checks during routine skill validation.
greetd and Polkit
These components participate in authentication and session authorization. Do not guess method names, lifecycle order, or response objects. Use the installed-version type pages and official examples. Test only in an isolated environment with a recovery path.
MPRIS, system tray, UPower, Bluetooth, and networking
Look up the installed module name and exported types before importing them. Module names and singleton shapes are not uniform across these services. If the installed API cannot support a requested feature, report the blocker. Do not silently delete requested behavior or add guessed adapters and compatibility branches.
Runtime isolation
A nested compositor alone does not isolate D-Bus or per-user services.
For service tests, isolate the runtime directory, session bus, and relevant service daemons as well.
Static qmllint and offscreen loading do not validate service ownership, events, or interaction.