feat(skills): add self-improving and system-monitor skills

self-improving: adapted from ClawHub's top skill (pskoett/self-improving-agent).
Logs errors, corrections, and learnings to skills/self-improving/data/.
Promotes important patterns to MEMORY.md for cross-session persistence.

system-monitor: health check for Armbian STB/server.
Monitors CPU temp, RAM, disk, load, and network connectivity.
health_alert.sh sends ntfy push only when thresholds are breached.
Reuses ntfy config from reminder skill for zero extra setup.
This commit is contained in:
muava12 2026-02-24 12:29:18 +08:00
parent a1c8d3c321
commit 7fc6cbea8f
7 changed files with 658 additions and 0 deletions

View file

@ -0,0 +1,223 @@
---
name: self-improving
description: Catat kesalahan, koreksi, dan pelajaran agar agent terus belajar dari pengalaman. Otomatis aktif saat terjadi error atau user mengoreksi.
metadata: {"nanobot":{"emoji":"🧠"}}
---
# Self-Improving Agent
Skill ini membuat agent belajar dari kesalahan dan koreksi. Setiap error, koreksi user, atau knowledge gap dicatat ke file log, dan pelajaran penting dipromosikan ke MEMORY.md agar persisten lintas sesi.
> Diadaptasi dari [self-improving-agent di ClawHub](https://clawhub.ai/pskoett/self-improving-agent) untuk PicoClaw.
## When to use (trigger phrases)
Skill ini aktif **otomatis** saat agent mendeteksi situasi berikut:
**Kesalahan:**
- Command gagal (non-zero exit code)
- Error, exception, atau stack trace
- Timeout atau connection failure
**Koreksi user:**
- "Bukan, yang bener..."
- "Salah, seharusnya..."
- "Actually, it should be..."
**Knowledge gap:**
- User kasih info yang agent belum tahu
- Dokumentasi ternyata outdated
- Perilaku API berbeda dari yang agent kira
**Feature request:**
- "Bisa gak kamu..."
- "Bagaimana kalau..."
- "I wish you could..."
## Storage
Semua log disimpan di `skills/self-improving/data/`:
```
skills/self-improving/data/
├── LEARNINGS.md # Koreksi, knowledge gaps, best practices
├── ERRORS.md # Command failures, exceptions
└── FEATURE_REQUESTS.md # User-requested capabilities
```
## Quick Reference
| Situasi | Aksi |
|---------|------|
| Command/operasi gagal | Catat ke `ERRORS.md` |
| User mengoreksi agent | Catat ke `LEARNINGS.md` (kategori: `correction`) |
| User minta fitur baru | Catat ke `FEATURE_REQUESTS.md` |
| API/tool eksternal gagal | Catat ke `ERRORS.md` dengan detail integrasi |
| Pengetahuan agent outdated | Catat ke `LEARNINGS.md` (kategori: `knowledge_gap`) |
| Ditemukan cara yang lebih baik | Catat ke `LEARNINGS.md` (kategori: `best_practice`) |
| Pelajaran bisa diterapkan luas | Promote ke `MEMORY.md` |
## Format Log
### Learning Entry
Append ke `skills/self-improving/data/LEARNINGS.md`:
```markdown
## [LRN-YYYYMMDD-XXX] category
**Logged**: ISO-8601 timestamp
**Priority**: low | medium | high | critical
**Status**: pending
### Summary
Satu baris ringkasan pelajaran
### Details
Konteks lengkap: apa yang terjadi, apa yang salah, apa yang benar
### Suggested Action
Fix atau improvement spesifik
### Metadata
- Source: conversation | error | user_feedback
- Related Files: path/to/file
- Tags: tag1, tag2
---
```
### Error Entry
Append ke `skills/self-improving/data/ERRORS.md`:
```markdown
## [ERR-YYYYMMDD-XXX] skill_or_command_name
**Logged**: ISO-8601 timestamp
**Priority**: high
**Status**: pending
### Summary
Ringkasan singkat apa yang gagal
### Error
```
Pesan error atau output aktual
```
### Context
- Command yang dijalankan
- Parameter yang dipakai
- Detail environment jika relevan
### Suggested Fix
Jika teridentifikasi, apa yang bisa memperbaiki ini
### Metadata
- Reproducible: yes | no | unknown
- Related Files: path/to/file
---
```
### Feature Request Entry
Append ke `skills/self-improving/data/FEATURE_REQUESTS.md`:
```markdown
## [FEAT-YYYYMMDD-XXX] capability_name
**Logged**: ISO-8601 timestamp
**Priority**: medium
**Status**: pending
### Requested Capability
Apa yang user ingin lakukan
### User Context
Kenapa mereka butuh ini, masalah apa yang ingin dipecahkan
### Suggested Implementation
Bagaimana ini bisa dibangun
### Metadata
- Frequency: first_time | recurring
---
```
## ID Format
Format: `TYPE-YYYYMMDD-XXX`
- TYPE: `LRN` (learning), `ERR` (error), `FEAT` (feature)
- YYYYMMDD: Tanggal saat ini
- XXX: Nomor urut (001, 002, dst)
## Resolve Entry
Saat issue sudah diperbaiki, update entry:
1. Ubah `**Status**: pending``**Status**: resolved`
2. Tambah blok resolusi:
```markdown
### Resolution
- **Resolved**: 2026-02-24T12:00:00Z
- **Notes**: Penjelasan singkat apa yang dilakukan
```
## Promote ke MEMORY.md
Saat pelajaran applicable secara luas (bukan one-off fix), promosikan ke `MEMORY.md`:
### Kapan Promote
- Pelajaran berlaku untuk banyak skill/fitur
- Pengetahuan penting yang harus diingat lintas sesi
- Mencegah kesalahan berulang
- Mendokumentasikan konvensi khusus user
### Cara Promote
1. **Ringkas** pelajaran jadi rule singkat
2. **Tambahkan** ke section yang tepat di `MEMORY.md`
3. **Update** entry original: ubah `**Status**``promoted`
### Contoh
**Learning entry (verbose):**
> PicoClaw exec tool memblokir pattern `${}` dan `> /dev/null`. Command cron harus ditulis sederhana tanpa shell metacharacters.
**Di MEMORY.md (ringkas):**
```markdown
## PicoClaw Safety Guard
- Exec tool memblokir: `${}`, `$()`, `> /dev/null`, `source *.sh`, `sudo`, `eval`
- Command cron harus ditulis sederhana: `bash scripts/file.sh "arg"`
```
## Recurring Pattern
Jika mencatat pelajaran yang mirip dengan entry yang sudah ada:
1. **Cari dulu**: apakah sudah ada entry serupa
2. **Link**: tambah `See Also: ERR-YYYYMMDD-XXX` di Metadata
3. **Naikkan priority** jika issue terus berulang
4. **Promote** jika sudah 3x berulang → masukkan ke `MEMORY.md`
## Periodic Review
Review `skills/self-improving/data/` di saat-saat natural:
- Sebelum mulai task besar baru
- Setelah menyelesaikan fitur
- Saat bekerja di area yang pernah ada masalah
- Mingguan selama development aktif
## Rules
1. **Log segera** — konteks paling segar tepat setelah masalah terjadi
2. **Spesifik** — agent di sesi berikutnya harus bisa memahami dengan cepat
3. **Sertakan langkah reproduksi** — terutama untuk error
4. **Sarankan fix konkret** — bukan sekadar "perlu investigasi"
5. **Promote agresif** — jika ragu, masukkan ke MEMORY.md
6. **Jangan log hal sepele** — hanya yang non-obvious dan bermanfaat
7. **Hindari menyimpan data sensitif** — jangan log API key, password, atau data pribadi

View file

@ -0,0 +1,5 @@
# Errors
Log command failures dan exceptions di sini.
---

View file

@ -0,0 +1,5 @@
# Feature Requests
Log permintaan fitur dari user di sini.
---

View file

@ -0,0 +1,5 @@
# Learnings
Log koreksi, knowledge gaps, dan best practices di sini.
---

View file

@ -0,0 +1,119 @@
---
name: system-monitor
description: Monitor kesehatan sistem — CPU, RAM, disk, suhu, dan uptime. Kirim alert via ntfy jika ada masalah.
metadata: {"nanobot":{"emoji":"📊"}}
---
# System Monitor
Monitor kesehatan STB/server: CPU, RAM, disk, suhu, dan uptime. Bisa dijalankan manual atau dijadwalkan via cron tool.
## When to use (trigger phrases)
- "cek sistem" / "system status"
- "health check" / "kesehatan server"
- "berapa suhu CPU?" / "CPU temperature"
- "disk penuh?" / "free disk space"
- "RAM usage" / "memory usage"
- "uptime" / "sudah jalan berapa lama?"
- "monitor sistem setiap jam"
## Perintah Manual
### Health check lengkap (via exec tool)
```bash
bash skills/system-monitor/scripts/health_check.sh
```
Output berupa ringkasan singkat yang mudah dibaca:
```
🖥️ SYSTEM HEALTH REPORT
========================
📅 2026-02-24 12:00 WIB
⏱️ Uptime: 3 days, 2:15
🔥 CPU Temp: 52°C ✅
💻 CPU Load: 0.85 (1 core)
🧠 RAM: 412MB / 1024MB (40%) ✅
💾 Disk: 4.2GB / 14.5GB (29%) ✅
🌐 Network: ✅ connected
========================
Status: ALL OK ✅
```
### Cek komponen spesifik (via exec tool)
```bash
bash skills/system-monitor/scripts/health_check.sh --cpu
bash skills/system-monitor/scripts/health_check.sh --memory
bash skills/system-monitor/scripts/health_check.sh --disk
bash skills/system-monitor/scripts/health_check.sh --temp
bash skills/system-monitor/scripts/health_check.sh --network
```
## Jadwal Otomatis (via cron tool)
### Health report harian pagi
```json
{"action": "add", "message": "📊 System Health Report", "command": "bash skills/system-monitor/scripts/health_check.sh", "cron_expr": "0 7 * * *"}
```
### Monitor suhu tiap 6 jam
```json
{"action": "add", "message": "🌡️ Temp check", "command": "bash skills/system-monitor/scripts/health_check.sh --temp", "every_seconds": 21600}
```
### Health check + ntfy alert (pakai reminder skill)
Jika ingin health report dikirim ke HP juga via ntfy, buat 2 job:
**Job 1 — Report ke Telegram:**
```json
{"action": "add", "message": "📊 Daily health", "command": "bash skills/system-monitor/scripts/health_check.sh", "cron_expr": "0 7 * * *"}
```
**Job 2 — Alert ke ntfy (hanya jika ada masalah):**
```json
{"action": "add", "message": "ntfy: health alert", "command": "bash skills/system-monitor/scripts/health_alert.sh", "every_seconds": 3600}
```
Script `health_alert.sh` hanya mengirim notifikasi jika ada warning/critical.
## Threshold (Default)
| Metrik | Warning | Critical |
|--------|---------|----------|
| CPU Temp | > 70°C | > 80°C |
| RAM Usage | > 80% | > 90% |
| Disk Usage | > 80% | > 90% |
| CPU Load (1-min) | > 2.0 | > 4.0 |
Threshold bisa dikustomisasi di `skills/system-monitor/data/config`.
## Custom Config
Buat `skills/system-monitor/data/config` jika ingin override default:
```bash
mkdir -p skills/system-monitor/data
cat > skills/system-monitor/data/config << 'ENDCONF'
TEMP_WARN=65
TEMP_CRIT=75
RAM_WARN=85
RAM_CRIT=95
DISK_WARN=85
DISK_CRIT=95
LOAD_WARN=3.0
LOAD_CRIT=5.0
ENDCONF
```
## Rules
1. **Prefer script** — selalu gunakan `health_check.sh`, jangan `top` atau `htop` (bisa hang).
2. **Jangan pakai `-f` flag** — streaming command tidak cocok untuk exec tool.
3. **Alert cukup summary** — jangan dump output panjang, cukup status singkat.
4. **Kombinasikan dengan ntfy** — gunakan `health_alert.sh` untuk push notification saat ada masalah.

View file

@ -0,0 +1,112 @@
#!/bin/bash
# health_alert.sh — Send ntfy alert ONLY if system has warning/critical issues
# Does nothing if everything is OK (silent success).
# Designed to be called from cron every hour.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
CONF_FILE="$SKILL_DIR/data/config"
# Defaults
TEMP_WARN=70
TEMP_CRIT=80
RAM_WARN=80
RAM_CRIT=90
DISK_WARN=80
DISK_CRIT=90
if [ -f "$CONF_FILE" ]; then
. "$CONF_FILE"
fi
# Detect issues
alerts=""
priority="default"
tags="computer"
# Check CPU temp
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
raw=$(cat /sys/class/thermal/thermal_zone0/temp)
temp=$((raw / 1000))
if [ "$temp" -ge "$TEMP_CRIT" ]; then
alerts="$alerts 🔥 CPU: ${temp}°C CRITICAL!"
priority="urgent"
tags="fire,$tags"
elif [ "$temp" -ge "$TEMP_WARN" ]; then
alerts="$alerts 🔥 CPU: ${temp}°C warning"
priority="high"
tags="warning,$tags"
fi
fi
# Check RAM
mem_info=$(free -m 2>/dev/null | grep Mem)
if [ -n "$mem_info" ]; then
total=$(echo "$mem_info" | awk '{print $2}')
used=$(echo "$mem_info" | awk '{print $3}')
if [ "$total" -gt 0 ]; then
pct=$((used * 100 / total))
if [ "$pct" -ge "$RAM_CRIT" ]; then
alerts="$alerts 🧠 RAM: ${pct}% CRITICAL!"
priority="urgent"
elif [ "$pct" -ge "$RAM_WARN" ]; then
alerts="$alerts 🧠 RAM: ${pct}% warning"
[ "$priority" = "default" ] && priority="high"
fi
fi
fi
# Check disk
disk_pct=$(df / 2>/dev/null | tail -1 | awk '{print $5}' | tr -d '%')
if [ -n "$disk_pct" ]; then
if [ "$disk_pct" -ge "$DISK_CRIT" ]; then
alerts="$alerts 💾 Disk: ${disk_pct}% CRITICAL!"
priority="urgent"
elif [ "$disk_pct" -ge "$DISK_WARN" ]; then
alerts="$alerts 💾 Disk: ${disk_pct}% warning"
[ "$priority" = "default" ] && priority="high"
fi
fi
# Check network
if ! ping -c 1 -W 3 8.8.8.8 > /dev/null 2>&1; then
alerts="$alerts 🌐 Network: disconnected!"
[ "$priority" = "default" ] && priority="high"
fi
# Exit silently if no issues
if [ -z "$alerts" ]; then
exit 0
fi
# Find ntfy config (check reminder skill's config)
NTFY_TOPIC=""
REMINDER_CONF="$SKILL_DIR/../reminder/data/ntfy.conf"
if [ -f "$REMINDER_CONF" ]; then
. "$REMINDER_CONF"
fi
# Also check own config
OWN_NTFY="$SKILL_DIR/data/ntfy.conf"
if [ -f "$OWN_NTFY" ]; then
. "$OWN_NTFY"
fi
if [ -z "$NTFY_TOPIC" ]; then
# No ntfy configured — just print to stdout (goes to Telegram via cron)
echo "⚠️ SYSTEM ALERT:$alerts"
exit 0
fi
# Send via ntfy
HOSTNAME_STR=$(hostname 2>/dev/null || echo "STB")
eval curl -sf \
-H "\"Title: System Alert - $HOSTNAME_STR\"" \
-H "\"Priority: $priority\"" \
-H "\"Tags: $tags\"" \
-d "\"$alerts\"" \
"\"$NTFY_TOPIC\"" || true
echo "⚠️ SYSTEM ALERT (sent to ntfy):$alerts"

View file

@ -0,0 +1,189 @@
#!/bin/bash
# health_check.sh — System health check for PicoClaw STB/server
# Usage:
# bash skills/system-monitor/scripts/health_check.sh # Full report
# bash skills/system-monitor/scripts/health_check.sh --cpu # CPU only
# bash skills/system-monitor/scripts/health_check.sh --memory # RAM only
# bash skills/system-monitor/scripts/health_check.sh --disk # Disk only
# bash skills/system-monitor/scripts/health_check.sh --temp # Temperature only
# bash skills/system-monitor/scripts/health_check.sh --network # Network only
set -euo pipefail
# Load config if exists
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
CONF_FILE="$SKILL_DIR/data/config"
# Defaults
TEMP_WARN=70
TEMP_CRIT=80
RAM_WARN=80
RAM_CRIT=90
DISK_WARN=80
DISK_CRIT=90
LOAD_WARN=2.0
LOAD_CRIT=4.0
if [ -f "$CONF_FILE" ]; then
. "$CONF_FILE"
fi
# Helper: status icon
status_icon() {
local val=$1 warn=$2 crit=$3
if [ "$(echo "$val >= $crit" | bc -l 2>/dev/null || echo 0)" = "1" ]; then
echo "🔴"
elif [ "$(echo "$val >= $warn" | bc -l 2>/dev/null || echo 0)" = "1" ]; then
echo "🟡"
else
echo "✅"
fi
}
# Components
get_uptime() {
uptime_str=$(uptime -p 2>/dev/null || uptime | sed 's/.*up /up /' | sed 's/,.*load.*//')
echo "$uptime_str"
}
get_cpu_temp() {
temp=""
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
raw=$(cat /sys/class/thermal/thermal_zone0/temp)
temp=$(echo "$raw / 1000" | bc 2>/dev/null || echo "$((raw / 1000))")
fi
if [ -z "$temp" ]; then
echo "N/A"
return
fi
icon=$(status_icon "$temp" "$TEMP_WARN" "$TEMP_CRIT")
echo "${temp}°C $icon"
}
get_cpu_load() {
load=$(cat /proc/loadavg 2>/dev/null | awk '{print $1}')
if [ -z "$load" ]; then
load=$(uptime | grep -oP 'load average: \K[^,]+' 2>/dev/null || echo "N/A")
fi
cores=$(nproc 2>/dev/null || echo 1)
if [ "$load" != "N/A" ]; then
icon=$(status_icon "$load" "$LOAD_WARN" "$LOAD_CRIT")
echo "$load ($cores core) $icon"
else
echo "N/A"
fi
}
get_memory() {
mem_info=$(free -m 2>/dev/null | grep Mem)
if [ -z "$mem_info" ]; then
echo "N/A"
return
fi
total=$(echo "$mem_info" | awk '{print $2}')
used=$(echo "$mem_info" | awk '{print $3}')
if [ "$total" -gt 0 ]; then
pct=$((used * 100 / total))
else
pct=0
fi
icon=$(status_icon "$pct" "$RAM_WARN" "$RAM_CRIT")
echo "${used}MB / ${total}MB (${pct}%) $icon"
}
get_disk() {
disk_info=$(df -h / 2>/dev/null | tail -1)
if [ -z "$disk_info" ]; then
echo "N/A"
return
fi
used=$(echo "$disk_info" | awk '{print $3}')
total=$(echo "$disk_info" | awk '{print $2}')
pct_raw=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
icon=$(status_icon "$pct_raw" "$DISK_WARN" "$DISK_CRIT")
echo "${used} / ${total} (${pct_raw}%) $icon"
}
get_network() {
if ping -c 1 -W 3 8.8.8.8 > /dev/null 2>&1; then
echo "✅ connected"
else
echo "🔴 disconnected"
fi
}
# Get overall status
get_overall_status() {
local has_warning=false has_critical=false
# Check temp
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
raw=$(cat /sys/class/thermal/thermal_zone0/temp)
temp=$((raw / 1000))
[ "$temp" -ge "$TEMP_CRIT" ] && has_critical=true
[ "$temp" -ge "$TEMP_WARN" ] && has_warning=true
fi
# Check RAM
mem_info=$(free -m 2>/dev/null | grep Mem)
if [ -n "$mem_info" ]; then
total=$(echo "$mem_info" | awk '{print $2}')
used=$(echo "$mem_info" | awk '{print $3}')
if [ "$total" -gt 0 ]; then
pct=$((used * 100 / total))
[ "$pct" -ge "$RAM_CRIT" ] && has_critical=true
[ "$pct" -ge "$RAM_WARN" ] && has_warning=true
fi
fi
# Check disk
disk_pct=$(df / 2>/dev/null | tail -1 | awk '{print $5}' | tr -d '%')
if [ -n "$disk_pct" ]; then
[ "$disk_pct" -ge "$DISK_CRIT" ] && has_critical=true
[ "$disk_pct" -ge "$DISK_WARN" ] && has_warning=true
fi
if [ "$has_critical" = true ]; then
echo "CRITICAL 🔴"
elif [ "$has_warning" = true ]; then
echo "WARNING 🟡"
else
echo "ALL OK ✅"
fi
}
# Main
MODE="${1:-full}"
DATE_STR=$(date '+%Y-%m-%d %H:%M %Z' 2>/dev/null || date)
case "$MODE" in
--cpu)
echo "💻 CPU Load: $(get_cpu_load)"
;;
--temp)
echo "🔥 CPU Temp: $(get_cpu_temp)"
;;
--memory)
echo "🧠 RAM: $(get_memory)"
;;
--disk)
echo "💾 Disk: $(get_disk)"
;;
--network)
echo "🌐 Network: $(get_network)"
;;
*)
echo "🖥️ SYSTEM HEALTH REPORT"
echo "========================"
echo "📅 $DATE_STR"
echo "⏱️ Uptime: $(get_uptime)"
echo "🔥 CPU Temp: $(get_cpu_temp)"
echo "💻 CPU Load: $(get_cpu_load)"
echo "🧠 RAM: $(get_memory)"
echo "💾 Disk: $(get_disk)"
echo "🌐 Network: $(get_network)"
echo "========================"
echo "Status: $(get_overall_status)"
;;
esac