Everything HPR does.

Every feature, every detail. No premium tiers. No feature gating. Everything is free and open source.

Real-Time Window Tracking

HPR watches which window is in focus every 50 milliseconds. It builds a running log of exactly where your time went — not where you think it went.

50ms Polling

Polls the active window every 50 milliseconds. Every switch detected, every transition logged. Uses std::chrono::steady_clock for monotonic, NTP-immune timing.

Live Time Accumulation

Total time per application updates in real time, displayed as 2h 14m 30s (25%). Percentage breakdown gives instant visibility into time distribution.

Switch History

Every transition between applications is timestamped and logged. Full chronological history shows from → to with exact times.

HPR Home — Live tracking view

Date Picker

Click the date picker and pull up any day you have ever run HPR. It loads that day's database asynchronously off a plain SQLite file sitting on your own disk.

Timing Integrity

Duration measurement uses std::chrono::steady_clock (monotonic). Display timestamps use system_clock. This separation is enforced — using system_clock for duration is a classic bug that corrupts totals when NTP fires or DST changes mid-session.

Window Normalization

Raw window titles from the OS are inconsistent and noisy. validateAndUpdateWindow_Cross runs a cross-platform normalization pass on every poll, filtering out system noise like plasmashell, searchhost, and KWin JS runtime artifacts.

Browser Tab Tracking without an extension

Chrome, Edge, Firefox, Brave — HPR tracks which tab is active by reading the window title the OS already exposes. No browser extension. No manifest. No permissions dialog. No marketplace install. It has always been there.

T

Tab View (Raw)

Shows unaliased, unprocessed tab titles exactly as the OS reports them. Differentiate between specific pages — time across two different YouTube videos, individual GitHub issues, separate docs.

S

Site View (Formatted)

Applies rules from tabAliases.csv to group tabs by website. All YouTube tabs collapse into "YouTube". All GitHub pages collapse into "GitHub". Toggle between the two views inside the app with a single click.

Tab View vs Site View

Mode Shows Use when
Tab View Raw title string from OS You want granular per-page breakdown
Site View Aliased name from tabAliases.csv You want time grouped by website
No Extension Needed

Every supported browser puts the active tab name in its window title. HPR reads that string on every 50ms poll. The data has always been there — no browser API, no content script, no manifest.json, no user permission required.

Chrome Edge Firefox Brave No Extension Tab View Site View tabAliases.csv

VS Code Project Tracking without an extension

HPR tracks which VS Code project you are in, not just that VS Code is open. No VS Code extension. No plugin. No marketplace install. HPR reads the window title the OS already exposes.

How it works

VS Code puts the active project name in its window title as filename - project - Visual Studio Code. HPR reads that title on every poll tick and parses it:

# VS Code title format:
filename - project - Visual Studio Code

# HPR strips trailing suffix, then
# splits on last " - " separator
# (spaces around dash, safe split point)
result = project_name

Project View — Raw & Formatted

A dedicated Project View tab shows time broken down by project. Toggle between two modes inside the app:

Mode Shows
Raw View Unprocessed full window title substring as received from the OS
Formatted View Categorizes projects via projectAliases.csv (e.g., mapping rust-app-v2 to Client Bob)

Works on Every Platform

Hyprland, GNOME, KDE Plasma 6+, Cinnamon, and Windows. Every backend already has a window title getter and VS Code puts the project name in the title on all of them. No platform-specific setup.

No Extension Needed

Zero VS Code plugins. Zero marketplace installs. Zero configuration inside VS Code. HPR reads the single string the OS already exposes as the window title. The project name has been there the whole time.

VS Code No Extension Raw View Formatted View projectAliases.csv All Platforms

Pattern Analysis Engine

PatternAnalyzer runs seven analysis passes every 30 seconds, building insights from your raw tracking data.

Most Used Application

Direct aggregation over timeLog_PerApp. Shows your dominant application with exact time.

Total Tracked Time

Sum of all application usage for the day. Your actual screen time, not an estimate.

Total App Switches

Count of every transition between applications. A signal of how fragmented your day was.

Most Switched From / To

Top switch pairs from switchHistory. Reveals your most common context-switch patterns.

Longest Focus Session

Chronological Event-Matching Algorithm. Flattens switch history into a unified timeline of arrivals/departures, sorted in O(N log N). One pass pairs each arrival with its next departure. Orphaned arrivals from crashes are overwritten, not ghost-extended.

Peak Productive Hour

Sliding Window Heuristic. A 60–90 minute window slides across the complete timeline, counting switches at each position. The position with fewest switches = deepest focus. No manual session marking required.

HPR Insights view showing pattern analysis results

Insights — All seven analysis passes

Noise Filtering

Both patterns filter out HPR itself, the Unknown state, and known system noise before running. Insights reflect actual work, not measurement artifacts.

Alias System

Raw window titles are inconsistent. Visual Studio Code on one machine, code on another, code.exe on Windows. Aliases collapse all of them into one label.

Application Aliases

aliases.csv — maps raw window names to display names. code catches vscode, code-oss, code.exe. terminal catches kitty, alacritty, konsole, wezterm.

Tab Aliases

tabAliases.csv — collapses specific URLs and page titles into website names. All YouTube tabs become "YouTube". All GitHub pages become "GitHub".

VS

Project Aliases

projectAliases.csv — categorizes your VS Code projects (e.g., mapping rust-app-v2 to Client Bob). The default template is located in ~/.config/HPR/.

Hot Reload

Save the alias file, HPR picks it up within the next UI tick. No restart required. Cached via unordered_map — O(1) lookups after first resolution.

aliases.csv
# raw substring,Display Name
code,Visual Studio Code
kitty,Terminal
alacritty,Terminal
konsole,Terminal
wezterm,Terminal
firefox,Firefox
chromium,Chrome
Late-Binding Design

The database stores raw OS strings exactly as received. Aliases are resolved at display time only. Renaming an alias retroactively updates every historical entry for that application with zero migration work.

Format
# One line per alias
raw substring,Display Name

# Lines starting with # are comments
# Matching is substring-based
# First match wins

Plain SQLite. One file per day.

Your data is a folder on your disk. Removing it means deleting that folder. No server. No account. No support ticket.

Data Directory
~/.local/share/HPR/HPR_DB/          (Linux)
%APPDATA%\HPR\HPR_DB\               (Windows)

    05-26/
        01-05-26.db
        02-05-26.db
        ...

A normal day: 30 to 100 KB
A full year: under 50 MB
30–100 KB
Per Day
<50 MB
Per Year

Write Strategy

app_usageINSERT OR REPLACE on unique app name. One row per app, always current.

switch_historyINSERT OR IGNORE on unique timestamp. Dumps full history every flush, SQLite drops duplicates.

WAL mode with passive checkpoint after every write. Added after real WAL corruption on Btrfs + LUKS during development.

Single-Instance Lock

Windows: CreateFileA with FILE_FLAG_DELETE_ON_CLOSE. Auto-deletes on crash.

Linux: flock(LOCK_EX | LOCK_NB). Kernel releases on process death.

Seamless Midnight Rotation

At exactly midnight, HPR automatically commits a final WAL checkpoint, clears all tracked data from RAM, and creates a fresh DD-MM-YY.db for the new day — with no restart required. You never lose data between days and never need to think about it.

Interpreted UI Mode

This is not a theme engine. This is not CSS variables. HPR loads the entire UI definition from disk at runtime using Slint's interpreter. You have full access to the Slint language — layouts, animations, components, property bindings.

Compiled vs. Interpreted

Aspect Compiled Interpreted
Class HPR HPRInterpreter
Mechanism Slint generates C++ at build time Slint loads .slint from config dir at runtime
Performance Maximum Negligible difference
Customizable No Full UI control
⚠ Contract

Structs, properties, and callbacks are referenced by name from C++. Renaming them breaks the connection silently. Read READ_ME_BEFORE_MODIFYING_UI.txt before editing.

What you can change

Colors and color schemes
Component layouts and positioning
Animations and transitions
Component structure
Typography and fonts
Add new visual components
Rename structs/properties/callbacks
config.csv
// Enable runtime UI loading
use-interpreter,true

// Your UI files
~/.config/HPR/ui/app-window.slint

// Reference copy for diffing
~/.config/HPR/ui-REFERENCEONLY/

The numbers.

Cachegrind, Callgrind, and real-world measurements. HPR's own code doesn't appear in the hot path.

~8 MB
RAM (Windows)
~22 MB
Private (Linux)
1–3%
CPU Usage
~2 MB
Binary Size

Linux Memory Explained

BTOP/htop report ~47 MB. The actual private memory (heap + stack + data) is ~22 MB. The remaining ~25 MB is shared GPU library pages from Mesa/LLVM loaded by Slint's OpenGL renderer. These pages are shared with every GPU-accelerated process on your system.

# Verify yourself:
cat /proc/$(pgrep HPR)/status | \
  grep -E "RssAnon|RssFile|VmRSS"

Disable GPU Overhead

Set hardware-acceleration,false in config.csv. Mesa never loads. libLLVM never loads. RSS drops to ~22 MB. UI is visually identical — CPU renderer only costs slightly more during redraws at 500ms intervals.

Cachegrind (15s sample)

L1 instruction miss rate:      0.20%
Last-level instruction miss:   0.01%
L1 data miss rate:             2.6%
Last-level data miss rate:     0.2%
Overall last-level miss rate:  ~0.0%

2.6% L1 data miss is entirely
Slint's font rendering pipeline.

Callgrind (60s sample)

4.46 billion instructions over 60 seconds. HPR's own C++ backend did not appear in the top 15 hottest functions. Everything was Slint, FreeType, fontconfig, or parley doing text work.

Zero network. Zero accounts.

Your data is a folder on your disk. Deleting it means deleting that folder. No server to request deletion from.

No Accounts

No signup. No login. No email. No password. Launch the binary and it works.

No Telemetry

No analytics. No crash reports. No usage metrics. No phone-home of any kind.

No Network

HPR at runtime touches no network, no DNS, nothing. The only external call in the entire codebase is a git clone in the GNOME extension install script — a shell command you run once, manually.

Lives in your tray. Stays out of your way.

HPR keeps running when you close the window. The only way to actually quit it is through the tray icon.

Windows

Action Result
Left click Does nothing
Right click Context menu → Show HPR / Quit
Close window Hides to tray (does not quit)

Linux (Waybar · KDE 6+ · Cinnamon)

Registered as org.kde.StatusNotifierItem on the session D-Bus. Same protocol used by Discord, Steam, and every modern app.

Action Result
Left / Right click Open HPR
Middle click Quit HPR
Hover Shows tooltip with hint text
Close window Hides to tray (does not quit)
No Libraries

Pure D-Bus over libdbus-1. No GTK. No Qt. Works with Waybar on Hyprland, KDE Plasma 6+'s system tray, and Cinnamon's panel out of the box with zero configuration.

Two options. That's the full config.

Intentionally small. It will grow alongside the feature set.

config.csv
# true = load UI from config dir at runtime
use-interpreter,false

# false = CPU renderer, eliminates GPU libs
hardware-acceleration,true
Config Locations
Linux:
~/.config/HPR/config.csv

Windows:
%APPDATA%\HPR\HPR_Config\config.csv

Event System & Thread Management

The UI and database layers have no direct references. They communicate through EventHub, a centralized in-process pub/sub bus with typed payloads.

EventHub API
// Subscribe
EventHub::connect(
  Event::HISTORY_LOADED_SINGULAR,
  [this](EventData data) { ... }
);

// Publish
EventHub::emit(
  Event::LOAD_DATABASE_SINGULAR,
  DatabaseDate_Singular{requestedDate}
);

// Cleanup
EventHub::disconnect(
  Event::HISTORY_LOADED_SINGULAR, id
);

Thread Lifecycle Contract

Constructor → allocate, do NOT start
run()       → spawn the thread
thread body → check atomic<bool> running
destructor  → set running=false, join()

Model Sync

Surgical in-place update rather than clear + repopulate. Clearing causes layout panics during resize/maximize. The syncModel lambda overlaps existing rows, erases excess, and appends new ones.

Roadmap

The foundational work is mostly done. What comes next is refinement, not new pillars.

AI

LLM-Powered Analysis

Pattern analysis powered by local LLM inference. All processing stays on-device.

Focus Mode

Application blocking during focus sessions. Enforced deep work periods with configurable block lists.

📊

Advanced Reporting

Extended analytics, historical trend visualization, and exportable reports.

All Free, Forever

The premium version has been merged into the free version. Every feature — current and future, including LLM analysis, Focus mode, and Advanced reporting — is available to everyone at no cost.

Ready to know where your time goes?

Three commands on Linux. One installer on Windows. Running in seconds.