# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. **Important:** - When updating this file, always update `README.md` as well. The README is the main user-facing documentation for the project. - On every commit, bump the version number in `index.html` (the `VERSION` constant) and update `README.md` with any relevant changes. ## Project Overview Kao is a minimalist system status monitor designed for an old Pixel phone used as an ambient display. It uses ASCII "emotes" to represent system health instead of complex graphs. ## Architecture **Publisher/Subscriber model:** ``` ┌─────────────┐ POST /event ┌─────────────┐ GET /status ┌─────────────┐ │ Detectors │ ──────────────────▶ │ Aggregator │ ◀────────────────── │ Emote-UI │ │ (sensors) │ │ (broker) │ │ (display) │ └─────────────┘ └─────────────┘ └─────────────┘ ``` - **Aggregator** (`aggregator.py`) — Flask service managing the event queue and priority logic - **Detectors** (`detectors/*.py`) — Independent scripts monitoring system metrics - **Emote-UI** (`index.html`) — OLED-optimized web frontend - **Sentry** (`kao.py`) — Unified entry point managing all processes ## Quick Start ```bash python -m venv venv source venv/bin/activate # or .\venv\Scripts\activate on Windows pip install -r requirements.txt python kao.py ``` UI available at http://localhost:5100 ## Configuration Edit `config.json` to configure detectors: ```json { "aggregator_url": "http://localhost:5100", "aggregator": { "script": "aggregator.py" }, "detectors": [ { "name": "cpu", "enabled": true, "script": "detectors/cpu.py", "env": { "CHECK_INTERVAL": "30", "THRESHOLD_WARNING": "85", "THRESHOLD_CRITICAL": "95" } } ] } ``` ## Detectors | Detector | Script | Required Env Vars | |----------|--------|-------------------| | Disk Space | `detectors/disk_space.py` | — | | CPU | `detectors/cpu.py` | — | | Memory | `detectors/memory.py` | — | | Service | `detectors/service.py` | `SERVICES` (comma-separated process names) | | Network | `detectors/network.py` | `HOSTS` (comma-separated hostnames/IPs) | | Docker | `detectors/docker.py` | `CONTAINERS` (optional, monitors all if empty) | All detectors support: `AGGREGATOR_URL`, `CHECK_INTERVAL`, `THRESHOLD_WARNING`, `THRESHOLD_CRITICAL` ## API Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/event` | POST | Register event: `{"id": "name", "priority": 1-4, "message": "optional", "ttl": seconds}` | | `/clear` | POST | Clear event: `{"id": "name"}` | | `/clear-all` | POST | Clear all active events | | `/notify` | POST | Notification with optional customization (see below) | | `/sleep` | POST | Enter sleep mode | | `/wake` | POST | Exit sleep mode | | `/status` | GET | Current state JSON | | `/events` | GET | List active events | | `/docs` | GET | Interactive API documentation (Swagger UI) | ### `/notify` Endpoint ```json { "message": "Someone at the door", "duration": 10, "emote": "( °o°)", "color": "#FF9900", "animation": "popping", "sound": "chime" } ``` | Field | Required | Description | |-------|----------|-------------| | `message` | No | Text to display below emote | | `duration` | No | Seconds before auto-expire (default: 5) | | `emote` | No | Custom emote to display | | `color` | No | Custom color (hex, e.g., `#FF9900`) | | `animation` | No | One of: `breathing`, `shaking`, `popping`, `celebrating`, `floating`, `bouncing`, `swaying` | | `sound` | No | One of: `chime`, `alert`, `warning`, `critical`, `success`, `notify`, `none` | ## Priority System Lower number = higher priority. Events with a `ttl` auto-expire (heartbeat pattern). | Priority | State | Emote | Color | Animation | |----------|-------|-------|-------|-----------| | 1 | Critical | `( x_x)` | Red | shaking | | 2 | Warning | `( o_o)` | Yellow | breathing | | 3 | Notify | `( 'o')` | Blue | popping | | 4 | Optimal | varies | Green | varies | ## Personality System The optimal state cycles through emotes with paired animations every 5 minutes: | Emote | Animation | Vibe | |-------|-----------|------| | `( ^_^)` | breathing | calm | | `( ˙▿˙)` | floating | content | | `(◕‿◕)` | bouncing | cheerful | | `( ・ω・)` | swaying | curious | | `( ˘▽˘)` | breathing | cozy | Additional states: - **Idle expressions** (15% chance): `( -_^)`, `( ^_~)`, `( ᵕ.ᵕ)` with blink animation - **Recovery celebration**: `\(^o^)/` with bounce for 5 seconds after issues resolve - **Connection lost**: `( ?.?)` gray, searching animation - **Sleep mode**: `( -_-)zzZ` dim, very slow breathing ## Home Assistant Integration Add REST commands to `configuration.yaml`: ```yaml rest_command: kao_notify: url: "http://kao-host:5100/notify" method: POST content_type: "application/json" payload: '{"message": "{{ message }}", "duration": {{ duration | default(5) }}}' kao_sleep: url: "http://kao-host:5100/sleep" method: POST kao_wake: url: "http://kao-host:5100/wake" method: POST ``` Use in automations: ```yaml # Doorbell notification - service: rest_command.kao_notify data: message: "Someone at the door" duration: 10 # Bedtime routine - service: rest_command.kao_sleep # Morning routine - service: rest_command.kao_wake ``` ## File Structure ``` ├── kao.py # Unified entry point ├── aggregator.py # Event broker/API server ├── index.html # OLED-optimized frontend ├── config.json # Runtime configuration ├── openapi.yaml # API documentation (OpenAPI 3.0) ├── detectors/ │ ├── disk_space.py │ ├── cpu.py │ ├── memory.py │ ├── service.py │ ├── network.py │ └── docker.py ├── requirements.txt └── SPEC.md # Original project specification ```