herdr plugin: a pomodoro timer with notifications, a sidebar token, hooks, and a state file for statuslines and keyboard lights
This repository has been archived on 2026-10-18. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
  • Shell 76.2%
  • Lua 22.4%
  • Makefile 1.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-18 04:05:16 +00:00
.github/workflows ci: allow manual runs (#5) 2026-10-13 21:18:31 +00:00
assets docs: new icon, centred above the README (#4) 2026-10-13 21:42:36 +11:00
bin feat!: keybars Pro's Focus names for phases and hooks (#6) 2026-10-18 01:10:06 +00:00
lua/herdr-pomodoro feat!: keybars Pro's Focus names for phases and hooks (#6) 2026-10-18 01:10:06 +00:00
tests feat!: keybars Pro's Focus names for phases and hooks (#6) 2026-10-18 01:10:06 +00:00
.busted feat: Neovim statusline component (#1) 2026-10-11 02:24:32 +11:00
.luacheckrc feat: Neovim statusline component (#1) 2026-10-11 02:24:32 +11:00
.stylua.toml feat: Neovim statusline component (#1) 2026-10-11 02:24:32 +11:00
config.env.example feat: herdr plugin for a pomodoro timer with hooks and a readable state file 2026-10-11 02:04:02 +11:00
herdr-plugin.toml feat!: keybars Pro's Focus names for phases and hooks (#6) 2026-10-18 01:10:06 +00:00
LICENSE feat: herdr plugin for a pomodoro timer with hooks and a readable state file 2026-10-11 02:04:02 +11:00
Makefile feat: Neovim statusline component (#1) 2026-10-11 02:24:32 +11:00
README.md docs: moved into herdr-keybars (#7) 2026-10-18 04:05:16 +00:00

herdr-pomodoro

herdr-pomodoro

Moved into herdr-keybars, which does this (a pomodoro timer, now keybars Pro's Focus timer with herdr actions, a $focus sidebar token and break notifications) alongside your agents on the keyboard. This plugin isn't developed further; uninstall it and install herdr-keybars.

A herdr plugin: a pomodoro timer with notifications, a sidebar token and hooks. Its state is one JSON file, so anything can show it: a Neovim statusline, keyboard lights, a shell prompt.

  • 25 minutes of work, a 5 minute break, and a 15 minute break every fourth round (all configurable).
  • A herdr notification when each phase ends.
  • $pomo in the sidebar, e.g. 🍅12m.
  • Hooks: run your own commands when a round starts or ends.

Requirements

  • herdr 0.9.3+
  • jq, bash

Install

herdr plugin install jwarykowski/herdr-pomodoro

Bind the toggle in herdr's config.toml, and add $pomo to the sidebar if you want it there:

[[keys.command]]
key = "prefix+p"
type = "plugin_action"
command = "jwarykowski.herdr-pomodoro.toggle"
description = "start / stop the pomodoro"

[ui.sidebar.spaces]
rows = [["state_icon", "workspace", "$pomo"], ["branch", "git_status"]]

Actions

action does
jwarykowski.herdr-pomodoro.toggle stop if running, else start
jwarykowski.herdr-pomodoro.start start a work round (the next round after a break)
jwarykowski.herdr-pomodoro.stop stop and reset the round count
jwarykowski.herdr-pomodoro.skip end the current phase now

When a break ends the timer waits for you to start the next round; set HERDR_POMODORO_AUTO_CONTINUE=1 to carry straight on.

State file

${XDG_STATE_HOME:-~/.local/state}/herdr-pomodoro/state.json:

{"phase": "work", "started_at": 1760160000, "ends_at": 1760161500, "round": 2, "long": false}

phase is work, break, or "" between rounds (ends_at null), as keybars Pro's Focus timer names them; long is true for every fourth break. Times are unix seconds, so a reader works out the remaining time itself and nothing has to tick. No file means no timer.

bin/pomodoro status prints one line for prompts and status bars (🍅 12:34, ☕ 3:10, ⏸, or nothing). bin/pomodoro status -json prints the timer as keybars-pro focus status -json prints Focus, so one reader handles both:

{"phase": "work", "remaining": 742, "length": 1500}

Neovim

The repo is also a Neovim plugin with a statusline component. With lazy.nvim:

{ "jwarykowski/herdr-pomodoro", lazy = true }

require("herdr-pomodoro").status() returns 🍅 12:34, ☕ 3:10, ⏸ or ""; .state() returns the decoded state file for your own rendering. It reads the file at most once a second, so it is cheap on every redraw. With lualine:

sections = {
	lualine_x = { function() return require("herdr-pomodoro").status() end, "filetype" },
},

Change the icons with require("herdr-pomodoro").setup({ icons = { work = "W", ["break"] = "B", idle = "-" } }).

Hooks

An executable in $(herdr plugin config-dir jwarykowski.herdr-pomodoro)/hooks/ named after an event runs when it happens. The names are keybars Pro's Focus events, so a hook can pass them straight on with keybars-pro notify:

event when
focus.started a work round starts
focus.break a work round ends and a break starts
focus.done a break ends and the timer waits for the next round
focus.stopped the timer is stopped

With HERDR_POMODORO_AUTO_CONTINUE=1 a break runs straight into the next round, which fires focus.started instead of focus.done.

Hooks get HERDR_POMODORO_EVENT, _PHASE, _ROUND, _ENDS_AT and _STATE (the state file path), and log to hooks.log next to it. For example, hooks/focus.break:

#!/bin/sh
keybars-pro notify focus.break

herdr-keybars's setup links these for you, and runs keybars Pro's Focus alongside.

Configuration

Optional. Put overrides in config.env inside the plugin config directory; see config.env.example.

Development

make lint    # shellcheck, stylua --check, luacheck
make test    # busted (specs run under Neovim via nlua)

Support

herdr-pomodoro is free and MIT licensed. If it keeps you focused, you can sponsor its development.

License

MIT