Build RescueTime

YESreplaces $12/mosaves $144/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort weekendthe files for this build are in the project pack

LanguageSwift for macOS, or an equivalent native agent per platformSamplingA timer reading the frontmost application and window titleStorageSQLite locally, never a serverClassificationRules you write, evaluated in order, with a visible fallbackIdle detectionSystem idle time, so away time is not counted

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 99 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.

VariableNeededExampleWhere the value comes from
DB_PATHrequired~/Library/Application Support/Time/time.dbThe local database. This is a detailed record of your computer use, so treat the file accordingly.
SAMPLE_INTERVAL_SECONDSrequired15How often focus is sampled. Shorter is more accurate and produces more rows.
IDLE_THRESHOLD_SECONDSrequired180How long without input before time stops being attributed.
STORE_PLAIN_TITLESrequiredfalseWhether window titles are stored readable. False by default; the allowlist is the exception.
PLAIN_TITLE_ALLOWLISToptionalcom.apple.dt.XcodeApplications whose titles may be stored readable, chosen deliberately.
SAMPLE_RETENTION_DAYSrequired90How long raw samples are kept. Aggregated intervals survive beyond this.

The build, in order

  1. Sampling, with a pause you can always reach

    The agent records which application has focus, and stopping it takes one action.

    1. On an interval through the workspace API. No permission is needed for the application name alone.

      Files Sampler.swift

    2. A menu bar item showing recording, with pause and resume one click away.

      Files MenuBar.swift

    3. A 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 passes
    watch 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.
  2. Idle time and window titles, carefully

    Time away is not counted, and titles do not become a log of everything you read.

    1. System idle time with a threshold you set. Verify against the clock rather than trusting the API.

      Files Idle.swift

    2. Hashing gives you change detection without storing content. A plain-title allowlist is opt-in per application.

      Files Titles.swift

    3. Application names still work. Say what titles would have added rather than disabling everything.

      Files Permissions.swift

    done when · tick each as it passes
    watch 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.
  3. Rules you wrote

    Time is grouped into categories you defined, and you can see why each interval landed where it did.

    1. First match wins, with the matching rule recorded on the interval.

      Files Rules.swift

    2. Its own category. Hiding it makes the totals look complete when they are not.

      Files Categories.swift

    3. With a count of affected intervals shown before it runs.

      Files Reclassify.swift

    done when · tick each as it passes
    watch 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.
  4. Reports without a verdict

    You can see where the time went, and the application does not tell you how to feel about it.

    1. By category and by application, with gaps and pauses visible.

      Files Reports.swift

    2. Banned words including productive, unproductive, wasted, distracted, score, grade and streak. Fails the build.

      Files scripts/copy-lint.swiftscripts/banned-words.json

    3. In every total. Excluding it flatters the numbers and hides the rules you have not written.

      Files Reports.swift

    done when · tick each as it passes
    watch 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.
  5. Focus sessions

    You can start a session with an intent and see afterwards what actually happened.

    1. Typed, in the user's words. It is what makes the summary meaningful afterwards.

      Files Sessions.swift

    2. Dismissible, and never repeated more than a configured rate. Blocking is worked around and loses the data.

      Files Sessions.swift

    3. Where the time went against the intent. The user draws the conclusion.

      Files SessionSummary.swift

    done when · tick each as it passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more time tracking.