# Sol Clippy System-Aware Idle Puppeteer

The Linux host daemon `/home/david/random/bin/sol98_clippy_idle.py` gives the
standalone Windows 98 Clippit character occasional system-aware idle behavior.
It does not automate Microsoft Agent directly. It sends allowlisted animation
and balloon commands through the authenticated Sol Chat bridge, preserving the
existing durable guest acknowledgement path.

## Runtime

- Installed daemon: `/home/david/.local/lib/sol98/sol98_clippy_idle.py`
- User service: `/home/david/.config/systemd/user/sol98-clippy-idle.service`
- Configuration: `/home/david/.config/sol98/clippy-idle.json`
- Atomic live state: `/home/david/.cache/sol98-clippy-idle-state.json`
- Deduplication history: `/home/david/.local/state/sol98-clippy-idle-observations.json`
- Control surface: `System-Aware Idle Puppeteer` in the Sol Clippy XFCE icon

The service samples every 15 seconds. The XFCE menu can enable or disable the
service, edit thermal and idle thresholds, toggle local-LLM prose, display a fresh diagnostic sample,
display daemon state, and manually test warm-CPU, idle-patrol, and system-status
scripts.

## LLM Observations

Automatic prose is generated by the loopback-only Gemma endpoint at
`http://127.0.0.1:18080/v1/chat/completions`. Each prompt includes current
temperature, load, disk-free percentage, session idle duration, VM state, and
a bounded top-ten host process tree containing only PID, parent PID, executable
name, parent name, CPU, memory, and elapsed time. Full command lines are never
sent.

The model must return allowlisted animation and balloon text as JSON. Output is
rejected when it invents guest process placement, diagnoses throttling or fans,
mislabels disk-free percentage, ignores a required factual focus, repeats a
recent opening, or is semantically close to any of the last 12 observations.
Rejected drafts are retried with a different focus. Several distinct factual
fallbacks keep monitoring functional if the model is unavailable.

## Sensor Selection

The selected CPU sensor is the installed `coretemp-0` sensor labeled
`Package id 0`, exposed through sysfs as `coretemp/Package id 0`. This matches
the package temperature shown by the XFCE Sensors plugin. The daemon does not
mistake the warmer NVMe composite sensor for CPU temperature and does not use a
single core as the package-wide trigger.

## Interaction Schedule

The default warm threshold is 40 C with a 38 C clear threshold. Crossing 40 C
immediately sends the first observation. If the package remains warm, staged
scripts run after 10 minutes, 30 minutes, and 60 minutes; the last stage may
repeat hourly. Temperature must remain at or below 38 C continuously for 15
minutes before the threshold rearms, preventing oscillation around 40 C from
repeating stage one. A service restart has a 60-second thermal startup grace.

The warm scripts rotate through `Alert`, `CheckingSomething`, `GetTechy`, and
`IdleHeadScratch`. Text includes current temperature, elapsed warm time, load,
or VM state, with occasional period-appropriate humor.

After at least 15 minutes of real desktop-session idle time, quieter patrols
can report temperature, load, disk space, time, bridge health, and VM state.
Normal idle patrols default to one every 45 minutes. A low-system-disk warning
is limited to once every six hours, and an idle high-load warning to once per
hour. A global 10-minute cooldown prevents different rules from speaking over
one another. A bridge command is never added while another Clippy command is
pending.

## Commands

```bash
systemctl --user status sol98-clippy-idle.service
systemctl --user enable --now sol98-clippy-idle.service
systemctl --user disable --now sol98-clippy-idle.service

/home/david/.local/lib/sol98/sol98_clippy_idle.py --diagnostics
/home/david/.local/lib/sol98/sol98_clippy_idle.py --status
/home/david/.local/lib/sol98/sol98_clippy_idle.py --test warm --dry-run
/home/david/.local/lib/sol98/sol98_clippy_idle.py --test idle
/home/david/.local/lib/sol98/sol98_clippy_idle.py --test status
```

The default JSON configuration is created automatically. The menu edits the
warm threshold, clear threshold, minimum idle time, and idle interval. Advanced
keys include `thermal_intervals_seconds`, `high_load_per_cpu`,
`disk_free_warning_percent`, `event_cooldown_seconds`, and `poll_seconds`.

## Verification

On 2026-07-16 fixed stage-one prose was found repeating as the package crossed
and recrossed the threshold. The balloon was cleared, sustained-cool rearming
and semantic history were deployed, and command 143 was generated by the local
LLM from a live 49 C reading plus the bounded host process tree. Windows 98
applied and acknowledged the new observation.
After the 60-second startup grace, automatic thermal command 144 was generated
by the LLM from a 46 C reading, 2.2% free disk space, and current
`python3`/`VBoxHeadless` CPU activity. It differed from command 143 and was
acknowledged as `applied`.
