aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-06-23 12:12:29 +0200
committerDanilo M. <danix@danix.xyz>2026-06-23 12:21:50 +0200
commitd15531a76f87e29e32c18ba64445003cafe1734a (patch)
tree52c4c17434b4cba9212a32907a149a592fb185e4 /CLAUDE.md
downloadbreaktimer-d15531a76f87e29e32c18ba64445003cafe1734a.tar.gz
breaktimer-d15531a76f87e29e32c18ba64445003cafe1734a.zip
Initial commit: breaktimer break-reminder daemon with Waybar module
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md45
1 files changed, 45 insertions, 0 deletions
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.