Initial skills documentation — 25 categories, all SKILL.md + references + scripts
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# Sho'Nuff Inbox Monitoring
|
||||
|
||||
Goal: Monitor `shonuff@germainebrown.com` for incoming replies/emails, extract content, and notify Germaine via Telegram.
|
||||
|
||||
## Architecture
|
||||
|
||||
Two-layer system:
|
||||
|
||||
1. **Collector script** (`shonuff-inbox-collect.py`, `no_agent=True`) — runs every 15m, checks for UNSEEN messages from non-trusted senders, outputs JSON with: from, subject, date, body_preview (first 500 chars), uid. Silent when nothing new. Marks messages as Seen after processing.
|
||||
|
||||
2. **LLM cron job** — takes the collector's JSON output, summarizes each message in 2-3 sentences for Germaine: who sent it, what it's about, whether action is needed. Responds with SILENT when nothing new.
|
||||
|
||||
## Script location
|
||||
|
||||
`/root/.hermes/scripts/shonuff-inbox-collect.py`
|
||||
|
||||
## Trusted senders (skipped, not reported)
|
||||
|
||||
```python
|
||||
TRUSTED = ["g@germainebrown.com"]
|
||||
```
|
||||
|
||||
The collector skips messages FROM these addresses entirely — no output, no summary. All other senders are reported.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **Apple Mail replies are HTML-only** — they often send with no `text/plain` alternative. The `get_text_body()` function strips HTML tags to extract plain text, but this can miss content that's rendered only through CSS or loaded images.
|
||||
- **Body preview is truncated at 500 chars** — the LLM summary may need more context for long messages. The preview in the JSON output is an excerpt, not the full body.
|
||||
|
||||
## Body extraction
|
||||
|
||||
```python
|
||||
def get_text_body(msg):
|
||||
body = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
ct = part.get_content_type()
|
||||
if ct == "text/plain":
|
||||
payload = part.get_payload(decode=True)
|
||||
if payload:
|
||||
body += payload.decode("utf-8", errors="replace")
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
if payload:
|
||||
body = payload.decode("utf-8", errors="replace")
|
||||
body = re.sub(r'\s+', ' ', body).strip()
|
||||
return body[:2000]
|
||||
```
|
||||
|
||||
The fallback path (HTML-only) is handled by extracting `text/html` parts and stripping tags manually.
|
||||
|
||||
## Cron config
|
||||
|
||||
- Schedule: `every 15m`
|
||||
- `no_agent=True` on the collector
|
||||
- LLM cron reads output via `context_from` job ID
|
||||
- If nothing changed from last run, the LLM responds SILENT and the user sees nothing
|
||||
|
||||
## Setup checklist
|
||||
|
||||
- [x] IMAP credentials in `.env` (`SHONUFF_EMAIL`, `SHONUFF_EMAIL_PASS`)
|
||||
- [x] Collector script at `~/scripts/shonuff-inbox-collect.py`
|
||||
- [x] `no_agent=True` cron at 15m
|
||||
- [x] LLM cron reading collector's output
|
||||
- [x] Trusted senders configured
|
||||
- [x] Base64 image for signature stored at `~/references/shonuff-image-b64.txt`
|
||||
Reference in New Issue
Block a user