Build RescueTime
YESreplaces $12/mosaves $144/yrback to the verdict
A background agent sampling which application and window has focus, storing that locally, classifying it with rules you write and can edit, showing where the time went without scoring it, supporting focus sessions with a pause you can always reach, and exporting everything.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree if you own one
Why Reading the frontmost application is a platform API. The design carries across platforms; the implementation does not.
Get it Apple menu, then About This Mac, if you are targeting macOS.
Verify
About This Mac reports macOS 14 or higher - installfree
Why Builds the agent and provides the profiler for the sampling loop.
Get it Mac App Store or developer.apple.com/xcode. open ↗
Verify
xcodebuild -version prints 16 or higher - decidefree
Why Application names need no permission. Titles need Accessibility and are considerably more revealing, so this is a deliberate choice rather than a default.
Get it Decide before Phase 2 whether you want titles at all. If yes, the hashing default and the per-application allowlist are what make it defensible.
Verify
The decision is recorded in the README - have readyfree, but it takes a week
Why Rules cannot be written in the abstract. You need to see what applications actually appear before you can categorise them usefully.
Get it Run Phases 1 and 2 for a week before writing rules in Phase 3. The uncategorised list is your rule backlog.
Verify
A week of samples exists across normal working days - account99 USD per year
Why Product phase only, and only if you distribute it.
Get it Enrol at developer.apple.com/programs. open ↗
Verify
A Developer ID Application certificate appears in Xcode settings
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- samples(at, bundle_id, app_name, window_title_hash, idle_seconds) · the raw record, sampled on an interval - intervals(id, bundle_id, started_at, ended_at, category_id, title_sample) · samples collapsed into runs, which is what you actually look at - rules(id, priority, match_kind, pattern, category_id, enabled) · match on bundle identifier or title pattern - categories(id, name, color) · named by you, with no built-in productive or unproductive distinction - sessions(id, started_at, ended_at, intent, completed) · focus sessions, with the intent you typed - pauses(started_at, ended_at, reason) · recorded, because a tracker that hides its gaps is lying by omission - Window titles are hashed by default rather than stored, because a title often contains a document name, a customer name or a search query.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DB_PATH | required | ~/Library/Application Support/Time/time.db | The local database. This is a detailed record of your computer use, so treat the file accordingly. |
SAMPLE_INTERVAL_SECONDS | required | 15 | How often focus is sampled. Shorter is more accurate and produces more rows. |
IDLE_THRESHOLD_SECONDS | required | 180 | How long without input before time stops being attributed. |
STORE_PLAIN_TITLES | required | false | Whether window titles are stored readable. False by default; the allowlist is the exception. |
PLAIN_TITLE_ALLOWLIST | optional | com.apple.dt.Xcode | Applications whose titles may be stored readable, chosen deliberately. |
SAMPLE_RETENTION_DAYS | required | 90 | How long raw samples are kept. Aggregated intervals survive beyond this. |
The build, in order
Sampling, with a pause you can always reach
The agent records which application has focus, and stopping it takes one action.
On an interval through the workspace API. No permission is needed for the application name alone.
Files
Sampler.swiftA menu bar item showing recording, with pause and resume one click away.
Files
MenuBar.swiftA gap with a reason is honest; an unexplained gap is a bug you will chase later.
Files
Store.swift
done when · tick each as it passeswatch out- A tracker without an obvious, immediate pause becomes something people work around by quitting it, which loses the data anyway and teaches them not to trust it. Make pause one click from the menu bar and make the recording state always visible.
Idle time and window titles, carefully
Time away is not counted, and titles do not become a log of everything you read.
System idle time with a threshold you set. Verify against the clock rather than trusting the API.
Files
Idle.swiftHashing gives you change detection without storing content. A plain-title allowlist is opt-in per application.
Files
Titles.swiftApplication names still work. Say what titles would have added rather than disabling everything.
Files
Permissions.swift
done when · tick each as it passeswatch out- Window titles are far more sensitive than application names: a browser title is the page you are reading, a document title is the client you are working for, and an editor title is the file. Hash by default, store plain text only where the user opted in per application, and say so where the setting lives.
Rules you wrote
Time is grouped into categories you defined, and you can see why each interval landed where it did.
First match wins, with the matching rule recorded on the interval.
Files
Rules.swiftIts own category. Hiding it makes the totals look complete when they are not.
Files
Categories.swiftWith a count of affected intervals shown before it runs.
Files
Reclassify.swift
done when · tick each as it passeswatch out- Silently reclassifying history whenever a rule changes rewrites last month's numbers and makes any comparison over time meaningless. Apply new rules going forward, and make retroactive reclassification an explicit action that says how many intervals it will change.
Reports without a verdict
You can see where the time went, and the application does not tell you how to feel about it.
By category and by application, with gaps and pauses visible.
Files
Reports.swiftBanned words including productive, unproductive, wasted, distracted, score, grade and streak. Fails the build.
Files
scripts/copy-lint.swiftscripts/banned-words.jsonIn every total. Excluding it flatters the numbers and hides the rules you have not written.
Files
Reports.swift
done when · tick each as it passeswatch out- A single productivity score is the feature people remember and the one that is most often wrong, because reading documentation in a browser and reading social media in a browser are the same application. If a category feels wrong, the fix is a rule, not a score that overrides your own knowledge of your work.
Focus sessions
You can start a session with an intent and see afterwards what actually happened.
Typed, in the user's words. It is what makes the summary meaningful afterwards.
Files
Sessions.swiftDismissible, and never repeated more than a configured rate. Blocking is worked around and loses the data.
Files
Sessions.swiftWhere the time went against the intent. The user draws the conclusion.
Files
SessionSummary.swift
done when · tick each as it passeswatch out- Blocking applications during a focus session turns a measurement tool into an enforcement tool, and enforcement is worked around within a week. A reminder that can be dismissed respects that you sometimes genuinely need the other application, and it keeps the data honest.
Export, retention and deletionproduct builder
The record is yours, it does not accumulate forever, and you can delete any part of it.
JSON for everything, CSV for spreadsheets. The record is yours and should be portable.
Files
Export.swiftSamples are large and detailed; intervals are what you look at. Drop the first, keep the second.
Files
Retention.swiftOne function covering every table. Verify by querying for the deleted application after.
Files
Delete.swift
done when · tick each as it passeswatch out- A tracker's database is a minute-by-minute record of everything you did on your computer, and deleting an interval without the underlying samples leaves the detail recoverable. Make deletion cover every table and verify by querying for the deleted application afterwards.
That is the whole plan for RescueTime. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Cross-device history covering phones and other computers.
- Website blocking and enforcement, deliberately omitted.
- The long-term behavioural dataset and cross-user comparisons.
- Team timesheets and reporting to anyone else.
- cross-device history, website blocking, goals, reports, and long-term behavioral dataset
- cross-device history
- team timesheets and payroll
- behavioral datasets
- blocking across every platform
- A weekly review that asks what you want to change rather than telling you
- Per-project categories driven by the folder a project lives in
- An annotation for a block of time, so a meeting is labelled rather than guessed at
Need the files? The project pack on the verdict page hands your agent the whole brief · more time tracking.