- Extract shared send_event/clear_event into detectors/base.py, removing ~150 lines of duplication across all 6 detectors - Fix default aggregator URL from port 5000 to 5100 in all detectors - Standardize cpu.py and memory.py to use active_alerts set pattern - Fix immediate emote rotation on startup (last_emote_change = time.time()) - Extract magic numbers to named constants in aggregator - Protect write_status() with try/except OSError - Fix notify event ID collision with monotonic counter - Replace blocking stream_output() with background daemon threads in kao.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
193 lines
6.2 KiB
Markdown
193 lines
6.2 KiB
Markdown
# 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/
|
|
│ ├── base.py
|
|
│ ├── disk_space.py
|
|
│ ├── cpu.py
|
|
│ ├── memory.py
|
|
│ ├── service.py
|
|
│ ├── network.py
|
|
│ └── docker.py
|
|
├── requirements.txt
|
|
└── SPEC.md # Original project specification
|
|
```
|