Configuration

Overview

Stasis uses a .rune configuration file. It first looks for $XDG_CONFIG_HOME/stasis/stasis.rune (typically ~/.config/stasis/stasis.rune). For system-wide configuration, copy the example to /etc/stasis/stasis.rune.

On first run, Stasis generates a default configuration at ~/.config/stasis/stasis.rune.

The master reference config is located at /usr/share/doc/stasis/stasis.rune.

Globals (Variables)

The top level is intended for reusable values. Define timers and strings once, then reference them inside default: and profiles.

@author "Your Name"
@description "Stasis configuration"

# Top-level is intended for reusable values.
lock_after        300
screen_off_after  300
suspend_after     1800
debounce_seconds  4
notify_seconds    5

Default Block

Your config must contain a default: block. Most settings live under this block. Action blocks defined directly under default: form the desktop plan. On laptops, the ac: and battery: sub-blocks are used instead (see AC & Battery).

default:
  enable_loginctl false
  enable_dbus_inhibit true
  pre_suspend_command None
  #prepare_sleep_command "hyprlock"
  monitor_media true
  ignore_remote_media true

  # Optional: ignore these media sources (case-insensitive)
  #media_blacklist ["spotify"]

  debounce_seconds debounce_seconds

  # Lid actions (laptop only — live here so they apply to both ac: and battery:)
  lid_close_action "hyprlock"
  #lid_open_action ""

  notify_on_unpause true

  # Global gate: per-step notifications only fire if this is true
  notify_before_action true
  notification_icon "stasis"

  inhibit_apps [
    r"steam_app_.*"
  ]

  startup:
    timeout 0
    command "notify-send 'Stasis idle manager started!'"
  end

  lock_screen:
    timeout lock_after
    command "hyprlock"
    resume_command "notify-send 'Welcome back $env.USER!'"
    notification "Locking soon"
    #notification_icon "dialog-warning"
    notify_seconds_before notify_seconds
  end

  dpms:
    timeout screen_off_after
    command "hyprctl dispatch dpms off"
    resume_command "hyprctl dispatch dpms on"
  end

  suspend:
    timeout suspend_after
    command "systemctl suspend"
  end
end

Startup Action

The startup: block runs once when Stasis starts (always first):

startup:
  timeout 0
  command "notify-send 'Stasis idle manager started!'"
end

loginctl Integration

Set enable_loginctl true under default: to register Stasis with login1 for global lock/unlock state tracking. This is a top-level global setting — there is no per-block use_loginctl option.

# Enable global login1 tracking (lock/unlock state)
enable_loginctl true
Why use this?

Without it, Stasis tracks the locker's process lifetime. If your locker daemonizes (runs in the background), Stasis might see it exit immediately and think the screen is already unlocked. Using enable_loginctl switches tracking to D-Bus signals from logind, which is much more robust for background lockers.

Wrapper Script Pattern:

To use this, create a wrapper script (e.g., ~/.local/bin/stasis-lock.sh):

#!/usr/bin/env bash
loginctl lock-session
swaylock -f

Then set your command to use the wrapper:

lock_screen:
  timeout 300
  command "~/.local/bin/stasis-lock.sh"

Session D-Bus Inhibit Integration

Keep session-bus inhibit handling enabled so desktop/session requests (including portal inhibits) are honored correctly:

# Enable session-bus inhibit tracking (recommended)
enable_dbus_inhibit true
Session context: Start your compositor in a real session context (for example: niri-session, dbus-run-session, or your compositor's recommended launcher) so session D-Bus features are available.

Pre-Suspend Command

Optionally run a command immediately before suspending — useful to ensure the screen is locked before the system sleeps:

# Run before suspending (e.g. ensure screen is locked first)
# pre_suspend_command is BLOCKING — use your locker's fork flag if it has one,
# or wrap it with the daemonize utility.
pre_suspend_command "swaylock -f"       # swaylock has a built-in fork flag
#pre_suspend_command "daemonize hyprlock"  # hyprlock doesn't, use daemonize

# Disable:
pre_suspend_command None
Important: pre_suspend_command is blocking — Stasis waits for it to exit before suspending, so if you pass a locker directly it will wait until you unlock before ever suspending. Use your locker's fork flag if it has one (e.g. swaylock -f), or wrap it with the daemonize utility. If your plan already has a lock_screen: step, you generally don't need pre_suspend_command at all.
# pre_suspend_command is BLOCKING — Stasis waits for it to finish before suspending.
# Use your locker's fork flag if it has one, or wrap with daemonize:

pre_suspend_command "swaylock -f"         # swaylock: built-in fork flag
#pre_suspend_command "daemonize hyprlock" # hyprlock: no fork flag, use daemonize

suspend:
  timeout 1800
  command "systemctl suspend"
end

# If you already lock as a plan step, prefer this instead:
#pre_suspend_command None

Prepare Sleep Command

Use prepare_sleep_command when you need a command to run as soon as logind announces an external sleep transition. This is different from pre_suspend_command, which only runs before Stasis's own suspend: step.

# Run immediately when logind emits PrepareForSleep(true).
# This covers external sleep events such as lid-triggered sleep or systemctl suspend.
prepare_sleep_command "hyprlock"

# Disable or clear inherited value:
prepare_sleep_command ""

Media Monitoring

Media Playback

Control whether Stasis monitors media playback to prevent idle actions:

monitor_media true
ignore_remote_media true
  • monitor_media — active playback prevents idle timeouts
  • ignore_remote_media — ignores remote sources (Spotify remote, KDEConnect, etc.)

Media Blacklist

Ignore specific media sources (case-insensitive):

media_blacklist ["spotify", "rhythmbox"]

Inhibitors

Application Inhibitors

Specify apps/processes that prevent idle actions while running (strings or regex literals):

inhibit_apps [
  "vlc"
  "Spotify"
  "mpv"
  r".*\.exe"
  r"steam_app_.*"
  r"firefox.*"
]
Regex Pattern Guidelines:
  • Use raw string syntax: r"pattern"
  • Escape special characters: \. for literal dots
  • Use .* for wildcards
  • Use ^ and $ for anchors

Notifications

On Unpause

Notify when resuming from an IPC pause (e.g., stasis pause for 1h):

notify_on_unpause true

Pre-Action

To show notifications before actions run:

  • Enable the gate: notify_before_action true
  • Optionally set a default: notify_seconds_before
  • Set notification "message" on the action block
  • Optionally override timing per-block with notify_seconds_before
notify_before_action true
notify_seconds_before 5

Notification Icons

Stasis 1.3.0 passes an icon to notify-send for generated notifications. Packaged installs provide the default stasis icon, and you can override or clear it globally.

# Global default for Stasis-generated notifications.
# Packaged installs provide the "stasis" icon.
notification_icon "stasis"

# Use another icon name or an absolute file path:
notification_icon "dialog-warning"

# Disable the default icon entirely:
notification_icon ""

Individual action blocks can override the global icon:

lock_screen:
  timeout 300
  command "hyprlock"
  notification "Locking session in 10s"
  notification_icon "dialog-warning"
  notify_seconds_before 10
end

Laptop Settings

Lid Actions

Configure what happens when the laptop lid closes or opens. These live directly under default: so they automatically apply to both ac: and battery: plans without duplication. Lid close/open also pause/resume the plan timers regardless. A profile can override or clear them.

# Lives under default: so it applies to both ac: and battery: plans.
# A profile can override or clear these.
lid_close_action "hyprlock"
lid_open_action  "brightnessctl set 60%"

# Clear an action entirely:
lid_open_action ""

Debounce

Prevent rapid lid open/close events from triggering multiple actions:

debounce_seconds 4

Idle Actions

Each action block supports:

  • timeout — seconds of idle time before triggering (required); 0 runs immediately on plan activation
  • command — command to run (required; use None to disable)
  • resume_command / resume-command — optional, run when activity resumes
  • notification — optional message shown before the action runs
  • notification_icon — optional icon name or path for this action's notification
  • notify_seconds_before — optional per-block timing override
Action names:
  • startup
  • lock_screen / lock-screen
  • early_dpms — useful for a shorter initial screen-off before the main lock
  • dpms
  • brightness
  • suspend
  • * — custom actions can be named anything

AC & Battery

Laptop plans live as sub-blocks inside default: (or inside a profile). When running on a laptop chassis, Stasis uses ac: or battery: depending on current power state — the desktop plan blocks are ignored. Globals and lid actions defined directly under default: still apply to both plans.

AC Plan

default:
  # ...globals, lid actions, desktop plan...

  ac:
    # timeout 0 runs immediately when AC becomes active
    custom_brightness_instant:
      timeout 0
      command "brightnessctl set 100%"
    end

    brightness:
      timeout 120
      command "brightnessctl set 30%"
    end

    dpms:
      timeout 60
      command "hyprctl dispatch dpms off"
      resume_command "hyprctl dispatch dpms on"
    end

    lock_screen:
      timeout 120
      command "hyprlock"
      notification "Locking on AC in 10s"
      notify_seconds_before 10
    end

    suspend:
      timeout 300
      command "systemctl suspend"
    end
  end
end

Battery Plan

default:
  # ...globals, lid actions, desktop plan...

  battery:
    custom_brightness_instant:
      timeout 0
      command "brightnessctl set 40%"
    end

    brightness:
      timeout 60
      command "brightnessctl set 20%"
    end

    dpms:
      timeout 30
      command "hyprctl dispatch dpms off"
      resume_command "hyprctl dispatch dpms on"
    end

    lock_screen:
      timeout 120
      command "hyprlock"
      resume_command "notify-send 'Welcome back $env.USER!'"
    end

    suspend:
      timeout 120
      command "systemctl suspend"
    end
  end
end
💡 Tips:
  • Put timeout 0 actions first — they run immediately when the plan activates (e.g., restore brightness on plug-in).
  • Profiles can also define their own ac: / battery: sub-blocks to override the laptop plan per-profile.

Full Example

Complete example covering desktop plan, laptop AC/battery plans, notification icons, sleep hooks, and both profile modes (overlay and fresh):

# This file was auto-generated by Stasis on first run
# Feel free to customize it to your needs
# Master config reference: /usr/share/doc/stasis/stasis.rune

@author "Dustin Pilgrim"
@description "Lightweight feature packed idle manager for Wayland"

# Top-level: reusable values (recommended)
lock_after        300
screen_off_after  300
suspend_after     1800
debounce_seconds  4
notify_seconds    5

default:
  enable_loginctl false
  enable_dbus_inhibit true
  pre_suspend_command None
  #prepare_sleep_command "hyprlock"
  monitor_media true
  ignore_remote_media true  # ignore remote players (spotify/kdeconnect/etc.)

  # Optional: ignore these media sources for media inhibit (case-insensitive)
  #media_blacklist ["spotify"]

  debounce_seconds debounce_seconds

  # Lid actions (laptop only — live here so they apply to both ac: and battery:)
  lid_close_action "hyprlock"
  #lid_open_action ""

  # Notify when resuming from IPC pause (e.g. `stasis pause 1h`)
  notify_on_unpause true

  # Enables per-step notifications (only if the block sets `notification`)
  notify_before_action true

  # Icon name/path for Stasis-generated notifications. Defaults to "stasis".
  # Set to "" to disable the default icon, or override per step with
  # notification_icon.
  notification_icon "stasis"

  inhibit_apps [
    "mpv"
    "vlc"
    "Spotify"
    r".*\.exe"
    r"steam_app_.*"
    r"firefox.*"
  ]

  # ----------------------------------------------------------------
  # DESKTOP PLAN (used only on desktop chassis)
  # ----------------------------------------------------------------
  startup:
    timeout 0
    command "notify-send -a Stasis 'Stasis started!'"
  end

  early_dpms:
    timeout 300
    command "hyprctl dispatch dpms off"
    resume_command "hyprctl dispatch dpms on"
  end

  lock_screen:
    timeout lock_after
    command "hyprlock"
    resume_command "notify-send 'Welcome back $env.USER!'"
    notification "Locking session in 10s"
    notification_icon "dialog-warning"
    notify_seconds_before 10
  end

  dpms:
    timeout screen_off_after
    command "hyprctl dispatch dpms off"
    resume_command "hyprctl dispatch dpms on"
  end

  suspend:
    timeout suspend_after
    command "systemctl suspend"
  end

  # ----------------------------------------------------------------
  # LAPTOP PLANS (used only on laptop chassis — ac: or battery:)
  # Desktop plan blocks above are ignored for laptops.
  # ----------------------------------------------------------------
  ac:
    # timeout 0 runs immediately when AC becomes active
    custom_brightness_instant:
      timeout 0
      command "brightnessctl set 100%"
    end

    brightness:
      timeout 120
      command "brightnessctl set 30%"
    end

    dpms:
      timeout 60
      command "hyprctl dispatch dpms off"
      resume_command "hyprctl dispatch dpms on"
    end

    lock_screen:
      timeout 120
      command "hyprlock"
      notification "Locking on AC in 10s"
      notify_seconds_before 10
    end

    suspend:
      timeout 300
      command "systemctl suspend"
    end
  end

  battery:
    custom_brightness_instant:
      timeout 0
      command "brightnessctl set 40%"
    end

    brightness:
      timeout 60
      command "brightnessctl set 20%"
    end

    dpms:
      timeout 30
      command "hyprctl dispatch dpms off"
      resume_command "hyprctl dispatch dpms on"
    end

    lock_screen:
      timeout 120
      command "hyprlock"
      resume_command "notify-send 'Welcome back $env.USER!'"
    end

    suspend:
      timeout 120
      command "systemctl suspend"
    end
  end
end

# --------------------------------------------------------------------
# PROFILES
#
# mode "overlay": merges on top of the active base (default/ac/battery)
# mode "fresh":   starts from nothing — define every global and action block you want
# --------------------------------------------------------------------

# gaming: overlay — only replace inhibit_apps
gaming:
  mode "overlay"

  inhibit_apps [
    r".*\.exe"
    r"steam_app_.*"
    r".*\.x86_64"
  ]
end

# work: overlay — longer timeouts, loginctl enabled
work:
  mode "overlay"

  enable_loginctl true
  enable_dbus_inhibit true
  debounce_seconds 10
  monitor_media true
  ignore_remote_media true

  lock_screen:
    timeout 600
    command "hyprlock"
    resume_command "notify-send 'Welcome back, $env.USER!'"
  end

  dpms:
    timeout 300
    command "hyprctl dispatch dpms off"
    resume_command "hyprctl dispatch dpms on"
  end

  suspend:
    timeout 3600
    command "systemctl suspend"
  end
end

# presentation: fresh — keep display on, suppress all idle actions
presentation:
  mode "fresh"

  pre_suspend_command None
  enable_dbus_inhibit true
  monitor_media false
  ignore_remote_media true
  debounce_seconds 0
  notify_on_unpause false
  notify_before_action false
  inhibit_apps [ ]

  lid_close_action ""
  lid_open_action ""

  brightness:
    timeout 0
    command "brightnessctl set 100%"
  end
end

# Profile switching (runtime IPC):
#   stasis profile gaming
#   stasis profile work
#   stasis profile presentation
#   stasis profile default   (or: stasis profile none)
Advanced

Profiles

Profiles are any top-level named blocks other than default. They override settings and action blocks from the active base plan, and can define their own ac:/battery: plans.

mode:
  • "overlay" (default) — merges on top of the active base; only what you specify is overridden
  • "fresh" — starts from nothing; you must define every global and action block you want
# Any top-level named block besides `default:` is a profile.
# Profiles override settings/steps from the active base and can
# have their own `ac:` / `battery:` plans.

gaming:
  mode "overlay"  # merges on top of active base

  # Replace the inherited inhibit_apps list:
  inhibit_apps [
    r".*\.exe"
    r"steam_app_.*"
    r".*\.x86_64"
  ]
end

work:
  mode "overlay"

  enable_loginctl true
  debounce_seconds 10
  monitor_media true
  ignore_remote_media true

  lock_screen:
    timeout 600
    command "hyprlock"
    resume_command "notify-send 'Welcome back, $env.USER!'"
  end

  dpms:
    timeout 300
    command "hyprctl dispatch dpms off"
    resume_command "hyprctl dispatch dpms on"
  end

  suspend:
    timeout 3600
    command "systemctl suspend"
  end
end

presentation:
  mode "fresh"  # starts from NOTHING — define every global and step you want

  pre_suspend_command None
  monitor_media false
  ignore_remote_media true
  debounce_seconds 0
  notify_on_unpause false
  notify_before_action false
  inhibit_apps [ ]

  # Clear lid actions so they don't fire during a presentation
  lid_close_action ""
  lid_open_action ""

  # Keep display on; no lock/dpms/suspend unless you add them
  brightness:
    timeout 0
    command "brightnessctl set 100%"
  end
end
Profile selection:

Profiles are switched at runtime via IPC:

# Switch profiles at runtime via IPC:
stasis profile gaming
stasis profile work
stasis profile presentation

# Return to default (no profile):
stasis profile default
# (alias)
stasis profile none