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

Historical Data — Three Modes

Click the calendar icon in the sidebar to open the History Range view. Choose from three loading modes:

1 Single Day — pick any date from the calendar picker. Loads that day's .db file asynchronously.
7 Last N Days — pull last 7, 14, 30 days or any custom count. Multiple daily files are merged automatically using a fast, parallel N-thread approach (no 30s timeouts like ActivityWatch).
Date Range — set a start and end date. HPR reads every daily file in that span concurrently using multiple threads and aggregates the result.
Non-Blocking & Parallel (N-Thread) Load

Historical loading runs on dedicated background threads. Live tracking is never paused, and queries run in parallel. This is incredibly fast and avoids the 30-second timeouts common in single-threaded tracking systems like ActivityWatch.

HPR History Range View

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, Zen Browser — 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.

Browser Support Matrix

Browser Platform Support Status Extension Required Parsing Strategy / Notes
Google Chrome Windows / Linux ✅ Working No Matches chrome in window title/process name
Microsoft Edge Windows / Linux ✅ Working No Matches edge in window title/process name
Mozilla Firefox Windows / Linux ✅ Working No Matches firefox in window title/process name
Brave Windows / Linux ✅ Working No Matches brave in window title/process name
Zen Browser Windows / Linux ✅ Working No Matches zen in window title/process name
Chrome Edge Firefox Brave Zen Browser No Extension Tab View Site View tabAliases.csv

Code Editor & IDE Project Tracking without extensions

HPR tracks which project you are currently working in, not just whether the editor is open. No editor extensions, plugins, or marketplace installs are required.

How it works — VS Code

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
result = project_name

How it works — JetBrains IDEs (Beta)

JetBrains IDE window titles are tracked by HPR with a jetbrains: prefix (resolving to jetbrains: ProjectName – file [module] or jetbrains: ProjectName). HPR parses the project name using the en dash :

# JetBrains title format:
jetbrains: ProjectName – file [module]

# HPR strips prefix "jetbrains: ", then
# takes everything before the first en dash " – "
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 the supported editors put the project name in the title on all of them. No platform-specific setup.

No Extension Needed

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

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

IDE & Code Editor Support Matrix

Application Platform Support Status Extension Required Parsing Strategy / Notes
Visual Studio Code Windows / Linux ✅ Working No Matches code, vscode, or visual studio code in window title/process name
IntelliJ IDEA Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
WebStorm Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
PyCharm Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
CLion Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
Rider Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
GoLand Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
RustRover Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
PhpStorm Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
RubyMine Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
DataGrip Windows / Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).
DataSpell Linux ✅ Working No Matches jetbrains in window title/process name; extracts project name before the en dash (–).

Day Construction Timeline

Reconstruct your daily narrative. HPR maps your active window transitions chronologically onto an interactive, zoomable, and scrollable timeline canvas, giving you visual continuity instead of just isolated numbers.

Zoom & Scroll Presets

Focus on microscopic details or analyze the entire day. Supports interactive presets to instantly zoom into 1h, 3h, or 8h intervals, or zoom out to 24h and All Day spans. The timeline canvas scrollbar lets you slide across the day seamlessly.

Adaptive Hourly Markers

Timeline markers calculate coordinates and adjust automatically. Zoomed viewports (1h, 3h, 8h) draw markers at every 1-hour interval, while high-span viewports (24h, All Day) space markers every 3 hours (e.g., 06:00 AM, 09:00 AM) to prevent overlapping labels and maintain design aesthetics.

Continuity Gap Capping

Prevents downtime from polluting your logs. If you close HPR or turn off your computer for 5 hours, a naive timeline would stretch the last active application across the entire downtime. HPR's reconstruction algorithm identifies these focus gaps (transitions to Unknown or shutdown states) and caps the preceding app segment to a maximum of 1 minute.

Interactive Hover Tooltips

No clicks required. Simply hover your cursor over any timeline block to view its properties instantly. The status panel updates dynamically in real-time, displaying the application's aliased name, exact active duration, and precise start/end time range.

HPR Tracking

The tracking engine includes HPR itself inside the timeline, giving you visibility into the time you spend managing goals, reviewing insights, or developing extensions.

HPR Day Construction Timeline

Day Construction Timeline — Zoomable & Scrollable

Fractional Calculations

Timelines are calculated using high-precision fractional positions, ensuring that short 1-second switches are scaled and rendered accurately alongside hours-long focus sessions.

Pattern Analysis Engine

PatternAnalyzer runs seven analysis passes every 30 seconds for real-time daily metrics, and triggers a multi-day correlation pass to extract 9 advanced trend insights.

Real-Time Daily Metrics

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, discarding orphan events.

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.

Advanced Cross-Day Patterns

Escape Pattern

Tracks switches from your primary work application directly to browsers, showing the average daily count of browser escapes.

Return Rate

Measures focus bounce-back by calculating the percentage of times you return to your work application immediately after a browser distraction.

Average Focus Session

Computes the average duration of uninterrupted work sessions before switching windows across the multi-day span.

Most Distracted Day

Pinpoints the day of the week with the highest average number of application switches, isolating weekly distraction patterns.

Productive Days

Counts the days during the current week where your hourly switch frequency remained below the productivity threshold.

Screen Time vs Average

Compares today's cumulative screen time with your N-day average to check if you are overworking or taking it easy.

Focus Dip Hour

Pinpoints the specific hour of the day where application switches spike most consistently across days, identifying energy crashes.

Deep Work Before Noon

Measures the percentage of days where your longest focus sessions start in the morning (before 12:00 PM local time).

Weekend vs Weekday

Compares average work-app usage on weekdays versus weekends to show how well you separate work from rest.

HPR Insights view showing pattern analysis results

Insights — All seven analysis passes

Database Integration & Parallel Queries

When the user enters the Insights view, HPR asynchronously queries the SQLite database using an N-thread concurrent read approach. This avoids dashboard UI freezes while loading many days of historical records.

Noise Filtering

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

Per-App Limits & Goals

Set a daily time limit or a daily usage goal on any tracked application — directly from the built-in Goals view. HPR monitors usage in the background and fires a system notification the moment you cross a threshold.

Limits

Cap an app to a maximum number of minutes per day. When usage crosses that threshold HPR sends a system notification — and can optionally force-quit the application automatically. The badge on each row shows exactly how many minutes remain, updated live.

Goals

Set a minimum number of minutes you want to spend in an app each day — for example, 30 minutes in your code editor. HPR tracks your progress and notifies you when you hit the goal.

How to configure

1

Open the Goals view

Click the Goals icon in the sidebar. Every tracked application appears in the list automatically.

2

Click any app row

The row expands inline, revealing a minute input with +/− step buttons and three actions: SET LIMIT, SET GOAL, or RESET.

3

HPR handles the rest

A dedicated background thread monitors usage continuously. Limits show a red accent badge; goals show green. Both display remaining time live.

HPR App Limits and Goals
Zero restart required

Limits and goals take effect immediately. No restart. No config file editing. Changes are reflected in the UI the moment you set them.

Override API hook

Advanced users can intercept the limit-reached event via the Lua Extension Override API to run custom logic — log it, send it to a webhook, trigger a different notification, or suppress it entirely.

App Limits Daily Goals System Notifications Background Monitor Per-App Live Remaining Time

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.

Ghost Sidebar + Reload UI button

The navigation sidebar collapses to a thin 14px sliver at the screen edge — hover to reveal icon buttons for every view. One of those buttons is Reload UI: hit it while in interpreted mode and your modified .slint file is re-parsed and the interface re-renders in under a second, without restarting HPR.

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
💡 UI/C++ Contract is Optional

Structs, properties, and callbacks are referenced by name from C++. Note that satisfying this contract is optional; if you omit any properties or callbacks, the application will still load and run, but you will not receive data or trigger those callbacks. Renaming them breaks the connection silently for those specific fields. 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/

Sandboxed Lua Extension Engine

Build dynamic custom behaviors, widgets, integrations, and automation directly using a highly secure, concurrency-safe Lua 5.4 scripting sandbox. No binary compilation required. Zero chance of destabilizing the core. The extension API is intentionally beginner-friendly — write a simple Lua function, drop the file into ~/.config/HPR/extensions/, and HPR picks it up instantly. No setup wizards, no package managers, no build steps. If you've ever written a script, you can build an extension.

The Extension Architecture

HPR embeds a sandboxed sol2-bound Lua VM inside its extension manager. Scripts run with safe limits, isolated variables, and restricted OS API wrappers, allowing robust third-party expansion without compromising core tracking thread execution.

Interactive UI Callbacks

Register UI callbacks using registerUiCallback_E. Slint callback arguments (Strings, Doubles, Booleans, Arrays, and Structs) are recursively mapped and forwarded directly to Lua VM event listeners as parameters (with a void return in C++).

C++ RAII Auto-Disconnection

Forget manual cleanup. All EventHub event subscriptions are bound to C++ connection tracking handles. When an extension is unloaded or reloaded, subscriptions are cleanly disconnected automatically.

Embedded SQLite Access

Execute fast, safe database queries directly from your extension. Interrogate tracking history, fetch active categories, and calculate stats inside your scripts.

EventHub Messaging

Subscribe to application events, lock states, time changes, and idle periods in real-time. Publish custom signals to drive modular widgets.

HTTP Networking

Make HTTP GET/POST requests directly from Lua to integrate with REST APIs, webhooks, and external services — all while the core remains offline by default.

Function Overriding API

For advanced users: intercept and override 28 core C++ engine functions directly from Lua. Rename windows before they're stored, mock database queries, block notifications, spoof timestamps, hijack HTTP requests, control tracking state, and more. Full override docs →

Native Shared Libraries (.dll/.so)

Supercharge extensions by loading external dynamic libraries. Execute raw machine code, call low-level OS APIs, create custom system tray icons, or run heavy multithreaded jobs. Securely controlled via a settings toggle.

Recursive Subdirectory Scan

RESCAN walks the extensions folder recursively. Organize your scripts into subdirectories freely — HPR finds them all. Use HPR.getExtensionDir_E() to get the relative path to your extension's own subfolder for safe file I/O.

🛡️

Per-Extension Isolation

Each loaded extension runs in its own dedicated background thread. If one extension crashes or throws, all others keep running and the core C++ tracker is completely unaffected.

HPR Extensions view showing extension logs and runtime details

The numbers.

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

~13 MB
RAM (Windows)
~26 MB
Private (Linux)
1–3%
CPU Usage
~4-5 MB
Binary Size

Linux Memory Explained

BTOP/htop report ~47 MB. The actual private memory (heap + stack + data) is ~26 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 ~26 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 by default. 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 (Opt-in)

No analytics, crash reports, or phone-home of any kind by default. If explicitly opted-in, HPR reports only two anonymous numbers: unique installation count and weekly active frequency.

No Network by Default

HPR's Core runs offline. The binary has network code to power the optional anonymous telemetry, the developer's YouTube Now Playing status stream, and Lua extensions. In details, the developer's client uploads what the developer is currently watching on YouTube to a Firebase Realtime Database, and normal users' clients read from this database to display that status in the About view (which can be disabled via the Allow Network Activity toggle in the Settings panel).

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.

Simple 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

# false = disable automatic application termination on limit breach
kill-apps,true

# minimum time interval (ms) between app terminations
kill-cooldown,2500

# window focus check frequency (ms)
poll-interval,50

# how often window tracking totals are saved to disk (ms)
db-flush-interval,10000

# wait time (ms) for Lua extensions to finish onExit before force exit
extension-shutdown-timeout,300

# wait time (ms) for Lua extensions to finish on reload/unload before detaching
extension-reload-timeout,450

# tracking loop polling and UI update frequency (ms)
ui-update-interval,200

# interval to run the pattern analyzer and update insights on the UI (ms)
ui-insight-interval,1000

# duration for which active errors are displayed on the UI (ms)
ui-error-duration,5000

# false = disable all outgoing network HTTP activity
allow-network-activity,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.

Ready to know where your time goes?

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