Shell Setup🔗

Triad manages status bars and desktop shells through shell profiles. A profile defines how to launch and stop a shell, and whether it needs Niri-compatible IPC. Triad starts the active profile on launch and can cycle between profiles at runtime.

The shells Block🔗

shells {
  active "noctalia"
  cycle  "noctalia" "waylee" "waybar"

  watchdog {
    enabled  #true
    fallback "waybar"
  }

  profile "noctalia" {
    launch "noctalia-shell"
    stop   "pkill" "-f" "noctalia-shell"
    niri-compat #true
  }

  profile "waybar" {
    launch "waybar"
    stop   "pkill" "-x" "waybar"
    niri-compat #true
  }

  profile "waylee" {
    launch "wayle"
    stop   "pkill" "-x" "wayle"
    niri-compat #true
  }

  profile "dank" {
    launch "dankmaterialshell"
    stop   "pkill" "-f" "dankmaterialshell"
    niri-compat #true
  }
}
SettingTypeDescription
activeStringProfile to launch at startup.
cycleListProfiles to rotate through with cycle-shell.
watchdog.enabledBoolRestart the shell if it crashes.
watchdog.fallbackStringProfile to use if the active shell fails repeatedly.

Each profile takes:

SettingTypeDescription
launchString argvCommand to start the shell.
stopString argvCommand to stop it cleanly.
niri-compatBoolSet $NIRI_SOCKET and expose the compatibility IPC facade used by Noctalia, DankMaterialShell, Waylee, and Waybar's niri/workspaces module.

Supported Shells🔗

Waybar🔗

Waybar reads standard Wayland protocols for most modules. Its niri/workspaces module uses Triad's compatibility IPC facade, so add niri-compat #true when you want Waybar workspace buttons.

profile "waybar" {
  launch "waybar"
  stop   "pkill" "-x" "waybar"
  niri-compat #true
}

Noctalia, DankMaterialShell, and Waylee🔗

These shells consume the compatibility IPC schema. Set niri-compat #true in their profiles. Triad sets $NIRI_SOCKET to a compatibility socket and translates events from its native snapshot.

profile "noctalia" {
  launch "noctalia-shell"
  stop   "pkill" "-f" "noctalia-shell"
  niri-compat #true
}

Waylee uses the same compatibility path:

profile "waylee" {
  launch "wayle"
  stop   "pkill" "-x" "wayle"
  niri-compat #true
}

Workspace Names in Your Bar🔗

Workspace names you set in workspace-rules flow through IPC to your shell automatically. Name your workspaces once in your Triad config and they appear in every bar without any further coordination:

workspaces {
  default-count 3
  default-layout "scroller"
}

workspace-rules {
  workspace 1 name="term"
  workspace 2 name="web"
  workspace 3 name="files"
  workspace 4 name="chat"  default-layout="deck"
  workspace 5 name="media" default-layout="monocle"
  workspace 6 name="code"  default-layout="center-tile"
}

Waybar🔗

Add niri-compat #true to the Waybar profile. Triad then sets $NIRI_SOCKET and Waybar's niri/workspaces module reads from it.

profile "waybar" {
  launch "waybar"
  stop   "pkill" "-x" "waybar"
  niri-compat #true
}

In your Waybar JSON config, set "all-outputs": false so each bar instance shows only the workspaces belonging to its own monitor — essential for multi-monitor setups:

"modules-left": ["niri/workspaces"],

"niri/workspaces": {
  "on-click": "activate",
  "all-outputs": false,
  "format": "{index}",
  "format-icons": {
    "active":  "󱓻",
    "urgent":  "󱓻",
    "default": "",
    "1": "1", "2": "2", "3": "3",
    "4": "4", "5": "5", "6": "6",
    "7": "7", "8": "8", "9": "9"
  }
}

With "all-outputs": false, the workspace bar on each monitor shows only the workspaces assigned to that output. Pin workspaces to specific monitors in workspace-rules or the output block:

workspace-rules {
  workspace 4 name="chat"  open-on-output="DP-2"
  workspace 5 name="media" open-on-output="DP-2"
}

Noctalia🔗

Noctalia receives workspace state directly via the event stream — names and active state update automatically. In Noctalia's settings.json, the Workspace widget in your bar config controls display:

{
  "id": "Workspace",
  "labelMode": "index",
  "hideUnoccupied": false,
  "showLabelsOnlyWhenOccupied": true,
  "enableScrollWheel": true
}

Set "labelMode": "name" to show workspace names instead of numbers. Noctalia will use the names from your workspace-rules directly.

DankMaterialShell🔗

DankMaterialShell also uses niri-compat #true and reads workspace state from the same Niri-compatible event stream. No additional configuration is needed beyond the profile entry.

Waylee🔗

Waylee also uses niri-compat #true. It reads workspaces, windows, outputs, overview state, and keyboard layout events through the same $NIRI_SOCKET facade.

Exporting Sockets to the Session🔗

Some launchers and systemd-activated services won't see $NIRI_SOCKET or $TRIAD_SOCKET unless they're exported to the D-Bus activation environment. Add this to your Triad config to handle it at startup:

spawn-at-startup "sh" "-lc" \
  "dbus-update-activation-environment --systemd \
   WAYLAND_DISPLAY XDG_CURRENT_DESKTOP NIRI_SOCKET TRIAD_SOCKET"

Shell Management Commands🔗

Manage your shell profiles and UI focus at runtime:

CommandDescription
switch-shell <name>Switch the active shell profile by name.
cycle-shellCycle through the profiles in shells.cycle.
focus-shell-uiShift focus to the shell UI surface.

Example Bindings:

bindings {
  bind "Ctrl+Alt+0" "cycle-shell"
  bind "Ctrl+Alt+9" "switch-shell 'noctalia'"
  bind "Super+Alt+u" "focus-shell-ui"
}

Notifications🔗

Get notified when the config reloads:

config-notification {
  reload-succeeded "notify-send" "Triad" "Config reloaded."
  reload-failed    "notify-send" "Triad" "Config error — check the log."
}