A small desktop companion with increasingly large opinions about your screen time. Built for Windows with Python 3.10+ and Tkinter. All three placeholder potato sprites are drawn in code: no image downloads, icon packages, accounts, or API keys needed.
Install Python from python.org with Tcl/Tk support (included in the regular installer). In this directory:
python -m spudbotOr double-click launch.bat. No Python packages are required for the core app.
python -m spudbot --demoDemo runs at 60× speed: default moods change after 30 and 60 real seconds. Every OS effect is simulated, even if enabled in preferences. Manual breaks still use real minutes. Switching demo on/off starts a fresh session.
Install Ollama, then download a model once:
ollama pull llama3.2:1bStart the Ollama desktop application (or ollama serve if it isn't already running).
Choose the installed model in Preferences and select Check Ollama. phi3 also
works after ollama pull phi3. The default is the smaller llama3.2:1b.
SpudBot never downloads models itself. With no model/server, it immediately falls
back on a built-in collection of roasts after a failed request; inference requests
time out after 25 seconds, while the interface remains responsive.
| Continuous time | Mood | Desktop pet |
|---|---|---|
| 0–30 minutes | Happy | 50 px, screen corner |
| 30–60 minutes | Annoyed | 150 px, screen corner |
| 60+ minutes | Angry | 500 px, screen center |
- A fresh taunt every 15 minutes, or click the potato / Roast me.
- Take a break starts a five-minute break; completing it resets the timer. Ending it early preserves the previous continuous time.
- Five minutes without mouse/keyboard input also resets the timer, once per absence. Brief idle time counts toward a continuous session. Passive reading or watching a video can be counted as a break: input idle is a heuristic, not presence detection.
- Pause freezes tracking. Esc stops active effects and pauses tracking globally while the app is running. Resuming preserves elapsed time. A polling gap over 30 seconds (such as sleep/resume) resets the session rather than firing overdue effects.
- Drag the floating potato to move it. Right-click for open, pause, break, and quit. Pet only hides the control panel; right-click the pet to reopen it. Closing the control panel quits the application; there is no system tray or auto-start service.
- Preferences validate and save to
%LOCALAPPDATA%\SpudBot\settings.json. Saving starts a fresh timer. The roast log holds the latest 200 entries in memory; break counts and logs are scoped to this run, not historical analytics.
Effects are off initially. Enable individual effects in Preferences. Once angry, one enabled effect is chosen at the threshold and every five minutes afterward:
- Brightness: set supported monitors to 10% for two seconds and restore each
monitor's original level. Requires
python -m pip install ".[brightness]". Monitor/driver compatibility varies; unavailable effects appear in the roast log. - Mouse: confine the cursor to the primary display's center for at most ten seconds. Keyboard input remains available; Esc releases it immediately.
- Minimize: minimize the current foreground window; skip SpudBot, the desktop, and taskbars. Restore it using the taskbar. Applications are never closed or killed.
Effects run in an independent helper process so the Tk event loop cannot hold up cleanup. Break, pause, preferences changes, demo changes, Esc, and exit signal that helper to stop. Cleanup releases the cursor and attempts to restore all brightness values, including after an exception. Brightness failures are reported; no software can guarantee restoration if a monitor disconnects, a driver hangs, or the helper itself is forcibly killed. No elevation, input hooks, or background service is used.
SpudBot's screen-time companion is inspectable and local by design. It checks only
the time of the last input event using Windows GetLastInputInfo; it does not record
keystrokes, capture screenshots, read window text, or send desktop telemetry.
The AI request contains the persona and elapsed whole minutes, sent exclusively to
127.0.0.1:11434 with proxy routing disabled. Ollama runs an open-weight model locally.
After the initial software/model downloads, SpudBot can operate offline with no
API charges. Built-in roasts also work without Ollama. Hardware/electricity and
initial download costs still depend on your setup. Ollama's own updater/settings
are managed separately by Ollama.
The Touch Grass idea: turn an abstract time limit into a tiny, expressive companion that grows from cheerful potato to increasingly unimpressed couch-vegetable critic.
python -m unittest discover -v
python -m spudbot --smoke-test
python -m compileall -q spudbot testsUnit tests exercise timer boundaries, cadence, idle/sleep resets, pause, break completion, AI fallbacks, local-only routing, config recovery, simulation, and effect cleanup with mocked OS operations. The GUI smoke test renders every screen, all three pet sizes, bubbles, and navigation/break/pause/demo controls, then exits. It does not run real OS effects or call Ollama.
Source map: engine.py is the deterministic timer, ai.py is the loopback client,
windows.py wraps Win32, effects.py owns bounded effect workers, art.py contains
replaceable placeholder drawings, and ui.py contains the dashboard and desktop pet.
Windows is the supported platform; other systems can render the dashboard but do
not get Windows activity detection, transparent pet windows, or OS effects.
API references: Ollama generate, GetLastInputInfo, ClipCursor.
MIT licensed. Python 3.10+ is the target; validation on this machine uses Python 3.14.