Troubleshooting
Every item here is known and deliberate. A dark sensor is a different problem: Verification covers reading and fixing those.
Attribution
Section titled “Attribution”- Poll granularity is
poll_sec, with a re-poll every 60 s. Hyprland’s event socket was rejected as the trigger: it cannot see acdinside a terminal, and it emits a title event per spinner frame. - A repo whose name contains a dot is truncated at it, because the project is cut at its first dot. Give such a repo its own root, or rename the directory and add a
[rename]entry so the old minutes follow. - A directory that holds worktrees books every worktree under it to the container’s name, for the same reason. Give the container its own root: the longest match then picks it, and the repo name below it becomes the project.
- Because a rename keys on the project name rather than the path, two repos sharing a name under different roots fold together. A rename is also single-hop, so renaming twice means pointing both old names at the current one.
- Idle inhibitors are honoured, so an abandoned video call stays present and books
personal/other. That reaches the chart and never the invoice. If it bothers you, copy/usr/share/tagwerk/hypridle.conf, setignore_dbus_inhibit = truein the copy, and point hypridle’s--configat it withsystemctl --user edit tagwerk-idle.service. - Spans written before
tscarried microseconds resolve by file order when two of them share a second across month files. Their append order was never recorded, so no rewrite can fix it (ADR-0009). - A shell under tmux, screen or another multiplexer is not a direct child of its terminal, so
/procresolves no cwd for that window and its minutes fall through to the title rules. kitty reads the pane’s foreground process instead, which under a multiplexer is the client, so a kitty pane inside tmux books the directory tmux itself was launched in. - A terminal window holding more than one login shell resolves no cwd rather than picking one, so a split or tabbed terminal that is not kitty books nothing to a repo (ADR-0016). kitty is exact in that case, because its socket names the focused pane.
- The login-shell check reads
/etc/shells, which packages register as they install, so a shell built by hand is invisible to it and its terminal resolves no cwd.
doctor
Section titled “doctor”- A beat sensor reads
darkonly when its own agent readswired, so an agent you never installed readsunknowninstead of alarming (ADR-0013). - The Claude check reads
~/.claude/settings.jsononly, so a hook wired in a project’s own.claude/settings.jsonreadsmissingand its beats then go unjudged rather than dark. - It judges a root by whether it is a directory right now, so a root on an unmounted drive reads
suspectuntil you mount it. That costs a row and exit 3, never a number in a report. - The cwd row reads
suspectwhen no poll insidepoll_dark_hcarried a working directory, so a week spent without opening a terminal reads the same as a terminal sensor that cannot resolve one. It is advisory for that reason, and a poller already readingdarkgets no cwd row at all. - It tests each
[[title]]pattern against every title on its own, so a pattern permanently shadowed by an earlier one still reads clear. Attribution takes the first match, and replaying that order across the whole ledger would cost more than the typo it would catch. - Exit 2 is shared with argparse, which spends it on a usage error, so
tagwerk doctor --bogusalarms a shell prompt exactly as a dark sensor does.
Reports
Section titled “Reports”- Colours come from five hues that pass the contrast check, so past five work repos two projects share one.
- Reports rescan the month files on every run. A month is about 43k minutes and a few thousand events, which is fine for years of data.
day --jsonjudgesover_capon a rounded cap, while theweekbar reddens on the unrounded one. Both measure presence, so they agree except on a fractionalday_cap_hwithin half a minute of the boundary.
Bar widget
Section titled “Bar widget”- It notches the day cap alone.
week_cap_his arguably the better burnout signal, but--jsonisdayalone, so a 38-hour week reads quiet there on Friday morning. - It redraws on a timer, so it trails the true minute by up to
refreshIntervalSec: 300 s by default, which is a fifth of a pixel of fill.
By design
Section titled “By design”One machine, no web UI, no sync, no notifications. --json is day alone; every other report is text for a human to read.