timerd-rs
timerd-rs is a small Linux terminal timer. Its name combines timer with
the Unix convention of using a trailing d for a daemon. It installs the
simple command timer and supports a stopwatch, a countdown, and one-time
wall-clock alarms. A per-user background process owns timer state, so the
foreground display can detach and attach again without stopping the timer.
Install
Install timerd-rs from crates.io:
Or install it from a local checkout:
The Cargo package is named timerd-rs; the installed executable is named
timer.
Start a timer
Run without arguments for an interactive choice between a stopwatch and a countdown:
Or start one directly:
A bare number is interpreted as seconds. Two-part clock input is MM:SS, and
three-part clock input is HH:MM:SS.
Add a note or start detached:
Schedule an alarm
Use at to schedule a one-time reminder at a local clock time. alarm is a
readable alias for the same command:
Accepted inputs are HH:MM, HH:MM:SS, YYYY-MM-DD HH:MM, and
YYYY-MM-DD HH:MM:SS. A clock time such as 08:00 means the next occurrence:
today when it is still ahead, otherwise tomorrow. An explicit date must be in
the future. All inputs use the machine's local timezone.
In the foreground, the large value is the remaining time while the target and description stay fixed:
00:24:37
alarm #12 · at 08:00 · running · eat breakfast
d detach | x cancel | +/- size (medium)
Alarms are tied to an absolute time and therefore cannot be paused or resumed. They can be detached, attached, listed, or cancelled like other timers. This release schedules one occurrence only; it does not create a daily repeating alarm.
Terminal bell
Add -b/--bell to a countdown or alarm to ring the terminal bell when it
finishes:
Use --no-bell to explicitly disable it. There is no -nb spelling because
short options are single characters and -n already means --note. Bell is
disabled by default, so --no-bell is mainly useful for explicit scripts and
future configuration overrides.
The bell is the standard terminal BEL control character (0x07). It has no
server-side audio or library dependency: over SSH, the byte travels through the
session and the local terminal emulator decides whether to play a sound, flash,
show a tab indicator, or ignore it. A foreground timer rings once before its
completion line; a detached timer sends the bell with its completion message to
the terminal that created it. Closing that SSH session still makes delivery
impossible, just like the ordinary completion message.
iTerm2 setup
The server cannot override the local iTerm2 profile. To hear or see the bell:
- Open iTerm2 > Settings > Profiles > Terminal for the profile used by the SSH session.
- Under Bell, clear Silence bell. Leaving it selected suppresses the
sound even when timerd successfully sends
BEL. - Choose a Bell sound if desired. Flash visual bell and Show bell icon in tabs are optional visual alternatives.
- To request a macOS banner, enable Notification Center alerts, open Filter Alerts, and enable Send "Bell" alert. macOS must also allow notifications for iTerm2 in System Settings.
Test the same SSH session before relying on a timer:
(; ) &
If neither test produces the configured sound, flash, icon, or alert, timerd
cannot force that terminal to show one. Stopwatch does not accept --bell,
because it has no natural completion point.
Choose one of four fixed foreground display sizes:
The accepted names are small, medium, large, and xlarge. Their short
values are s, m, l, and xl; 1, 2, 3, and 4 are also accepted.
small keeps the original one-line display. Larger sizes use built-in block
digits and automatically fall back when the terminal is too narrow or short.
Because a detached timer has no foreground display, --size and --detach
cannot be used together; choose a size when attaching instead.
Animated themes
Themes are optional. Without -t/--theme, the foreground display remains
the same plain timer as before. Enable the bundled sleepy-cat theme when
starting or attaching to a timer:
Discover, preview, and validate themes with:
During a themed foreground session, press ] for the next discovered theme
or [ for the previous one. The cycle includes none, which hides the art
without stopping the timer. These keys only become active when the session was
started or attached with a theme option.
User themes are loaded automatically from
$XDG_CONFIG_HOME/timerd-rs/themes, or ~/.config/timerd-rs/themes when
XDG_CONFIG_HOME is not set. The filename is the theme name, so a file named
my-cat.toml is selected with timer 5m -t my-cat. A theme needs at least one
running frame; paused and done frames are optional:
= 1
= "My Cat"
= 4
= "center"
[[]]
= """
/\___/\
( o o )
( ^ )
"""
[[]]
= """
/\___/\
( - - )
( ^ )
"""
[[]]
= """
/\___/\
( z z )
( ^ )
"""
[[]]
= """
\ | /
\(^)/
/ \
"""
Each art opening and closing """ must be on its own line. Theme art is
printable ASCII data only: terminal control characters are rejected, and frame
counts and dimensions are bounded. To contribute a bundled theme, add one TOML
file to the repository's themes directory; the build script discovers
and embeds it automatically, with no Rust registration table to edit.
Foreground controls
While the foreground display is active:
| Key | Action |
|---|---|
Space |
Pause or resume |
d |
Detach while keeping the timer running |
Ctrl-B, then D |
tmux-style alias for detach |
x |
Stop the stopwatch or cancel the countdown |
Ctrl-C |
Same as x |
+ or = |
Increase the display size |
- |
Decrease the display size |
1–4 |
Select small through xlarge directly |
[ / ] |
Previous / next theme, including none (themed sessions only) |
Attach again with the complete command or its short alias:
Without an ID, attach selects the most recently used detached timer. Only one foreground client may control a timer at a time.
Configuration
The built-in default display size is small. To change it for future
foreground displays, create $XDG_CONFIG_HOME/timerd-rs/config.toml, or
~/.config/timerd-rs/config.toml when XDG_CONFIG_HOME is not set:
[]
= "large"
Configuration accepts the full values small, medium, large, and
xlarge. A command-line --size value takes precedence over the file, while
the +, -, and number keys affect only the current foreground session.
Inspect the path and active value with:
A missing file is valid and uses small; an invalid setting reports its file
and parse error. The configuration is read by each new foreground invocation,
so the daemon does not need to restart.
Manage timers
Every frequent command has a readable name and a short alias:
When an ID is omitted, the daemon selects the most recently used compatible
timer. clear removes finished, stopped, and cancelled records.
timer watch opens a live view of every running or paused task. The final
CREATED column is the task creation time in the machine's local timezone:
ID TYPE STATUS TIME TARGET NOTE CREATED
> 12 alarm running 00:24:37 08:00 eat breakfast 2026-10-29 07:35:23
13 countdown running 00:04:12 08:10 coffee 2026-10-29 08:05:48
14 stopwatch paused 01:32:08 - coding 2026-10-29 06:37:52
Use the following keys inside the watch view:
| Key | Action |
|---|---|
Up / Down (or k / j) |
Select a task |
Enter |
Leave the watch view and attach to the selected task |
x |
Stop a stopwatch or cancel a countdown/alarm |
s |
Snooze: add a duration to a countdown or delay an alarm |
e |
Edit the note and, when applicable, remaining duration or alarm target |
q, Esc, or Ctrl-C |
Exit the watch view without stopping tasks |
Snooze accepts the same duration forms as countdown creation, such as 30s,
5m, or 1h30m. Editing a countdown replaces its remaining duration; editing
an alarm accepts the same local clock/date formats as timer at. A stopwatch
has no deadline, so it supports note editing but not snooze.
Shell completions
Generate completion code with timer completions SHELL (the singular
completion spelling is also accepted). For Fish:
mkdir -p ~/.config/fish/completions
timer completions fish > ~/.config/fish/completions/timer.fish
For Bash:
For Zsh, generate _timer into a directory included in fpath:
fpath=(/.zfunc )
&&
Elvish and PowerShell are also supported. Generated completions cover commands, aliases, options, shell names, and bundled theme names. User-installed theme names remain free-form. Regenerate the completion file after an upgrade so newly added options and bundled themes are included.
Countdown and alarm completion
For a detached countdown, the daemon keeps a write handle to the terminal that created it. If that terminal or SSH session is still open, completion appears there as ordinary terminal output:
[timer #3] ✓ countdown finished · stretch break
This does not depend on a desktop notification service, iTerm2 escape codes,
tmux, or screen. If the original terminal has closed, the write is allowed to
fail and the timer still becomes done. Its result remains visible in
timer list.
A detached alarm uses the same terminal-session mechanism and includes its target clock and description:
[timer #12] ⏰ 08:00 · eat breakfast
An asynchronous completion line can visually interrupt text currently being typed at the shell prompt. The typed input remains owned by the shell, but a prompt redraw may occasionally be necessary.
Files and process model
timer is a single crate and a single executable. On first use, that executable
starts itself in a hidden daemon mode. The CLI and foreground renderer talk to
it over a private Unix socket.
Runtime files follow the XDG directory conventions:
$XDG_RUNTIME_DIR/timer-rs/timer.sock
$XDG_STATE_HOME/timer-rs/state.json
$XDG_STATE_HOME/timer-rs/daemon.log
When the corresponding variables are unset, state is stored under
~/.local/state/timer-rs, and the socket uses a user-specific directory under
/tmp.
The daemon can be stopped explicitly:
Shutdown is refused while any timer is running or paused, because stopping the service would prevent timely completion messages.
Active task metadata is persisted, but a terminal write handle cannot survive a daemon restart. On systems configured to kill all user processes at logout, a future systemd user-service integration may be needed for timers that must survive a complete logout.