Skip to content

tagwerk

Work hours that track themselves on a Hyprland desktop, whether you were in a repo, a Slack thread or a Zoom call, with your coding agents’ time counted too.

Every CLI time tracker is manual, and manual discipline is what killed the timewarrior setup this one replaces: a forgotten start, a forgotten stop. tagwerk has no start and no stop. On Hyprland it watches which repo your terminal or coding agent sits in, which window has focus, and whether you are idle, then credits every present minute to a project. A repo takes the minute while one is active. Otherwise the focused window decides, so a Slack thread or a Zoom call books to work and an unrecognised window to personal. It answers two questions and no others: what goes on this month’s invoice, and whether last week was too long a week.

Piece What it does
Focus poller tagwerk focus as a systemd user service polls window class, title and terminal cwd
hypridle tagwerk idle and tagwerk active from the idle listener and around sleep
Agent hooks Claude Code hooks and a pi extension run tagwerk beat with the agent’s cwd
Ledger ~/.local/share/tagwerk/YYYY-MM.jsonl, append-only, UTC timestamps
Reports day, week, month, invoice; fix appends a span

Nothing in the ledger is ever edited. A fix is a new span appended after the fact, and the latest one wins.

A minute is present when you are not idle and a poll landed within the last 2 minutes. Each leased kind is credited a whole present minute, so a day’s total meets wall-clock presence and rises above it on a day spent in two kinds at once.

An agent beat leases its repo for 10 minutes. A focused terminal’s cwd, or a window title naming a repo, leases for 1 minute. A leased repo keeps earning while an unrelated window is focused — a browser tab during a long agent turn still books to the repo. Two leased repos split each minute evenly.

With no lease, the focused window decides: a shell sitting at a root books that kind’s general, a work-pattern title books work/general, and anything else books personal/other.

Beats while idle book nothing, so an unattended overnight agent adds no hours.

Concepts covers presence, the even split and the two catch-alls in full.

kind counts toward the week cap on the invoice
work yes yes
fixed yes no
personal no no
off no no

A fixed-price customer’s hours belong in the burnout check and never on an hourly customer’s bill. The day cap asks a different question and no kind answers it: it counts presence, personal included, because burnout does not care who paid for the hour.

A kind never names the payer.

Terminal window
paru -S tagwerk-git
tagwerk init && $EDITOR ~/.config/tagwerk/config.toml
systemctl --user enable --now tagwerk-idle.service tagwerk-focus.service

tagwerk itself has no runtime dependencies and tracks master. It is built and tested on Omarchy 4; any Arch Hyprland works and the terminal sensor reads every terminal, while the bar widget is Omarchy only. The Claude Code hooks and the pi extension are part of that install, not an optional extra: without them a minute of background agent work is credited to the focused window instead of the agent’s repo. tagwerk doctor reports one row per sensor — live, dark or unknown — so a missing hook is easy to tell apart from a repo outside your roots.

Installation covers the units, the hypridle choice, the uwsm requirement and how a terminal cwd is resolved; Verification proves each sensor fires.