← Back to Docs
⚠️ Heads Up — Advanced Territory

This API is for developers with some C++ and Lua knowledge who want to push HPR beyond its defaults. You'll be reaching directly into the engine's guts — overriding how windows are named, how databases are queried, how notifications fire, and more. It's powerful stuff, and it's totally fine if you're still learning. Just know that overrides bypass normal safety checks, so double-check your return types and test things out before shipping.

💡 Naming Convention Tip: Functions exposed to Lua via the standard API use an _E suffix (e.g., getCurrentWindow_E). Most override hooks target native C++ functions and do not have the _E suffix (e.g., showNotification, getAlias). However, some overrides targeting C++ extension helpers do keep their _E suffix (e.g., getCurrentWindow_E, getLiveTimeLogPerApp_E). Always double-check the exact key name.

Function Overriding API

The Function Overriding API lets your Lua extensions intercept and completely hijack core C++ functions inside the HPR engine. Define functions inside the HPR.overrides table in your init(), and the engine will call your code instead of (or before) the built-in C++ implementation. You control what goes in and what comes out.

How It Works

When an overridable C++ routine runs, it checks if any loaded extension has a matching key in the HPR.overrides table. If found, C++ serializes its parameters into a bridge type (CppValue), hands them off to your Lua function, and uses whatever you return to short-circuit the native path.

Return nil from your override to let C++ continue normally (pass-through). Return any value to replace the C++ result entirely.

Boilerplate Template

Every override extension starts the same way. Register your overrides inside init():

HPR.authorName = "YourName"
HPR.extensionName = "MyOverrides"

function init()
    HPR.overrides = {}
    
    -- Register your overrides here...
    HPR.overrides.someFunction = function(arg1, arg2)
        -- Your logic
        return nil  -- nil = let C++ handle it
    end

    return 1000
end
🪟

Window & Title

4 functions
validateAndUpdateWindow_Cross(windowName)
C++ → src/window/validateAndUpdateWindow.cpp

This is the gatekeeper of window titles. Every single window title passes through this function before it gets processed, stored in the database, or shown in the UI. HPR normally strips junk like "explorer.exe", "shellhost", etc. — but with this override, you decide what gets through and what gets renamed. Want to rename "code" to "VS Code"? Want to silently drop tracking for certain apps? This is your hook.

Params: windowName (string) — the raw window/app name Returns: string (modified title) or nil (pass-through)
Example — Rename apps & block tracking for specific windows
HPR.overrides.validateAndUpdateWindow_Cross = function(windowName)
    -- Rename "code" to something nicer
    if windowName == "code" then
        return "VS Code"
    end

    -- Block tracking for private browsing
    if windowName:find("Incognito") then
        return ""  -- empty string = HPR ignores it
    end

    return nil  -- everything else: let C++ handle it normally
end
showNotification(title, message)
C++ → src/window/windowUtilities.cpp

HPR sends desktop notifications through DBus (Linux) or WinToast (Windows) for events like tracking milestones, errors, etc. This override lets you intercept, modify, or completely suppress those notifications. Annoyed by a specific notification? Kill it. Want to log them instead of showing popups? Easy. Return any truthy value to block the native notification from firing.

Params: title (string), message (string) Returns: any truthy value to suppress, or nil to allow
Example — Suppress noisy notifications, log the rest
HPR.overrides.showNotification = function(title, msg)
    -- Silence all milestone notifications
    if title:find("Milestone") then
        print("[Suppressed] " .. title .. ": " .. msg)
        return true  -- blocks the desktop popup
    end

    -- Let all other notifications through
    return nil
end
getCurrentWindow_E()
C++ → src/extension/window_E.cpp

Returns the name of the currently active window/application. Other extensions call HPR.getCurrentWindow_E() to figure out what app the user is in right now. Note: HPR's core engine does not rely on this function for its own tracking and data storage. Overriding this will not affect core HPR database logs or UI tracking, but it will ensure that your overridden value is provided to any other extensions querying the active window.

Params: none Returns: string (spoofed app name) or nil (real value)
Example — Spoof active app for other extensions
HPR.overrides.getCurrentWindow_E = function()
    if focusModeActive == true then
        return "Deep Work Mode"  -- other extensions will see this
    end
    return nil  -- off-hours: report real app
end
getCurrentTitle_E()
C++ → src/extension/window_E.cpp

Returns the title/tab of the active window. Other extensions call HPR.getCurrentTitle_E() to retrieve the focused window's title. Note: HPR's core engine does not rely on this function for its own tracking and data storage. Overriding this will not affect core HPR database logs or UI tracking, but it will ensure that your overridden value is provided to any other extensions querying the active title.

Params: none Returns: string (spoofed title) or nil (real value)
Example — Redact sensitive titles for other extensions
HPR.overrides.getCurrentTitle_E = function()
    return "[Redacted]"  -- other extensions see this, but core HPR logs the real title
end
🏷️

Alias Resolution

6 functions
getAlias(rawName)
C++ → src/miscellaneous/aliasManager.cpp

HPR uses an alias system to turn ugly process names like "firefox-esr" into pretty display names like "Firefox". This function is called every time HPR needs the display name for an application. Override it to create dynamic aliases — aliases that change based on time of day, or aliases that pull from an external config. Way more flexible than the static alias file.

Params: rawName (string) — the raw process/app name Returns: string (custom alias) or nil (use built-in alias file)
Example — Dynamic app aliases
HPR.overrides.getAlias = function(rawName)
    local aliases = {
        ["firefox-esr"] = "Firefox",
        ["chromium-browser"] = "Chromium",
        ["code"] = "VS Code",
        ["alacritty"] = "Terminal",
    }
    return aliases[rawName]  -- nil if not in our table = C++ handles it
end
getAlias_Tab(rawName)
C++ → src/miscellaneous/aliasManager.cpp

Same idea as getAlias, but for browser tab titles. HPR tracks individual tabs as separate entries, and this hook lets you rename them on the fly. Combine "YouTube - Video 1" and "YouTube - Video 2" into just "YouTube" to declutter your stats, or tag categories like "Social" for all social media tabs.

Params: rawName (string) — the raw tab title Returns: string (custom alias) or nil
Example — Group all YouTube tabs together
HPR.overrides.getAlias_Tab = function(rawName)
    if rawName:find("YouTube") then
        return "YouTube"  -- collapse all YT tabs into one entry
    end
    if rawName:find("reddit") or rawName:find("Twitter") then
        return "Social Media"
    end
    return nil
end
getAlias_Project(rawName)
C++ → src/miscellaneous/aliasManager.cpp

Overrides alias lookup for project directories. HPR tracks which project folders you're working in (e.g., your IDE's active workspace). Raw directory names like "my-cool-project-v2-final" can be cleaned up here into something human-readable, or you can group multiple related repos under one umbrella name.

Params: rawName (string) — the raw project/directory name Returns: string (custom alias) or nil
Example — Group related project folders
HPR.overrides.getAlias_Project = function(rawName)
    -- Group all HPR-related repos under one name
    if rawName:find("HPR") then
        return "HPR Project"
    end
    return nil
end
getReverseAlias(aliasName)
C++ → src/miscellaneous/aliasManager.cpp

The reverse of getAlias — given a display alias, resolve it back to the raw process name. HPR uses this internally when it needs to go from pretty names back to actual system identifiers (e.g., for database lookups). Override this if you've custom-mapped aliases and need the reverse mapping to stay consistent.

Params: aliasName (string) — the display/alias name Returns: string (raw name) or nil
Example — Reverse lookup for custom aliases
HPR.overrides.getReverseAlias = function(aliasName)
    local reverse = {
        ["VS Code"] = "code",
        ["Firefox"] = "firefox-esr",
        ["Terminal"] = "alacritty",
    }
    return reverse[aliasName]
end
getReverseAlias_Tab(aliasName)
C++ → src/miscellaneous/aliasManager.cpp

Reverse alias lookup for browser tabs. If you've grouped tabs via getAlias_Tab (e.g., all YouTube videos → "YouTube"), this hook lets HPR resolve "YouTube" back to whatever raw title you want. Useful when other parts of the engine need the original title for comparison or display purposes.

Params: aliasName (string) — the tab alias Returns: string (raw tab title) or nil
Example — Reverse tab alias
HPR.overrides.getReverseAlias_Tab = function(aliasName)
    if aliasName == "Social Media" then
        return "reddit.com"  -- pick a representative raw name
    end
    return nil
end
getReverseAlias_Project(aliasName)
C++ → src/miscellaneous/aliasManager.cpp

Reverse alias lookup for project directories. Given a display name like "HPR Project", resolve it back to the actual directory name. Keep this in sync with your getAlias_Project override so HPR doesn't get confused when doing reverse lookups.

Params: aliasName (string) — the project alias Returns: string (raw folder name) or nil
Example — Reverse project alias
HPR.overrides.getReverseAlias_Project = function(aliasName)
    if aliasName == "HPR Project" then
        return "HPR"
    end
    return nil
end
🗃️

Database

6 functions
dbQuery(sql, params)
C++ → src/database/databaseManager.cpp

Intercepts SELECT queries going to the main active database. Every time an extension calls HPR.dbQuery_E(), this hook fires first. You can return fake/mock data, filter out sensitive rows, or redirect queries entirely. The return format is an array of tables, where each table is a row with column-name → value pairs.

Params: sql (string), params (array of strings) Returns: array of {key=value} tables, or nil
Example — Mock database results for testing
HPR.overrides.dbQuery = function(sql, params)
    -- Intercept app_usage queries and return mock data
    if sql:find("app_usage") then
        return {
            { name = "VS Code", duration = "7200000" },
            { name = "Firefox", duration = "3600000" },
        }
    end
    return nil  -- all other queries run normally
end
dbExecute(sql, params)
C++ → src/database/databaseManager.cpp

Intercepts write operations — INSERT, UPDATE, DELETE, and any other non-SELECT SQL statements. This is a powerful safety net: you can block destructive writes, log all mutations for auditing, or conditionally prevent data from being recorded. Return any value to prevent the write from hitting the database.

Params: sql (string), params (array of strings) Returns: any value to block the write, or nil to allow it
Example — Block DELETE statements as a safety guard
HPR.overrides.dbExecute = function(sql, params)
    -- Never allow any DELETE operations
    if sql:upper():find("DELETE") then
        print("[BLOCKED] Attempted DELETE: " .. sql)
        return true  -- blocks the execution
    end
    
    -- Log all writes for auditing
    print("[DB WRITE] " .. sql)
    return nil  -- let it through
end
dbQueryPath(dbPath, sql, params)
C++ → src/database/databaseManager.cpp

Like dbQuery, but for queries targeting a specific database file path rather than the main active database. Extensions can query arbitrary .db files on disk, and this hook lets you intercept those. Useful for mocking historical data or redirecting queries to a different database entirely.

Params: dbPath (string), sql (string), params (array of strings) Returns: array of {key=value} tables, or nil
Example — Redirect queries from one db to another
HPR.overrides.dbQueryPath = function(dbPath, sql, params)
    print("[dbQueryPath] " .. dbPath .. " → " .. sql)
    
    -- Block queries to databases outside HPR's data dir
    if not dbPath:find("HPR") then
        print("[BLOCKED] Query to external db!")
        return {}  -- return empty results
    end
    return nil
end
dbQueryHistorical(sql, params)
C++ → src/extension/extensionManager.cpp

Intercepts SELECT queries against the currently loaded historical database. When users view past data (e.g., "show me last Tuesday's stats"), HPR loads a historical .db file. This hook lets you mock historical data for testing, inject computed/aggregated values, or filter out rows you don't want displayed.

Params: sql (string), params (array of strings) Returns: array of {key=value} tables, or nil
Example — Inject fake historical data for demos
HPR.overrides.dbQueryHistorical = function(sql, params)
    -- Return fake data for demo mode
    if sql:find("app_usage") then
        return {
            { name = "Productivity Suite", duration = "14400000" },
            { name = "Research", duration = "10800000" },
            { name = "Communication", duration = "3600000" },
        }
    end
    return nil
end
getLoadedHistDbPath()
C++ → src/database/databaseManager.cpp

Returns the file path of the currently loaded historical database. Other extensions or internal code might use this to know which .db file is active for historical queries. Override this to spoof the path — useful for pointing the system at a custom database location or for testing purposes.

Params: none Returns: string (spoofed path) or nil
Example — Point to a custom database file
HPR.overrides.getLoadedHistDbPath = function()
    -- Always report our custom test database
    return "/home/user/.local/share/HPR/test_data/demo.db"
end
getDbPathForDate(date)
C++ → src/database/databaseManager.cpp

Resolves which .db file to use for a given date. HPR organizes data by date (e.g., 01-06-2026.db) in month-based folders. Override this to implement custom database storage schemes — maybe you want all databases in one flat folder, or you want to redirect to a network-mounted path, or you're building a backup system.

Params: date (string) — date in DD-MM-YYYY format Returns: string (custom file path) or nil
Example — Custom database storage scheme
HPR.overrides.getDbPathForDate = function(date)
    -- Store all databases in a flat directory
    return "/mnt/nas/hpr-data/" .. date .. ".db"
end
⏱️

Live Time Logs

3 functions
getLiveTimeLogPerApp_E()
C++ → src/extension/window_E.cpp

Returns a table mapping application names → tracked duration in milliseconds for the current live session. Note: HPR's core engine does not rely on this function for its own tracking, database logs, or UI rendering. Overriding this will not affect the main HPR application stats, but it will ensure that your overridden value is returned to other extensions that query the live application time logs.

Params: none Returns: table {appName = milliseconds, ...} or nil
Example — Merge apps into categories for other extensions
HPR.overrides.getLiveTimeLogPerApp_E = function()
    -- Return custom merged categories
    return {
        ["Coding"] = 7200000,       -- 2 hours
        ["Browsing"] = 3600000,     -- 1 hour
        ["Communication"] = 1800000, -- 30 min
    }
end
getLiveTimeLogPerTab_E()
C++ → src/extension/window_E.cpp

Returns a table mapping browser tab titles → tracked duration in milliseconds. Note: HPR's core engine does not rely on this function for its own tracking, database logs, or UI rendering. Overriding this will not affect the main HPR application stats, but it will ensure that your overridden value is returned to other extensions that query the live browser tab time logs.

Params: none Returns: table {tabTitle = milliseconds, ...} or nil
Example — Filter out boring tabs for other extensions
HPR.overrides.getLiveTimeLogPerTab_E = function()
    -- Only report tabs with meaningful time
    return {
        ["GitHub"] = 5400000,
        ["Stack Overflow"] = 2700000,
    }
end
getLiveTimeLogPerProject_E()
C++ → src/extension/window_E.cpp

Returns a table mapping project directories → tracked duration in milliseconds. Note: HPR's core engine does not rely on this function for its own tracking, database logs, or UI rendering. Overriding this will not affect the main HPR application stats, but it will ensure that your overridden value is returned to other extensions that query the live project time logs.

Params: none Returns: table {projectName = milliseconds, ...} or nil
Example — Consolidate monorepo sub-projects for other extensions
HPR.overrides.getLiveTimeLogPerProject_E = function()
    return {
        ["HPR (all repos)"] = 14400000,  -- 4 hours combined
        ["Side Projects"] = 3600000,
    }
end
🌐

Network (HTTP)

2 functions
httpGet(host, path, secure, headers)
C++ → src/extension/extensionManager.cpp

Intercepts outgoing HTTP GET requests made by other extensions via HPR.httpGet_E(). This is incredibly useful for testing: return spoofed API responses without hitting the network. You can also use this as a firewall — block requests to domains you don't trust, or log every outgoing request for auditing. Return a table with body (string) and status (number) fields.

Params: host, path, secure (bool), headers (table) Returns: {body = "...", status = 200} or nil
Example — Mock API responses for offline development
HPR.overrides.httpGet = function(host, path, secure, headers)
    -- Mock the weather API so extensions work offline
    if host:find("api.weather") then
        return {
            body = '{"temp": 22, "condition": "sunny"}',
            status = 200
        }
    end

    -- Block requests to unknown domains
    if not host:find("github") and not host:find("hpr") then
        print("[FIREWALL] Blocked GET → " .. host)
        return { body = "", status = 403 }
    end

    return nil  -- allow the real request
end
httpPost(host, path, body, secure, headers)
C++ → src/extension/extensionManager.cpp

Intercepts outgoing HTTP POST requests. Same idea as httpGet, but for POST calls. Extensions that sync data to external services, send webhooks, or post analytics all pass through here. Great for building a "dry run" mode where nothing actually leaves your machine, or for capturing exactly what payload an extension is sending.

Params: host, path, body (string), secure (bool), headers (table) Returns: {body = "...", status = 200} or nil
Example — Dry-run mode: log all outgoing POSTs
HPR.overrides.httpPost = function(host, path, body, secure, headers)
    print("[DRY RUN] POST → " .. host .. path)
    print("  Body: " .. body)

    -- Pretend it succeeded without actually sending
    return {
        body = '{"ok": true}',
        status = 200
    }
end
⏯️

Tracking Control

2 functions
stopTracking()
C++ → src/extension/extensionManager.cpp

Called when something tells HPR to pause window tracking. This might be triggered by the user clicking "Pause" in the UI, or by another extension calling HPR.stopTracking_E(). Override this to prevent tracking from being paused — maybe you want to force continuous tracking during work hours, or add a confirmation step before pausing. Return any value to block the pause.

Params: none Returns: any value to block the pause, or nil to allow
Example — Prevent pausing if a custom flag is active
HPR.overrides.stopTracking = function()
    if preventPausing == true then
        print("[Override] Pausing is currently blocked!")
        return true  -- blocks the pause
    end
    return nil  -- allow pausing
end
startTracking()
C++ → src/extension/extensionManager.cpp

Called when something tells HPR to resume window tracking. The counterpart to stopTracking. Override this if you want to conditionally block tracking from resuming — for instance, keeping tracking paused on weekends, or only allowing it to resume after a specific condition is met. Return any value to block the resume.

Params: none Returns: any value to block the resume, or nil to allow
Example — Block tracking from resuming if a custom flag is active
HPR.overrides.startTracking = function()
    if blockResume == true then
        print("[Override] Resuming tracking is blocked.")
        return true  -- keeps tracking paused
    end
    return nil
end
🎨

UI (Slint Interface)

2 functions
setUiProperty(name, value)
C++ → src/extension/extensionManager.cpp

Intercepts calls to update a Slint UI property. When any extension calls HPR.setUiProperty_E("propertyName", value), this hook fires first. You can block specific property updates, transform the values before they reach the UI, or redirect them entirely. This is how you hijack the visual layer — change colors, text, visibility, or any UI state before it renders.

Params: name (string), value (any — string/number/bool/table) Returns: any value to block the update, or nil to allow
Example — Block sensitive UI updates
HPR.overrides.setUiProperty = function(name, value)
    -- Prevent any extension from changing the title bar
    if name:find("title") then
        print("[Blocked] UI title change to: " .. tostring(value))
        return true
    end

    -- Log all UI updates for debugging
    print("[UI] " .. name .. " = " .. tostring(value))
    return nil
end
registerUiCallback(name)
C++ → src/extension/extensionManager.cpp

Intercepts UI callback registrations. When an extension tries to bind a Lua function to a Slint UI action (like a button click or slider change), this hook fires with the callback name. You can block specific registrations to prevent extensions from hooking into certain UI actions, or log them for debugging. Return any value to block the registration.

Params: name (string) — the callback/action name being registered Returns: any value to block registration, or nil to allow
Example — Whitelist allowed UI callbacks
HPR.overrides.registerUiCallback = function(name)
    local allowed = {
        ["on-refresh-clicked"] = true,
        ["on-date-changed"] = true,
    }
    
    if not allowed[name] then
        print("[Blocked] Callback registration: " .. name)
        return true
    end
    return nil
end
🔧

Utilities

1 function
getTime_MS()
C++ → src/extension/extensionManager.cpp

Returns the current system time in milliseconds (epoch). HPR and extensions use this for timestamping events, calculating durations, and scheduling. Override this to mock time — the holy grail for testing. You can freeze time, accelerate it, or set it to any specific moment. Every part of the engine that asks "what time is it?" will get your answer instead.

Params: none Returns: number (milliseconds since epoch) or nil
Example — Toggle between real and frozen time
HPR.overrides.getTime_MS = function()
    -- Use a flag to toggle between real time and a mock timestamp
    if HPR.useMockTime then
        return 1767225600000 -- Frozen at Jan 1, 2026
    end
    return nil -- Default to system time
end

Quick Reference

# Override Key Params Returns Category
1validateAndUpdateWindow_CrosswindowNamestring | nilWindow
2showNotificationtitle, messageany | nilWindow
3getCurrentWindow_Estring | nilWindow
4getCurrentTitle_Estring | nilWindow
5getAliasrawNamestring | nilAlias
6getAlias_TabrawNamestring | nilAlias
7getAlias_ProjectrawNamestring | nilAlias
8getReverseAliasaliasNamestring | nilAlias
9getReverseAlias_TabaliasNamestring | nilAlias
10getReverseAlias_ProjectaliasNamestring | nilAlias
11dbQuerysql, paramsarray | nilDatabase
12dbExecutesql, paramsany | nilDatabase
13dbQueryPathdbPath, sql, paramsarray | nilDatabase
14dbQueryHistoricalsql, paramsarray | nilDatabase
15getLoadedHistDbPathstring | nilDatabase
16getDbPathForDatedatestring | nilDatabase
17getLiveTimeLogPerApp_Etable | nilTime Log
18getLiveTimeLogPerTab_Etable | nilTime Log
19getLiveTimeLogPerProject_Etable | nilTime Log
20httpGethost, path, secure, headers{body, status} | nilNetwork
21httpPosthost, path, body, secure, headers{body, status} | nilNetwork
22stopTrackingany | nilTracking
23startTrackingany | nilTracking
24setUiPropertyname, valueany | nilUI
25registerUiCallbacknameany | nilUI
26getTime_MSnumber | nilUtility