Parental control for computer time: daily limits and allowed login hours per person, enforced on Windows, Linux and macOS, with one shared daily total across all computers and OSs.
Current version: 2.2.0. See CHANGELOG.md.
- One daily limit per child, across every computer and OS. Minutes used on the desktop, the laptop or the other OS of a multi-boot machine add up to one total.
- Allowed login hours and daily minutes, for weekdays and weekends, with per-day exceptions.
- The same child under different account names on different computers is recognised as one person.
- Configuration page: one window to manage people, limits, the network store and installation permissions, from any of the computers.
- Statistics: for any day, the minutes per child on each computer, and one timeline of what happened on all computers (sessions, locked screens, warnings, logoffs and why), exportable as CSV.
- The child is told why: a sign-in that isn't allowed shows the reason before signing out.
- Works offline: if the network store is unreachable, stricter offline limits apply and the minutes are uploaded later.
- Your data stays at home: usage is shared through your own WebDAV store (for example on a NAS), over HTTPS with a password; nothing is sent anywhere else.
Configuration: people and their limits. Here Sam has 90 minutes on weekdays between 08:00 and 20:00, 150 minutes at weekends, and a longer Friday. Other account names link Sam's accounts on the other computers. Blank fields use the defaults.
Statistics: the Activity tab. Minutes per child on each computer, and the combined timeline of all computers.
What a child sees when signing in after the daily time is used up (Windows):
All screenshots use demo data.
Each computer, and each OS on a multi-boot computer, runs its own tracker as a SYSTEM/root service. Every few minutes the tracker:
- Lists the active, unlocked desktop sessions. Locked screens and switched-away sessions do not count.
- Maps each account to a person from the configuration. Accounts that don't belong to a person are ignored and not recorded.
- Logs the person off if the time is outside their allowed login hours. Between these checks, new logins are checked every 20 seconds. Someone who signs in while already over the limit or outside the hours sees a message saying why (for example "Your time for today is used up (90 of 90 minutes)") and is signed out 15 seconds later.
- Adds the elapsed time to this installation's usage record for today. It writes locally first, then copies the record to the network store.
- Adds up the person's minutes from all installations and logs them off when the daily limit is reached.
Windows PC Linux (same PC) macOS laptop
tracker ──┐ tracker ──┐ tracker ──┐
local store local store local store
└───────────────────┴─────────────────────┴──► network store (WebDAV over HTTPS)
config/limits.toml
records/<installation>/<date>.json
events/<installation>/<date>.jsonl
writers/<installation>.json
Offline. If the network store can't be reached, the tracker keeps working from local data plus the last records it saw from other installations today. It then applies the stricter of the person's own limits and the global defaults. Records are uploaded once the store is reachable again.
Configuration. The configurator (a GUI) edits config/limits.toml on the network store.
Every tracker downloads it each cycle and only uses it after checking that it is valid, so a
broken file never replaces a working one. Each installation also keeps a local copy for offline
use. A revision number stops two people from overwriting each other's changes.
Shared activity log. Next to its local log file, every tracker keeps a journal of what happened to managed people on that computer: session counted, screen locked, user switched, close to the limit, logged off and why, offline and back. It is uploaded together with the usage records, so the configurator's Activity tab can show, for any day, the minutes per person per computer and one combined timeline of all computers, and export both as CSV.
Per time period there are three values: Max minutes (0-1440 per day), Earliest login and Latest login (HH:MM). For each value separately, the most specific setting wins:
- Person's day override (for example Monday)
- Person's weekday / weekend values
- Global defaults for weekday / weekend
schema = 1
revision = 4
[settings] # optional
check_interval_minutes = 5
retention_days = 30
log_level = "INFO"
[defaults.weekday]
limit_minutes = 120
earliest_login = "08:00"
latest_login = "21:00"
[defaults.weekend]
limit_minutes = 180
[users.sam]
accounts = ["sam.k"] # other account names of the same person, on other computers
[users.sam.weekday]
limit_minutes = 90
[users.sam.day_overrides.monday]
latest_login = "19:00"Account names are compared without regard to case.
Any WebDAV server reachable over HTTPS works. For TrueNAS Scale:
- Create a dataset, for example
tank/timemanager. Don't share it over SMB or NFS: only the trackers should write to it. - Install the WebDAV app. Share the dataset under a name such as
timemanager, with authentication set to basic, and HTTPS enabled. - Create a dedicated user for the trackers (for example
timemanager) with access to this share only. - Note the URL, for example
https://truenas.lan:30035/timemanager. If the certificate is self-signed, export its CA certificate as a PEM file and copy it to each computer. Certificates are always verified. - Recommended: schedule periodic ZFS snapshots of the dataset.
A cloud WebDAV provider works the same way, but only over https://.
- Multi-boot machines: make Windows keep the hardware clock in UTC, as Linux and macOS do. In an
administrator prompt, run
reg add HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v RealTimeIsUniversal /t REG_QWORD /d 1 /f, then reboot. - Windows time zone: by default, standard users can change the time zone. That shifts midnight
and the allowed login hours. Remove the right in
secpol.msc→ Local Policies → User Rights Assignment → Change the time zone → remove Users. - Children use standard (non-admin) accounts on every OS.
- Install the tracker on every OS on every computer the children can use.
- Firmware: set a firmware (BIOS/UEFI) setup password, disable booting from USB, and protect the OpenCore boot picker with a password. Otherwise an OS without the tracker can be booted.
Step-by-step guides, including testing: another Windows computer, Linux, macOS.
There is no installer. Each OS has its own build, a TimeManager folder containing tracker (the
service) and configurator (the GUI). Get it in either of two ways:
- Release zip:
TimeManager-<version>-<windows|linux|macos>.zip. - Build it yourself from the source, so you know exactly what runs as SYSTEM/root. PyInstaller
can't build for another OS, so build on each OS with Python 3.11 or newer:
The result is
python -m venv venv venv/bin/pip install -r requirements-dev.txt # Windows: venv\Scripts\pip ... venv/bin/python build.py # Windows: venv\Scripts\python build.py
dist/<os>/TimeManager/, plus the same folder as a zip indist/.
On Windows, a downloaded unsigned program triggers SmartScreen ("Windows protected your PC"). Choose More info → Run anyway, or build it yourself.
The tracker runs as SYSTEM/root. A user who can change its folder could replace the program and gain full control of the computer, so the folder must be writable by administrators only.
| OS | Copy the TimeManager folder to |
How |
|---|---|---|
| Windows | C:\Program Files\TimeManager |
Explorer (it asks for administrator rights). Program Files is already protected against changes by standard users |
| Linux | /opt/timemanager |
sudo mkdir -p /opt/timemanager && sudo cp -R TimeManager/. /opt/timemanager/ && sudo chown -R root:root /opt/timemanager |
| macOS | /usr/local/timemanager |
sudo mkdir -p /usr/local/timemanager && sudo cp -R TimeManager/. /usr/local/timemanager/ && sudo chown -R root:wheel /usr/local/timemanager |
The configurator checks these permissions and can fix them (step 5).
Upgrading: stop the task/service, copy the new folder over the old one, and start it again.
instance.toml, data/ and logs/ are kept.
Start the configurator with administrator rights: on Windows it asks through UAC; on Linux and
macOS, run sudo <install folder>/configurator/configurator. On Linux Wayland desktops, first allow
root to open windows with xhost +si:localuser:root.
- Connection: where this computer finds the network store.
- Choose Network store (WebDAV over HTTPS), then enter the URL (with the share name, e.g.
https://nas.home.arpa:30036/timemanager) and the username and password. - Choose the certificate file if the NAS certificate isn't publicly trusted. It's copied into the install folder.
- Test connection runs the same checks as
tools/check_store.py. Save connection writesinstance.toml(readable by SYSTEM/Administrators or root only), and the tracker reconnects within one check interval with no restart. - When you edit later, leave the password blank to keep the saved one.
- If the store has no limits yet, the configurator offers to upload this computer's limits.
- Installation shows the exact program your task/service must run (with a Copy button). It
warns if standard users can change the program folder or read
instance.toml; Fix permissions corrects that.
- Choose Network store (WebDAV over HTTPS), then enter the URL (with the share name, e.g.
- People: add a person by name, or pick a local account. Use Other account names when the same child has a different account name on another computer. Blank fields inherit.
- Defaults: the limits that apply to everyone. They are also the offline limits.
- Settings: the check interval, how many days of history to keep, and the log level.
- Activity: choose a day to see the minutes per person on each computer, with the total and the limit, and the combined timeline of all computers (in local time). Export CSV… saves both, for a spreadsheet or your own reports.
- Import from file… loads a
limits.toml, for example from version 1.x; press Save limits to store it.
Trackers pick up saved limits within one check interval.
The tracker runs as one endless loop (one cycle every check interval), so exactly one instance must run, from boot, as SYSTEM/root. You set this up yourself.
With the script (in PowerShell as administrator; the script is in the install folder):
cd "C:\Program Files\TimeManager"
powershell -ExecutionPolicy Bypass -File .\create-scheduled-task.ps1 # create and start the task
powershell -ExecutionPolicy Bypass -File .\create-scheduled-task.ps1 -Remove # remove it againIt creates the task with exactly the settings below (and replaces an existing one of the same name).
Options: -TaskName, -TaskFolder (e.g. My), -TrackerPath.
Or by hand in Task Scheduler (Create Task…, not Create Basic Task):
| Setting | Value | Why |
|---|---|---|
| Program | C:\Program Files\TimeManager\tracker\tracker.exe (no arguments) |
finds instance.toml one folder up by itself |
| Run as | SYSTEM, Run with highest privileges | logging users off needs it; children can't stop it |
| Trigger | At startup | runs before anyone logs in |
| Stop the task if it runs longer than | unchecked (no time limit) | otherwise Windows kills it after 3 days |
| If the task fails, restart every | 1 minute, up to 999 times | recovers from a crash |
| If the task is already running | Do not start a new instance | two trackers would count time twice |
| Power | do not "Start only on AC power"; do not stop on battery | laptops |
| Wake the computer to run | unchecked | sleep time isn't usage anyway |
Don't use a repeating trigger (every 5 minutes): the tracker repeats by itself, and repetition as in 1.x would start overlapping instances. After upgrading from 1.x, delete the old task.
The template timemanager-tracker.service is in the build folder (and in service/ in the source):
sudo cp /opt/timemanager/timemanager-tracker.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now timemanager-tracker
systemctl status timemanager-trackerThe template local.timemanager.tracker.plist is in the build folder (and in service/):
sudo cp /usr/local/timemanager/local.timemanager.tracker.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/local.timemanager.tracker.plist
sudo chmod 644 /Library/LaunchDaemons/local.timemanager.tracker.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/local.timemanager.tracker.plist
sudo launchctl print system/local.timemanager.trackerIf you installed somewhere else, change the program path in the template (it must match what the configurator's Installation section shows).
Read <install folder>/logs/tracker.log (as administrator/root). Set the log level to DEBUG in the
configurator to see every session and its minutes. To run one cycle by hand without logging anyone
off, stop the task/service first, then run, as administrator/root:
<install folder>/tracker/tracker --once --dry-runTo test enforcement, give a test account limit_minutes = 1.
core/ pure logic: config validation, limit resolution, usage records, enforcement rules
platforms/ OS adapters: windows.py (WTS + LogonUI), linux.py (loginctl), macos.py (ioreg + launchctl)
storage/ store backends: folder.py, webdav.py
tracker/ sync.py (local/network rules), cycle.py (one tracker cycle), main.py (service loop)
configurator/ session.py (load/save with revision check), gui.py (customtkinter window)
shared/ version and paths, instance.toml + installation identity, permission checks, logging
service/ systemd unit (Linux) and LaunchDaemon (macOS) templates
tools/ check_store.py: command-line check of a WebDAV store
tests/ pytest suite: run with python -m pytest
Local data lives next to the program: instance.toml, data/ (own records, cache, state) and
logs/ (rotating, 5 × 1 MB).
- The sign-in message is a message box on Windows, a desktop notification on Linux (GNOME, KDE; it
uses
notify-sendorgdbus) and a dialog on macOS. A fullscreen game may cover it; the sign-out happens anyway. - No warning before the time runs out during a session yet; only a sign-in that is not allowed is told why.
- Logoff is forced, so unsaved work is lost.
- An unlocked but idle session counts as usage.
- Changes in the configurator always overwrite whole settings; there's no per-field merge with someone else's edits (a revision conflict asks you to reload).


