Kao is a display, not a monitor — external systems push events via REST rather than Kao polling things itself. Update CLAUDE.md to reflect this: - New Design Philosophy section making the REST-first approach explicit - Architecture diagram updated to show external systems as the push source - Detectors section demoted to "Legacy Detectors" with a note to prefer push - TODO.md added with planned REST API improvements (SSE, notify queue, sticky notifications, named presets, batch notify, /history endpoint) and display improvements (brightness curve, scrolling ticker) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
202 lines
7.3 KiB
Markdown
202 lines
7.3 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 ambient display for an old Pixel phone. It uses ASCII "emotes" to represent system health instead of graphs or dashboards. External systems (Home Assistant, Uptime Kuma, scripts, etc.) push events and notifications to Kao via REST — Kao itself does not poll or monitor anything.
|
|
|
|
## Design Philosophy
|
|
|
|
**Kao is a display, not a monitor.** It should not duplicate work that other tools already do. The right pattern is: your existing monitoring stack detects a problem, then POSTs to Kao to show it. This keeps Kao simple and lets each tool do what it's good at.
|
|
|
|
The bundled `detectors/` scripts are legacy and exist for standalone use cases. New work should focus on making the REST API richer, not adding more detectors.
|
|
|
|
## Architecture
|
|
|
|
**REST push model:**
|
|
|
|
```
|
|
┌─────────────────────┐ POST /event ┌─────────────┐ GET /status ┌─────────────┐
|
|
│ External systems │ ──────────────────▶ │ Aggregator │ ◀────────────────── │ Emote-UI │
|
|
│ (HA, scripts, etc) │ POST /notify │ (broker) │ │ (display) │
|
|
└─────────────────────┘ └─────────────┘ └─────────────┘
|
|
```
|
|
|
|
- **Aggregator** (`aggregator.py`) — Flask service managing the event queue and priority logic
|
|
- **Emote-UI** (`index.html`) — OLED-optimized web frontend
|
|
- **Sentry** (`kao.py`) — Unified entry point managing all processes
|
|
- **Detectors** (`detectors/*.py`) — Legacy standalone sensors; prefer REST push from existing tools
|
|
|
|
## 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" }
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Legacy Detectors
|
|
|
|
These bundled scripts exist for standalone use but are not the preferred approach. Prefer pushing from Home Assistant, Uptime Kuma, or any tool that already monitors what you care about.
|
|
|
|
| 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`, `doorbell`, `knock`, `ding`, `blip`, `siren`, `tada`, `ping`, `bubble`, `fanfare`, `alarm`, `klaxon`, `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 face is set once per day on `/wake` (random pick). Each morning a fresh emote is chosen:
|
|
|
|
| Emote | Animation | Vibe |
|
|
|-------|-----------|------|
|
|
| `( ^_^)` | breathing | calm |
|
|
| `(◕‿◕)` | 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
|
|
├── kao_tui.py # Developer TUI for testing sounds/events
|
|
├── 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
|
|
├── TODO.md # Planned features and improvements
|
|
└── SPEC.md # Original project specification
|
|
```
|