Anyone who has kept a timesheet knows Friday afternoon. You look back at a week you definitely worked and try to remember which part was the migration and which was the bug that ate Tuesday. The hours were real. Nobody wrote down which task they belonged to, because that meant stopping work to press a button.
TimerOS has recorded hours automatically since launch. Until this month it could not say what they were for. Since v1.3, the desktop app matches those hours to your open tasks as you work, entirely on your own computer. Here is how it decides, and when it deliberately decides nothing.
Why guessing is the real risk
The obvious approach is to take whatever is on screen, find the closest-sounding task and book the time. It looks great in a demo and does real damage, because a timesheet that is 80% right is worse than one that is 60% filled. The wrong 20% looks exactly like the correct rows. So you either check every row, which takes longer than filling in the timesheet yourself, or you bill a client for work done on a different job.
A wrong booking is more expensive than a missing one, because you cannot see it.
So the matcher holds back. It needs solid evidence before it books anything, and when it does not have it, the time stays productive but unassigned. The app treats that as a normal result and does not nag you about it.
What it actually reads
In v1.3, just one thing: the title of the window you are looking at. It does not use the application name or the browser address. Those two only help decide whether you are productive or idle, and play no part in matching a task. The scoring code receives the address and deliberately ignores it.
The title is split into words and compared with the words in your own open tasks and subtasks. Words from a task’s title count in full; words from its description count at 40% and can only raise a score, never lower it. Rare words count for more than common ones, and about 130 generic words (fix, bug, update, task) are ignored completely. So “Fix login bug” and “Fix export bug” are told apart by the words that actually differ.
What a match has to pass
A candidate task has to clear all of these before anything is booked:
- Two matching words, or one unique word. A single shared generic word is never enough. One word is enough only if it appears in exactly one task in your whole list, which is why ticket numbers work.
- A score of at least 0.45. That is the share of the task’s title words found in the window title, with rare words weighted more heavily.
- A winning margin of 0.15 over the runner-up. When two similar tasks score closer together than that, the matcher books nothing instead of guessing between them.
- Sixty seconds of agreement. The same task has to keep winning repeated checks for a full minute before it gets its first booking. Alt-tabbing past something for fifteen seconds books nothing.
Two extra nudges
Word matching alone ignores what you already know about the work, so two other factors adjust the score. A task marked in progress gets a quarter more weight. Dates matter too: work inside a task’s scheduled dates gets a small boost, while a task that starts more than a week from now, or is more than two weeks overdue, drops to 60%. The date comes from the same trusted clock TimerOS uses for shifts, so changing your computer’s timezone does not affect it.
Sticking with a task, and letting go
The other half of the problem is stability. A matcher that changes its mind every five seconds chops the day into thousands of fragments, which is detailed but useless.
So a match sticks. Once a task is chosen, a different task has to outscore it for two full minutes before the booking switches. A quick look at another ticket does not break up the block you are in. If a match goes thirty minutes without being confirmed again, it is released, so a task you finished at eleven does not keep collecting your afternoon.
There is a second way in. If you have a task, incident or change request open inside TimerOS itself for twenty seconds, the time goes straight to it. No guessing is needed, because you are looking at the record. This is the only way incidents and change requests get time assigned at all.
What leaves your machine
All of this runs on your own computer, in the desktop app, which is written in Rust. The word list is built from your assigned work, and the scoring and matching happen there too.
What gets synced is a list of task IDs with a number of seconds each, in the same format as the rest of the day’s hours. Window titles are never sent: the app reads them locally and syncs only the result. The productive/idle classification works the same way, as explained in a separate post.
The matcher described here is not AI. There is no model, no server doing inference and nothing that needs a GPU. It is a fixed scoring formula: the same input always gives the same result, and it behaves the same whether your tracking mode is Automatic or Rule-based. That is why we can give you the exact thresholds in this post, and why you can predict what it will do.
How this differs from auto-tracking elsewhere
Recording activity in the background is not new: Toggl Track and Clockify both do it without a running timer. The difference is what you get at the end.
Neither approach is clearly better. Record-and-review never books anything wrong, because it never books anything; the work falls on you on Friday. Matching hands that work to the computer and accepts that it will sometimes be wrong. That is why being able to review and undo a booking matters more than the matcher itself.
What we deliberately did not do
- No project-level fallback. When the first version could not identify a task, it booked the time to the project. We removed that five hours later, in v1.3.1. “Some time, on roughly the right project” looks plausible, and that is exactly what makes a timesheet untrustworthy.
- No nagging. An Unassigned row shows time that matched nothing, and you can assign it in one click if you want. It does not turn red and it does not keep reminding you.
- No hidden overwriting. A task’s hours come only from tracked time. Since v1.15.0 you can no longer type a number over them.
- Invoicing came later, on purpose. A wrong booking becomes a wrong invoice, so matched hours stayed out of billing while the matcher was new. Since v1.15.0, time-and-materials invoices bill the tracked hours on each task, so review the matched time before you invoice.
We never aimed for a timesheet that fills itself in perfectly. We wanted to replace remembering with checking. You can check a list in two minutes on Friday, but you were never going to remember Tuesday.