2025-10-27 Org mode burst timer

Org mode has two built-in timers – the “relative timer” (which is basically a stopwatch – it starts with 0 and counts up), useful for taking meeting minutes with an indication of when things were discussed, and a “countdown timer” (which is, well, a countdown timer – you tell it a duration, it counts down from it, and rings a bell when it gets to zero).

What I sometimes miss is the following feature. I’d like to have some kind of timer which would tell me when a given amount of time passed, but then it would keep running. For instance, let’s assume that I want to write this blog post for at least 25 minutes, but also measure the time I spend doing it even if I keep writing for longer.

Of course, this is more or less what my tomato.el did from early on (and what I partially recreated with ketchup.el). Interestingly, Org mode has a very similar feature built-in. When you set an effort estimate on a task and clock it, you’ll get notified after reaching your estimate. However, this is not exactly what I need – I’d like to have a similar feature but also for “bursts of work”. I have some long-running tasks for which the effort estimate doesn’t make sense – for example, when I read a book, I often track the time I spend on it. On the other hand, I usually want to read said book for at least N minutes per day (of course, those who read my blog regularly will guess that this is tied to Beeminder), and it’s best to spend that time in one session.

So, let’s get working on this. I’m going to write some code which will be tied to the Org mode clocking mechanism, and if a clock is started on a task which has a burst property, it will start a timer to notify me that many minutes later. (I don’t need my feature to display how much time has passed since I started the clock, since I have org-clock-mode-line-total set to current.) This could be a global minor mode, but since I do not envision turning this feature off, and it will only influence anything when a very specific property is set, I’m fine with just having it on all the time.

(defvar burst--timer nil
  "Timer for bursts of work.")

(defun burst-run-timer ()
  "Run the burst timer."
  (when-let* ((burst-string (org-entry-get (point) "burst" t))
              (burst (string-to-number burst-string)))
    (setq burst--timer
          (run-with-timer (* burst 60)
                          nil
                          #'org-notify
                          (format "%s minutes have passed"
                                  burst)
                          org-clock-sound))))

(defun burst-cancel-timer ()
  "Cancel the burst timer."
  (when (timerp burst--timer)
    (cancel-timer burst--timer)))

(add-hook 'org-clock-in-hook #'burst-run-timer)
(add-hook 'org-clock-out-hook #'burst-cancel-timer)
(add-hook 'org-clock-cancel-hook #'burst-cancel-timer)

In fact, the code is very similar to the one I wrote for my ketchup feature. The difference is in the condition used to start the timer. I am wondering if this means that an abstraction for “run a timer when clocking in, cancel it when clocking out or canceling the clock” could be useful.

Anyway, that’s it for today – although while writing this, I had an even better idea, so expect a follow-up to this post soon!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode