POSIX shell task timer with periodic reminders, batch mode, FIFO support, and no external dependencies.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-04 04:33:01 -07:00
.gitignore feat: add backup and temporary file patterns to gitignore 2026-06-03 14:45:02 -07:00
.markdownlint.yaml feat: add markdownlint configuration to disable specific rules 2026-06-03 14:48:32 -07:00
.pre-commit-config.yaml feat: add pre-commit configuration for code quality checks 2026-06-03 14:48:42 -07:00
mortality variable break duration based on completed task length 2026-06-04 04:27:33 -07:00
README.md document batch mode behavior and FIFO streaming 2026-06-04 04:29:21 -07:00
ROADMAP.md docs: update roadmap with completed signal handling tasks 2026-06-03 15:08:30 -07:00

mortality

Periodic task timer for the terminally impatient. Pure POSIX sh, zero dependencies.

Features

  • Two calling conventions — single task or batch from file / FIFO
  • Periodic reminders — frequency increases exponentially as time runs low
  • Post-timer prompt — mark done or extend by N minutes
  • Batch mode — process tasks sequentially, no prompts, auto-breaks between
  • FIFO streaming — feed tasks via named pipe, keeps running for more
  • SIGINT handling — prompt to exit or resume on Ctrl+C
  • Portable — runs on any system with /bin/sh (Linux, macOS, BSD)

Requirements

A POSIX-compliant /bin/sh shell. That's it. No bc, perl, Python, or other dependencies. Uses only shell builtins, sleep, date, and printf.

Installation

Drop the mortality script somewhere on your PATH and make it executable:

chmod +x mortality
cp mortality ~/.local/bin/

Or run it straight from the repo:

./mortality 30m "write documentation"

Usage

Single task

mortality <duration> <task description>
Argument Description Example
duration A number followed by m (minutes), h (hours), or s (seconds) 30m, 1h, 45s
task description What you're timing "review PR #42"
mortality 25m "code review"
mortality 1h "write design doc"
mortality 90s "standup update"

Task list (batch mode)

mortality <task-list.txt>

The file must contain one task per line in the format:

<duration>,<task description>

Example tasks.txt:

25m,code review
10m,standup
45m,write documentation
15s,stretch break

Empty lines are ignored. Duration format is the same as CLI mode.

Batch mode behavior

Unlike interactive mode, batch mode skips all prompts:

  • Tasks start immediately — no ENTER to start prompt
  • Tasks auto-complete — no Done? (y/n) prompt (cannot extend)
  • Between tasks a break is automatically injected based on the just-completed task's length:
Completed task duration Break
< 30m 60s pause, then next task (no timer)
>= 30m && < 1h 60s pause, then 5m break timer
>= 1h && < 4h 60s pause, then 15m break timer
>= 4h && <= 8h 60s pause, then 60m break timer

The MORTALITY_COMPLETE_FORMAT notification fires before the pause, so you can chain notifications into external systems before the break starts.

FIFO / streaming mode

Pass a named pipe (FIFO) instead of a regular file for continuous operation:

mkfifo tasks.fifo
mortality tasks.fifo

Then feed tasks from another terminal or script:

echo '30m,write report' > tasks.fifo
echo '15m,review findings' > tasks.fifo

Mortality reads one task at a time, runs it with batch-mode rules (auto-start, auto-complete, break injection), then blocks waiting for the next task on the FIFO. It stays running until killed (Ctrl+C prompts to exit).

Note: Validation (validate_tasklist) is skipped for FIFOs since the input stream never ends. Malformed lines will still be caught by parse_duration and cause an exit.

Interactive session

  1. Press ENTER to start the timer
  2. Timer runs silently — periodic reminders print time remaining:
    • Every 60s during the last 5 minutes
    • Doubles for each 10-minute chunk before that (2 min at 5-15m, 4 min at 15-25m, 8 min at 25-35m, ...)
  3. Time's up! — terminal bell rings
  4. Prompt: Done? (y/n)
    • y / Y — "Good job." and exits / moves to next task
    • n / N — asks "How many more minutes?" (default 5) and resumes timer
  5. Repeat from step 2 until done

Signal handling

Press Ctrl+C during any prompt or the countdown:

Interrupted. Exit? (y/n)
  • y / Y — exits cleanly
  • n / N — resumes the timer or re-prompts

External notifications

Set MORTALITY_PROMPT_CMD to a command that reads a line from stdin. Each reminder message is piped to it in addition to stdout.

export MORTALITY_PROMPT_CMD='9p -a 10.24.10.22:564 write /message'
mortality 30m "deploy to production"

This lets you forward reminders to a notification system, pager, LED display, or whatever $MORTALITY_PROMPT_CMD can reach.

Format strings

All notification messages are configurable via printf-compatible format strings. Available arguments depend on the message type.

MORTALITY_START_FORMAT — start message (default: Start Task:\n%s\nTimebox: %02d:%02d:%02d\n)

  • %s — task description
  • %02d — hours, minutes, seconds

MORTALITY_UPDATE_FORMAT — periodic reminder (default: ... you have %02d:%02d:%02d left ...)

  • %02d — hours, minutes, seconds

MORTALITY_COMPLETE_FORMAT — task done message (default: Good job.)

  • %s — task description

MORTALITY_END_FORMAT — end message (default: Task Complete: %s)

  • %s — task description

Development

pre-commit install     # install git hooks
pre-commit run --all   # run all checks

Checks: shellcheck, shfmt (POSIX dialect), trailing whitespace, YAML lint, markdownlint.

Project status

Active development. See ROADMAP.md for planned phases and issues for current work.