Files
mesh-catalog/modules/dunst
jochen 84731d8fc6
mesh/merge-gate pass: builds dunst → g14, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery failed: its walk failed: a gate on a first machine (what it carried put back), a build, a machine
mesh/delivery-group group feat/setting-defaults failed: a member failed
dunst: say plainly why each default
2026-10-08 17:02:43 +02:00
..

dunst

The notifier as a module (novox/hq ADR 0208, research 026/05).

  • Installs dunst, and libnotify for notify-send, the client every program and these tools use.
  • Claims the mesh's node-notifier seat and serves its verbs send and history.
  • Owns ~/.config/dunst/dunstrc and the directory ~/.config/dunst/dunstrc.d/. Another module's rule is that module's own file in the directory (ADR 0208 §4). dunst reads the directory after dunstrc, so a drop-in outranks it.
  • Starts nothing. The package registers dunst with D-Bus, which starts it on the first notification, inside the account's service manager. There is no autostart line, no unit and no session-start contribution.
  • Requires no display of its own. dunst speaks both X11 and Wayland and picks the one the session has, so it serves an X session and a later sway one alike.

Answers from a notification

send with actions runs notify-send --wait with one --action per answer, answers the id at once and waits in this bundle for the operator's choice (dunst offers the actions on a middle click, or in its context menu). The token chosen is said as this module's event action-chosen; it becomes the node-notifier seat's event once seats publish events of their own (novox/hq to-be 46 phase 3). Nothing is said for a notification closed, expired or replaced without an answer, and a wait ends after seven days. A notification that offers answers stays until dismissed (expire_ms 0). A restart of this bundle ends the waits it held; it says started {machine} once it serves, and the operator channel shows the open answers there again (novox/hq ADR 0258). notify-send prints the id before it waits, also into a pipe (checked on the laptop on 2026-10-08: the id at once, and "Wait timeout expired" when it expired).

Tools

Every tool goes over the account's session bus. None needs the screen, and each answers clearly when the account is not logged in.

tool does
node-notifier.send a notification: title, body, urgency, sender, icon, how long, and the answers it offers (actions: token and label); answers its id, and says the chosen answer later as the event action-chosen {id, token, machine}
node-notifier.history what was shown, newest first, with how long ago
dunst_pause / dunst_resume do not disturb: notifications are held back, not lost
dunst_close_all clear the screen; the history keeps them
dunst_rules the rules the running notifier holds, and the files they come from
dunst_count shown, waiting, in history, and whether paused

Settings

Two preferences have defaults in the definition (novox/hq ADR 0262). The mesh's layer, then a machine's, overrides them, and the file is written with the value, never with a variable dunst reads.

setting default what it is
font-size 10 the points of font = Inter <size>; 10 reads well on a screen of about 100 DPI, which is the workstations
width 250 the notification's width in pixels; a larger font needs a wider notification

A machine with a denser screen sets both for itself, and the next push writes them:

mesh-controller.settings {module: "dunst", node: "<machine>", values: '{"font-size": 16, "width": 400}'}

mesh-controller.settings {module: "dunst", node: "<machine>"} shows each value and where it came from: the default, the mesh, or the machine. dunst reads its file when it starts, and nothing in this module tells a running dunst that the file changed: a new size shows at the next login, or after dunstctl reload.

What it chose, and what it improves

The workstations' files differed: one had the notifications bottom-right, 15 % transparent and with rounded corners; the other top-right, opaque and square. This module takes the second, because the rest of the desktop is square and opaque, and the top-right corner sits under the bar that shows the count. The file keeps only the settings that differ from dunst's defaults.

  • The context menu works. It called /usr/bin/dmenu, installed on neither machine. It now calls dmenu, the seat command of whichever module holds node-launcher (rofi on the workstations).
  • The face is the interface one, Inter (research 026/04), instead of a monospace Nerd font.
  • icon_path, which named two directories of an icon theme that is not installed, is gone. The icon theme is looked up recursively.

What it leaves as found

  • ~/.config/dunst/dunstrc.d/50-slack.conf, the Slack rule. It becomes the Slack module's own drop-in when there is one, and until then it is the operator's file in a directory this module owns.

Migration (ADR 0182)

  • The first push keeps the found dunstrc once, then writes the module's.
  • The desktop runs two notification daemons because its session began before the session bus fix (research 026/01). That ends at the next login, and nothing here starts a second one. dunst_count after logging in again shows the one daemon's counts.

Blockers

  • node-notifier is ADR 0208's seat. Until the controller knows it, mctl reads the claim as unknown.
  • dunst_rules and the counts ask the running notifier. When none runs, the bus starts one, which needs a session to draw on.