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
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
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"
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 trueSession 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 NoneMedia 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 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 5Laptop 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 runsnotify_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, and all three 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
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
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"
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
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
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