From d15531a76f87e29e32c18ba64445003cafe1734a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 23 Jun 2026 12:12:29 +0200 Subject: Initial commit: breaktimer break-reminder daemon with Waybar module Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 CLAUDE.md (limited to 'CLAUDE.md') diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f47ab25 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,45 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +`breaktimer` is a Bash break-reminder daemon for a Linux/Wayland desktop (dunst + pipewire + Waybar). No build, no package manager, no tests — it's a single shell script plus Waybar integration files. Comments and notification strings are in Italian; keep that convention when editing. + +## Running + +```bash +./breaktimer.sh start|stop|restart|pause|resume|toggle|status +./breaktimer.sh run # internal: the daemon loop, not called directly +``` + +Dependencies: `dunst` (notify-send), `pipewire` (pw-play, paplay fallback), coreutils. + +## Architecture + +State machine: `working -> (notify) -> breaking | longbreak -> working`. Every `LONG_EVERY` (4th) work block triggers a long break instead of a micro-break. + +**Time model is the core invariant** (breaktimer.sh:8-10): the daemon persists REMAINING seconds of the current phase, not absolute timestamps. Each `TICK` (5s) it decrements REMAINING *only while working/counting*. Consequences: +- Manual pause (`paused` state) freezes the countdown — tick `continue`s without decrementing. +- Outside the `WORK_START`..`WORK_STOP` window, the `working` phase freezes (breaks still count down). +- Breaks never erode work time. + +Any change to the loop must preserve "freeze = don't decrement REMAINING" so the Waybar countdown stays coherent. + +### Daemon mechanics +- `start_daemon` forks via `setsid "$0" run`. It does **not** write the PID itself — `$!` after a `setsid &` is not the loop's real PID. Instead the loop writes its own `$$` to the PID file, and `start_daemon` polls `is_running` until it appears (then reports success/failure). +- **Singleton guard**: `run_loop` refuses to start (exit 1) if the PID file names a *live* process other than itself (`kill -0`). This stops a stray `breaktimer.sh run` from clobbering a running daemon's shared state files. +- All state lives in files under `$XDG_RUNTIME_DIR` (falls back to `/tmp`): `breaktimer.pid`, `.state` (running|paused), `.phase` (working|breaking|longbreak|stopped), `.remain` (seconds). Subcommands like `pause`/`toggle` work by writing these files; the running loop reads them each tick. This file-based IPC is how the CLI talks to the daemon. +- **TERM/INT `cleanup` trap deliberately does NOT delete the PID file.** Bash defers a trap until the current `sleep` returns (up to `TICK`=5s), so on `restart` the *old* daemon's trap fires ~5s after the *new* one already wrote its PID — deleting it there would orphan the new daemon. A stale PID file is harmless because `is_running` uses `kill -0`; the next `start` overwrites it. The trap only writes `stopped` and removes `.remain`. + +### Config +Tunables are top-of-file variables in breaktimer.sh: timing (`MICRO_MIN`, `BREAK_MIN`, `LONG_MIN`, `LONG_EVERY`), work window (`WORK_START`, `WORK_STOP`), urgency levels, and sounds. + +**Sounds**: three events — micro-pause, long-pause, back-to-work — each with a `SOUND_*` user override and a `SYS_SOUND_*` default. Defaults point at `$SOUND_DIR` (`~/.local/share/sounds/modern-minimal-ui-sounds/stereo`): `message-new-instant.oga` / `alarm-clock-elapsed.oga` / `service-login.oga`. `sound_for_{micro,long,back}` use the override if set and the file exists, else the default. Playback via `pw-play`, falling back to `paplay`. Empty/missing file = silent (no error). + +## Waybar integration + +- `waybar-breaktimer.config.jsonc` — the `custom/breaktimer` module: polls every 5s, left-click `toggle`, right-click `restart`, expects `return-type: json`. +- `breaktimer.css` — phase-colored styling for `#custom-breaktimer.{working,breaking,longbreak,paused,stopped}` (Catppuccin colors). + +- `waybar-breaktimer.sh` — JSON status emitter the Waybar `exec` calls. Reads the `.phase`/`.remain`/`.state` files (no time recomputation — the daemon already froze `.remain`), maps phase -> CSS `class`, formats `.remain` as `m:ss`, and prints `{text, class, tooltip}`. Nerd Font glyphs in `text`. Returns the `stopped` class when the daemon isn't running. -- cgit v1.2.3