Files

5.2 KiB

Waybar Time Tracker

A small, dependency-free Python time tracker for Waybar with a start/stop button and timesheet generation.

Features

  • Start / stop button in Waybar: click the module to toggle tracking.
  • Live elapsed time shown in the bar while running.
  • Persistent JSON storage in ~/.local/share/time_track/data.json (override with TIME_TRACK_DIR).
  • Timesheet generation in Markdown, grouped by task and by day.
  • Optional server sync of completed entries, using environment-only configuration.

Files

File Purpose
time_track.py Main CLI and Waybar interface
waybar-config.json Example Waybar custom module configuration
waybar-config.jsonc Same example, with comments (for Waybar JSONC configs)
style.css Example CSS for the running/idle states

Installation

  1. Make sure time_track.py is executable:

    chmod +x /path/to/time_track/time_track.py
    
  2. Add the custom module from waybar-config.json (or waybar-config.jsonc) to your Waybar config (~/.config/waybar/config or ~/.config/waybar/config.jsonc).

  3. Add the CSS from style.css to your Waybar stylesheet (~/.config/waybar/style.css).

  4. Update the paths in the config to point to wherever you placed time_track.py.

Why the module might not show

If the Waybar module appears but has no text, check that "format" is not empty. When return-type is "json", Waybar replaces "{}" with the text field emitted by the script. An empty format ("") makes the module invisible. Use "format": "{}" or omit the field entirely.

CLI usage

# Start a session (will prompt for a task; empty is allowed)
./time_track.py toggle

# Start a session without a prompt, using a specific task
./time_track.py toggle "client-a"

# Stop the active session (same as ./time_track.py stop)
./time_track.py toggle

# Emit Waybar JSON (used by the module)
./time_track.py status

# Show the active session
./time_track.py current

# Stop the active session
./time_track.py stop

# Show recent entries
./time_track.py log
./time_track.py log 25

# Generate a Markdown timesheet
./time_track.py timesheet week
./time_track.py timesheet month

# Sync completed entries (after setting the environment variables below)
./time_track.py sync

Optional server sync

Sync is disabled unless all configuration is provided through the process environment. No server URL, token, or device identifier is written to a configuration file.

export TIME_TRACK_SERVER_URL="https://time-track.example.com"
export TIME_TRACK_SERVER_TOKEN="your-api-token"
export TIME_TRACK_DEVICE_ID="laptop-2026"
./time_track.py sync

sync sends a POST request to ${TIME_TRACK_SERVER_URL}/api/v1/sync/time-track with Authorization: Bearer <token> and a 15-second timeout. Its JSON request body is:

{
  "device_id": "laptop-2026",
  "entries": [
    {
      "id": "6cf5c9f0-7f65-4fcd-a76f-02cc2a9f3ca3",
      "task": "client-a",
      "start": "2026-09-14T09:00:00",
      "end": "2026-09-14T10:00:00",
      "duration": 3600
    }
  ]
}

Only finished entries are sent. Each completed entry receives a stable UUID. On first load after upgrading, historic entries are assigned UUIDs and the local data file is updated, so repeating a sync submits the same entry IDs for server-side idempotency. The active session is never uploaded.

Automatic sync (systemd user timer)

A systemd user pair can run sync on a schedule:

  • time-track-sync.service (oneshot; reads %h/.config/time-track-sync/env and runs time_track.py sync)
  • time-track-sync.timer (every 15 minutes, Persistent=true to catch up after sleep)

The env file holds the same three variables as above, with mode 600. Because the client re-sends all finished entries and the server dedupes by entry UUID, resending is safe; a race with a concurrently toggling tracker can at worst skip one cycle. The timer does not upload the active session.

Useful commands:

systemctl --user start time-track-sync.service            # run a sync now
systemctl --user list-timers time-track-sync.timer        # next scheduled run
journalctl --user -u time-track-sync.service -f           # live logs

Waybar behavior

  • Left click: start or stop a session.
    • When starting, a task prompt appears. The launcher order is wofi, rofi, bemenu, dmenu, then zenity, then a terminal fallback.
    • Existing tasks are shown as a dropdown/list. Type a new task or pick an existing one.
    • Press Enter with no input to start with an empty task.
    • Press Escape / Cancel to abort starting.
  • Right click: print the current week's Markdown timesheet to stdout (useful bound to a notification or terminal).
  • The module updates every 5 seconds while running.

Task prompting requirements

For the click-to-start prompt to work from Waybar you need one of these installed:

Launcher Notes
wofi Best for Wayland; shows previous tasks as a dropdown and allows typing new ones
rofi Works on X11 and Wayland
bemenu Wayland/X11 dmenu alternative
dmenu Classic suckless dmenu
zenity GTK entry dialog (no dropdown, but supports empty input)

If none are installed, the script falls back to a terminal prompt when run from a TTY.