A screen-time tracking and enforcement system. It has three parts:
server/– A Go HTTP server that receives client events, stores them in SQLite, and serves an HTML admin UI for reports, settings, and lock/unlock commands.client-windows/– A Windows client built as a singlerootaika.exethat runs both a background service and a user-session agent (rootaika.exe service/rootaika.exe agent). It updates itself over the air from a public GitHub release.client-waveshare/– A Raspberry Pi + Waveshare e-ink display that shows today's per-device screen-time totals, fetched from the server as JSON.client-rp2040-button/– An RP2040 board with a physical button that locks (short press) or unlocks (long press) all devices via the server API.
The client sends activity events to the server, polls for config and commands, and enforces screen locking.
- Go 1.22 or newer (the server image build uses Go 1.24).
- Docker (optional, for running the server in a container).
- Windows + PowerShell 5.1 (for building and installing the client).
Both modules use pure-Go SQLite (modernc.org/sqlite), so CGO is not required.
cd server
go test ./...
go run ./cmd/rootaika-serverThe default address is http://localhost:8080/ and the database is rootaika.db. The admin UI is served at the root /.
Compiled binary:
cd server
go build -o rootaika-server ./cmd/rootaika-server
./rootaika-server| Variable | Default | Description |
|---|---|---|
ROOTAIKA_ADDR |
:8080 |
Listen address/port |
ROOTAIKA_DB_PATH |
rootaika.db |
SQLite file path |
ROOTAIKA_DATA_DIR |
dir of ROOTAIKA_DB_PATH |
Directory for filesystem assets (uploaded lock-warning MP3) |
ROOTAIKA_ADMIN_USER |
admin |
Admin UI user |
ROOTAIKA_ADMIN_PASSWORD |
admin |
Admin UI password |
ROOTAIKA_CLIENT_USER |
client |
Client API user |
ROOTAIKA_CLIENT_PASSWORD |
client |
Client API password |
Change the credentials in production:
ROOTAIKA_ADMIN_PASSWORD='change-me' \
ROOTAIKA_CLIENT_PASSWORD='change-me-too' \
ROOTAIKA_ADDR=:8080 \
ROOTAIKA_DB_PATH=rootaika.db \
go run ./cmd/rootaika-servercd server
docker build -t rootaika-server .
docker run --rm -p 8080:8080 -v rootaika-data:/data \
-e ROOTAIKA_ADMIN_PASSWORD='change-me' \
-e ROOTAIKA_CLIENT_PASSWORD='change-me-too' \
rootaika-serverThe image builds a static binary (CGO_ENABLED=0), runs as a non-root user, and persists the database in the /data volume.
The client is a single rootaika.exe dispatched on its first argument, so one file swap updates everything:
rootaika.exe service: a background process that holds the config, buffers events into a local SQLite database, sends batches to the server, polls for config and commands, keeps the agent running (watchdog), and performs over-the-air updates.rootaika.exe agent: a process that runs in the user session, reads idle time and the active process, sendsactivity_observedevents to the service, and enforces lock/unlock.rootaika.exe apply-update: a transient helper the service launches to swap the binary and restart the service during an OTA update.
cd client-windows
go test ./...
GOOS=windows GOARCH=amd64 go build ./cmd/rootaikaUse the PowerShell script, which produces rootaika.exe into dist/:
cd client-windows
.\scripts\build.ps1 -Version v1.2.0The binary is linked with the -H=windowsgui flag, so neither process shows a console by default (debug mode allocates a console at runtime). Alternatively, build manually:
go build -ldflags "-H=windowsgui -X rootaika/client-windows/internal/version.Version=v1.2.0" .\cmd\rootaikaThe server declares a desired client version as a triple (version, artifact_name, sha256). Releases are registered once in the admin UI's Versiot section, then the deployed version is selected from that registry: globally in settings, or as a per-device override (test one machine first). The client reports its own version on the config poll (client_version); when the server's desired version differs, the service downloads the named asset from the fixed public repo github.com/pre/rootaika, verifies its SHA256, and launches apply-update to swap the file and restart, without rebooting Windows. A failed version is not retried for 30 minutes, so a bad release cannot spin.
Create a draft release; the script generates release notes from the conventional commits since the previous tag (grouped into Features / Fixes / Tests / Chores / Other), pins the release to the current HEAD, and dispatches the build workflow:
bin/release-github v1.2.3GitHub Actions (.github/workflows/release.yml) builds rootaika.exe inside the pinned Go image and attaches the exe, its .sha256 file, and install.ps1 to the draft, appending the admin-UI triple to its notes. Open the printed link, wait for the assets to appear, review, and press Publish release. Publishing creates the tag and locks the release permanently: the repo uses immutable releases, so assets cannot be added or changed after publishing, and a published tag name can never be reused — a broken release is abandoned and superseded by the next version. You author the release; the assets are built and uploaded by the rootaika-bot machine account (a collaborator with write access whose classic PAT, public_repo scope only, is the RELEASE_BOT_TOKEN Actions secret — the workflow's own GITHUB_TOKEN is read-only).
The build is reproducible: the same commit built in the same image yields a bit-identical exe, so anyone can verify a published release locally:
git checkout v1.2.3
make -C client-windows docker-build VERSION=v1.2.3
cat client-windows/dist/rootaika.exe.sha256 # must equal the release asset digestIf Actions is unavailable, build and attach the assets by hand while the release is still a draft: make -C client-windows docker-build VERSION=v1.2.3, then gh release upload v1.2.3 client-windows/dist/rootaika.exe client-windows/dist/rootaika.exe.sha256 client-windows/scripts/install.ps1 — immutability makes uploads impossible after publishing.
.\scripts\install.ps1 -ClientPassword change-meThe script:
- copies
rootaika.exetoC:\Program Files\rootaika, - writes the config to
C:\ProgramData\rootaika\client.json, - registers the
rootaika-serviceservice (rootaika.exe service) with auto-start and crash recovery (restart/5000three times), - registers the agent (
rootaika.exe agent) to start on user logon (HKLMRun), - starts the service and agent immediately.
.\scripts\uninstall.ps1 # removes the service and autostart
.\scripts\uninstall.ps1 -Purge # also removes the binaries and config/bufferThe default path is C:\ProgramData\rootaika\client.json. The first launch creates the config and a persistent client_id UUID.
{
"server_url": "http://192.168.68.199:8080",
"client_username": "client",
"client_password": "change-me",
"agent_listen_address": "127.0.0.1:48611"
}The default server URL uses the direct LAN IP http://192.168.68.199:8080 until DNS is available. Existing configs that still contain the old loopback default http://127.0.0.1:8080 are migrated to the LAN IP on load. The environment variables ROOTAIKA_SERVER_URL, ROOTAIKA_CLIENT_USERNAME, ROOTAIKA_CLIENT_PASSWORD, and ROOTAIKA_AGENT_LISTEN_ADDRESS override the file values at runtime.
Debug mode is read only from the config file's debug_mode field (or from the config the server pushes down). There is no command-line flag or environment variable for it. Each subcommand accepts only -config. When built with -H=windowsgui, debug_mode: true opens a console window at runtime.
To run against a specific server without touching the installed C:\ProgramData\rootaika\client.json, create a separate config such as debug.json:
{
"server_url": "http://192.168.68.199:8080",
"client_username": "client",
"client_password": "change-me",
"agent_listen_address": "127.0.0.1:48611",
"debug_mode": true
}Then start the service against it (its watchdog launches the agent from the same exe):
.\rootaika.exe service -config .\debug.jsonThe service fills in any missing fields (client_id, agent_token, intervals, db path) and saves them back on first run. Notes:
- If
rootaika-serviceis already installed as a Windows service, stop it first (sc stop rootaika-serviceorscripts\uninstall.ps1) so two instances do not fight over the agent port (48611). ROOTAIKA_SERVER_URLcan override the server URL at runtime, butdebug_modehas no environment override and must be set in the config file.
For more detail, see client-windows/README.md and server/README.md.
- Start the server (Docker or binary) and set strong
ROOTAIKA_ADMIN_PASSWORDandROOTAIKA_CLIENT_PASSWORDvalues. - Build the client (
rootaika.exe) with thescripts\build.ps1script. - Install the client on each Windows machine with
scripts\install.ps1, providing the client password and overriding-ServerUrlonly if needed. - Manage machines, reports, and locks from the admin UI at
http://<server>:8080/.
The client uses these endpoints with Basic Auth (the client credentials):
POST /api/v1/events/batchGET /api/v1/client/config?client_id=<uuid>GET /api/v1/client/commands?client_id=<uuid>POST /api/v1/client/commands/{command_id}/ack?client_id=<uuid>
The e-ink board client (client-waveshare/) uses the client credentials to read:
GET /api/v1/board/today– today's per-device active minutes plus the admin-configured refresh interval, as compact JSON.
The local API between the agent and the service is protected by an X-Rootaika-Agent-Token header generated into the config.
MIT, see LICENSE.