Permissions reference
Every permission a widget can request, what the user is told it means at install time, and which methods and events it unlocks.
Everything is denied by default. A widget declares what it needs in the
manifest's permissions object, and the user consents at install time,
permission by permission. Three rules shape the system:
- Consent can only narrow. What the user granted is intersected with the manifest; nothing can escalate past what the manifest declared, and the user may grant less.
- Updates re-prompt only for additions. An update that adds a permission asks again; removals apply silently.
- Ask for what you use. Every grant is shown to the user in plain language (the wording below). A widget requesting more than it visibly needs reads as suspicious in review and to users.
The permissions
The wording in the second column is exactly what the marketplace shows the user at install time.
| Permission | Shown to the user as | Unlocks |
|---|---|---|
time | Reads the current time from the dashboard's clock | dd.time, the time.tick event |
storage | Saves its own data inside the dashboard | dd.storage |
files | Reads files or folders you explicitly pick for it | dd.files.read of user-set filePath settings |
desktop | Integrates with your desktop (icons, wallpaper area) | dd.desktop, desktop.changed, dd.dialogs.pickDesktopItems |
system | Reads system stats like CPU, memory and battery | dd.system.status / onVitals, the system.vitals stream |
systemControls | Changes system settings such as volume | the dd.system write surface: volume, mute, Wi-Fi, openSettings. Useless without system |
media | Sees what music or video is playing | dd.media.status / onNowPlaying, the media.nowPlaying stream |
mediaControls | Controls media playback | the dd.media transport verbs. Useless without media |
audio | Reads audio levels (for visualizations) | the audio.spectrum stream. Loudness bands only, never raw audio |
control | Controls other widgets you grant it access to | dd.widgets over user-approved targets, widgets.changed |
peers | Talks to other widgets of the same type | dd.peers drag and drop |
systemApps | Opens system apps you pick for it | dd.apps, catalog keys only |
claudeUsage | Reads your local Claude Code usage summary | dd.claudeUsage.status, aggregated only |
notifications | Shows you reminders, even when the widget is hidden | dd.notify.sync |
power | Shuts down, restarts, sleeps, locks or signs out of this PC | dd.power |
folders | Lists and opens items in folders you pick for it | dd.folders, folders.changed, dd.dialogs.pickFolderItems |
The scoped grants
http and links are objects, not booleans, and their scope is part of the
consent.
http
"permissions": { "http": { "hosts": ["api.open-meteo.com"], "rateLimit": 60 } }hosts: exact hostnames the widget may fetch through dd.http.fetch. Shown to the user as: "Talks to the internet, only to:" followed by the list. No wildcards; every hop of a redirect is re-checked.rateLimit: requests per minute, optional. Omitted means the host default of 30; values are clamped to 120. Never shown at install.
links
"permissions": { "links": { "prefixes": ["steam://run/"] } }prefixes: URL prefixes dd.links.open may launch, each a fullscheme://...string. Shown to the user as: "Can open these link types on your PC:" followed by the list. Empty means no access, and dangerous schemes are refused at call time no matter what a manifest declares.
Read and control pairs
Two capabilities are split so that reading never implies acting:
systemreads vitals;systemControlschanges volume, Wi-Fi, and opens settings panels. Controls withoutsystemare useless.mediareads now-playing;mediaControlsdrives playback.
power is deliberately its own permission rather than part of
systemControls: granting a volume slider is not granting the ability to
turn the machine off.
Version floors
Some permissions did not exist in the earliest app releases. The marketplace
validators require a matching minAppVersion when a manifest requests them:
| Permission | Requires at least |
|---|---|
power | "minAppVersion": "0.1.9" |
folders | "minAppVersion": "0.1.10" |
Consent-bearing settings
Three setting types are part of the permission story:
filePath (which file or folder), secretRef (which credential), and
instances (which other widgets). Their manifest defaults are always
ignored; only what the user actively picked counts. See
the manifest reference.
For the containment model behind all of this, see How the sandbox works.