Productivity Daemon
Electron + React + TypeScript + sql.js + Anthropic SDK app — an "attention antivirus" that monitors browsing, classifies distractions via AI, and blocks at multiple layers.
Code location: C:\Users\Lenovo\Desktop\AI\daemon (Windows path), /mnt/c/Users/Lenovo/Desktop/AI/daemon (WSL path)
Support Files
references/debug-api.md— Full debug API endpoint referencescripts/probe-template.mjs— Reusable Node.js probe script for API testing (auto-discovers port)
Quick Start
# From Windows terminal (as Administrator for full blocking):
cd C:\Users\Lenovo\Desktop\AI\daemon
npm run dev
The app exposes a debug HTTP API on http://127.0.0.1:9119 (falls back to 9120-9123 if port is held by a stale process — the hot-reload port fallback is normal in dev mode).
Debug API Testing — USE NODE.JS, NOT POWERSHELL
Critical pitfall: PowerShell Invoke-RestMethod / Invoke-WebRequest corrupts large JSON responses when piped through WSL subprocess — UnicodeDecodeError: invalid start byte on non-UTF8 bytes in the Electron process output.
Always use Node.js fetch() scripts for API testing. Write .mjs files in scripts/ and run them via:
powershell.exe -NoProfile -Command "cd 'C:\Users\Lenovo\Desktop\AI\daemon'; node scripts/<name>.mjs 2>&1"
sql.js Stale Data Pitfall
The app uses sql.js (SQLite compiled to WASM) loaded into memory on startup. Disk changes to the DB file do not take effect until the app restarts — the in-memory instance is isolated.
Even worse: db.export() + fs.writeFileSync() via sql.js sometimes fails to persist DELETEs silently. If stale inference data is masking a code fix:
- Kill the app (
Stop-Process -Name electron -Force) - Delete the DB file entirely:
C:\ProgramData\ProductivityDaemon\daemon.db - Restart — the app recreates a fresh DB from state.json
The state.json at C:\ProgramData\ProductivityDaemon\state.json is the durable source of truth (blocklists, settings, sessions). The SQLite DB stores inferences, events, and agent messages with 90-day retention.
Elevation Testing
The app has 5 blocking layers that only activate when elevation === 'full':
- hosts file redirect (127.0.0.1)
- DNS-over-HTTPS server disable
- Windows Firewall outbound block rules
- Browser policy injection (Chrome/Edge)
- Process killer
Script-based elevation (Start-Process -Verb RunAs) does not work — UAC requires manual user interaction at the GUI prompt. To test with elevation=full:
- Right-click Windows Terminal → "Run as Administrator"
cd C:\Users\Lenovo\Desktop\AI\daemon && npm run dev- Verify:
GET /state→elevation: "full"
Without elevation, the app functions as an interstitial blocker only (warning windows in the UI). The full blocking stack is untested until a manual Admin restart is performed.
Key Debug Endpoints
See references/debug-api.md for the complete reference. Quick checks:
| Endpoint | Purpose |
|---|---|
GET /ping |
Health check — PID, uptime, port |
GET /state |
Full store: elevation, blocklist, sessions, inferences, settings |
GET /inferences |
AI classifications (?status=pending|auto_applied|confirmed|rejected) |
GET /blocklist |
Active domain/process blocks |
GET /logs?n=N |
Structured debug log ring buffer |
POST /inject/url |
Run URL through full inference pipeline |
POST /inject/chat |
Send message to Claude agent (requires API key) |
POST /inject/scan |
Run FocusScan for installed distractor detection |
POST /inject/block |
Add domain to blocklist (now persists to store) |
POST /inject/sweep |
Trigger background inference sweep |
Confidence Threshold Architecture
Located in src/main/inference/InferenceEngine.ts:
CONFIDENCE_AUTO_BLOCK = 0.85— min for auto-apply in auto modeCONFIDENCE_SUGGEST = 0.60— min for suggestion in ask modeCATEGORY_AUTO_BLOCK_SCORE— per-category base scores (adult 0.97, social_media 0.88, video_streaming 0.85, etc.)HARDBLOCK_CATEGORIES— categories that skip the "no goals" confidence discount and always use baseScore + 0.05
Current HARDBLOCK_CATEGORIES: adult, gambling, dating, social_media, video_streaming
Common Debugging Workflow
GET /ping— confirm app is aliveGET /state— check elevation, blocklist state, blockingModePOST /inject/urlwith known distraction → verify inference pipeline- Check
/inferencesand/logsfor results - If confidence values look wrong: check for stale SQLite data (see pitfall above)
- If endpoints return 404: check app PID — old process may still hold the port. Kill all Electron processes and restart.
Known Quirks
- Port reuse in dev mode: Hot reload restarts the main process before the OS releases the port. DebugServer tries 9119→9120→9121→9122→9123. Always check
/pingfor the actual port, or readC:\ProgramData\ProductivityDaemon\debug-port. - Ring buffer starts empty:
/logs?n=5returns 0 entries on fresh start — normal. The buffer fills as events fire. - friendster.com appears as inference: Stale data from pre-fix sessions. Delete the DB to clear.
- Blocklist via debug API vs GUI: The
/inject/blockendpoint now persists correctly (was a previous P0 bug). Both paths use the same store.