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 5Default 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
endStartup Action
The startup: block runs once when Stasis starts (always first):
startup:
timeout 0
command "notify-send 'Stasis idle manager started!'"
endloginctl 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 trueWithout 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.
To use this, create a wrapper script (e.g., ~/.local/bin/stasis-lock.sh):
#!/usr/bin/env bash
loginctl lock-session
swaylock -fThen 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 trueniri-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 Nonepre_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 NonePrepare 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 truemonitor_media— active playback prevents idle timeoutsignore_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.*"
]- 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 truePre-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 5Notification 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
endLaptop 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 4Idle Actions
Each action block supports:
timeout— seconds of idle time before triggering (required);0runs immediately on plan activationcommand— command to run (required; useNoneto disable)resume_command/resume-command— optional, run when activity resumesnotification— optional message shown before the action runsnotification_icon— optional icon name or path for this action's notificationnotify_seconds_before— optional per-block timing override
startuplock_screen/lock-screenearly_dpms— useful for a shorter initial screen-off before the main lockdpmsbrightnesssuspend*— 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
endBattery 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- Put
timeout 0actions 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)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.
"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
endProfiles 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