Breaks started from the menu in reading mode used to end on their own once the due break's length passed, so work started counting before the user was back. They now last until input, which makes them identical to an ordinary idle_start, so the reading_break event and its cap logic are gone.
wlr-break-timer
A fully automated break timer for wlroots-based desktop environments (SwayWM, etc.) that helps maintain healthy work habits by tracking work duration and break periods.
Features
- Zero user interaction required - Automatically tracks work/break cycles.
- Dual break timers - Independent short breaks (20m work → 20s break) and long breaks (45m work → 5m break).
- Automatic idle detection - Detects when you're away from the computer, even while an idle inhibitor (such as Waybar's "stay awake") is active.
- Pause/Unpause - Manually pause the timer when needed (paused time doesn't count toward work duration).
- Reading mode - Hands-off time counts as work while reading, and you start breaks from the menu.
- Self-managing log - Automatically trims old events to keep log size minimal.
- Waybar integration - Shows countdown timers in your status bar with context menu.
- No dependencies - Only requires Python 3 (pre-installed on most Linux systems).
- No daemon process -
break-idleand swayidle are the only long-running processes. Other scripts are executed to modify or read the log file.
How It Works
- break-idle monitors keyboard/mouse activity via the ext-idle-notify-v1 Wayland protocol
- When idle timeout is reached,
break-eventlogs anidle_startevent - When you return,
break-eventlogs anidle_endevent break-statusparses the log to calculate active time and break status- Waybar polls
break-statusevery second to display current timers
swayidle can't be used for the idle timeout because it obeys idle inhibitors, so activity would stop being tracked whenever an inhibitor is active. break-idle uses get_input_idle_notification (ext-idle-notify-v1 version 2, sway 1.11+), which only looks at real input. swayidle is still used to log sleep and resume.
Timer Logic
- Short breaks: After 20 minutes of active work, you need a 20 second break
- Long breaks: After 45 minutes of active work, you need a 5 minute break
- Automatic credit: Idle periods ≥ break duration automatically count as breaks taken
- Smart reset: Long breaks also reset the short break timer (since they encompass it)
- Auto-trim: When a long break is completed, all log entries before it are deleted
Installation
-
Copy scripts to your PATH:
chmod +x break-event break-idle break-status cp break-event break-idle break-status ~/.local/bin/ -
Create configuration directory:
mkdir -p ~/.config/break-timer cp config.example.json ~/.config/break-timer/config.json -
Edit configuration (optional):
nano ~/.config/break-timer/config.json -
Add to Sway config (
~/.config/sway/config):exec break-idle 5 exec swayidle -w \ before-sleep 'break-event sleep' \ after-resume 'break-event wake' -
Add to Waybar config (
~/.config/waybar/config):{ "modules-right": ["custom/break-timer"], "custom/break-timer": { "exec": "break-status", "return-type": "json", "interval": 1, "format": "{icon} {}", "format-icons": { "normal": "🕐", "reading": "📖", "snoozed": "💤" }, "tooltip": true, "menu": "on-click", "menu-file": "/path/to/menu.xml", "menu-actions": { "start-break": "break-event start-break", "snooze": "break-event snooze", "toggle-reading": "break-event toggle-reading", "skip-long": "break-event skip_long", "toggle-pause": "break-event toggle-pause" } } } -
Add Waybar styling (
~/.config/waybar/style.css):#custom-break-timer.normal { color: #a6e3a1; } #custom-break-timer.warning { color: #f9e2af; } #custom-break-timer.overdue { font-weight: bold; } #custom-break-timer.overdue-short { color: #fab387; } #custom-break-timer.overdue-long { color: #f38ba8; } #custom-break-timer.break { color: #89b4fa; } #custom-break-timer.paused { color: #cba6f7; font-style: italic; } #custom-break-timer.snoozed { color: #9399b2; } -
Reload Sway and Waybar:
swaymsg reload killall waybar && waybar &
Configuration
Edit ~/.config/break-timer/config.json:
{
"short_break": {
"interval": "20m", // Work duration before short break
"duration": "20s" // Required short break length
},
"long_break": {
"interval": "45m", // Work duration before long break
"duration": "5m" // Required long break length
},
"snooze": "5m" // How long Snooze hides an overdue break (optional)
}
Status Display
The Waybar module shows:
- Working:
15:30 / 45:20- Time until short break (15min 30sec) and long break (45min 20sec) - Short break:
SB 1:45- Time remaining in short break - Long break:
LB 8:30- Time remaining in long break - Overdue:
BREAK! 0:00 / 5:00- You've exceeded a break time - Snoozed:
3:20 (-2:30)- Snooze time remaining, and how overdue the most overdue break is - Paused:
⏸ PAUSED- Timer is paused, no activity is being tracked
Color Coding
- Green (normal): Plenty of time until next break
- Yellow (warning): Break due in less than 5 minutes
- Orange (overdue-short): Short break time has passed, you should take a break!
- Red (overdue-long): Long break time has passed, you should take a break!
- Blue (break): Currently in a break period
- Purple (paused): Timer is paused
- Grey (snoozed): An overdue break is snoozed
The overdue states also carry the overdue class, so one rule (such as a blink animation) can apply to both.
Using the Context Menu
Right-click the break timer widget in Waybar to access the context menu:
- Start Break: Start a break now: a long break if one is due, otherwise a short break. Keyboard or mouse input ends it.
- Snooze: Hide overdue breaks for 5 minutes (configurable). Does nothing if no break is due. Snoozing again restarts the 5 minutes, a break that comes due during the snooze also waits, and taking a break ends the snooze. The timers keep counting, so when the snooze ends the widget shows the true overdue amount. The icon changes to 💤 while snoozed.
- Toggle Reading Mode: For reading or watching without touching the computer. While on:
- Hands-off time counts as work instead of a break
- Breaks only start from Start Break, and end on input
- The widget icon changes to 📖 (via
format-icons)
- Skip Long Break: Reset all timers (useful if you just returned from a break not tracked by the timer)
- Toggle Pause: Pause or unpause the timer. While paused:
- No activity is tracked
- Idle detection is disabled (idle events are not logged)
- The widget shows "⏸ PAUSED" in purple
Log Management
- Location:
$XDG_RUNTIME_DIR/break-timer/activity.log(usually/run/user/1000/break-timer/) - Format: Simple text -
<timestamp> <event_type> - Auto-trim: Automatically cleaned when long breaks complete
- Size: Typically <10KB, contains only relevant recent events
- Persistence: Cleared on logout/reboot (starts fresh each session)
Troubleshooting
Waybar shows "???"
- Check if
break-statusis executable:chmod +x ~/.local/bin/break-status - Test manually:
break-statusshould output JSON - Check log exists:
ls $XDG_RUNTIME_DIR/break-timer/
Timers don't update
- Verify break-idle is running:
pgrep -af break-idle(if it exited, run it in a terminal to see the error) - Check if events are being logged:
cat $XDG_RUNTIME_DIR/break-timer/activity.log - Test event logging:
break-event idle_startthenbreak-event idle_end
Timers seem wrong
- Check your configuration:
cat ~/.config/break-timer/config.json - View raw log:
cat $XDG_RUNTIME_DIR/break-timer/activity.log - Delete log to reset:
rm $XDG_RUNTIME_DIR/break-timer/activity.log
Architecture
┌─────────────┐
│ break-idle │ Monitors compositor for keyboard/mouse activity
└──────┬──────┘
│ timeout → idle_start
│ resume → idle_end
▼
┌─────────────────────┐ ┌──────────────────────┐
│ break-event │────────▶│ activity.log │
│ - Append timestamp │ writes │ (event log) │
│ - Auto-trim old │ │ │
└─────────────────────┘ └──────────────────────┘
▲
│ reads
│
┌─────────────┐ ┌───────────────┴──────┐
│ Waybar │────────▶│ break-status │
│ (polls 1s) │ calls │ - Parse log │
│ │ │ - Calculate timers │
└─────────────┘ │ - Output JSON │
└──────────────────────┘
Similar Projects
- Workrave - The original, and a great app, but does not have very robust Wayland support at the time this tool was created.
- BreakTimer - Very nice interface, but only supports a single timer.
- ianny - Supports Wayland, but otherwise I have not explored deeply.
License
MIT