- index.html: fix playWarningSound (440→550 Hz, louder), fix playBubbleSound (audible volumes/durations), add looping klaxon sound (sawtooth wah-wah), stopKlaxon() on tap and state clear, bump VERSION to v2.2.0 - kao_tui.py: add klaxon to SOUNDS list, drop notify duration 5→2s for faster iteration; also include improved post() error reporting - CLAUDE.md: add kao_tui.py to file structure, fix personality table (remove ˙▿˙ row not in aggregator), add klaxon to sound list - README.md: add klaxon to sound list, update counts - openapi.yaml: bump version to 2.2.0, add klaxon to sound enum Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.4 KiB
6.4 KiB
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.mdas well. The README is the main user-facing documentation for the project. - On every commit, bump the version number in
index.html(theVERSIONconstant) and updateREADME.mdwith 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
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:
{
"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
{
"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:
( -_-)zzZdim, very slow breathing
Home Assistant Integration
Add REST commands to configuration.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:
# 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
└── SPEC.md # Original project specification