← Back to Plugins
Tools

Spratt Skills

kmanan By kmanan 👁 56 views ▲ 0 votes

Custom build addons for OpenClaw with skill md

Homepage GitHub

README

![image (2) (Small)](https://github.com/user-attachments/assets/1c4afea6-c572-48ff-9bbd-d1a3768f3fe1)

# Spratt Skills โ€” Household Automation Add-ons for OpenClaw

A collection of infrastructure add-ons for [OpenClaw](https://github.com/openclaw/openclaw) that turn it into a household operating system. Built for a real family, running in production on a Mac Mini M4.

These aren't typical OpenClaw skills (SKILL.md files that teach the LLM what to do). They're **infrastructure** โ€” daemons, databases, pipelines, and automation that run alongside OpenClaw, handling the things an LLM shouldn't be trusted to do reliably.

## The Core Idea: LLM Plans, Code Delivers

Every component follows the same principle: the LLM decides what to do, deterministic code executes it. No LLM is involved at message delivery time, flight polling time, or database write time. The LLM's job is language and reasoning. Code handles reliability.

---

## Components

### 1. [Outbox](./outbox/) โ€” Scheduled Message Delivery

A SQLite message queue with a polling daemon. The LLM writes messages to a table with a scheduled send time. A Python daemon delivers them via iMessage (BlueBubbles). No LLM at delivery time.

**Why it exists:** OpenClaw crons re-invoke the LLM at delivery time. The LLM reinterpreted instructions differently each run โ€” trip dinners went as individual DMs instead of group chat, a flight monitor ran 22 polls and delivered zero notifications. The outbox pattern eliminates this failure mode entirely.

| | |
|---|---|
| **What you get** | outbox.py (CLI + Python API), sender.py (daemon), SQLite schema |
| **Dependencies** | Python 3, SQLite, iMessage via [BlueBubbles](https://bluebubbles.app/) + imsg CLI |
| **macOS-specific** | launchd plist for the daemon (KeepAlive). Adaptable to systemd. |
| **Setup time** | ~15 minutes |

### 2. [Trip Manager](./trip-manager/) โ€” Database-First Trip Automation

The LLM writes trip data directly to SQLite through a CLI (`trip-db.py add-flight`, `add-hotel`, etc.). Outbox messages are auto-generated for flight reminders, hotel check-ins, and dinner notifications. Flight monitor state is auto-derived. Update any record, regenerate downstream โ€” only the changed items, no full regeneration.

**Why it exists:** Family travel has dozens of moving parts โ€” flights, hotels, restaurants, Uber links, group chat notifications โ€” spread across confirmation emails and text threads. Without structure, details get lost and nobody gets reminded. The trip manager gives the LLM a single database to write to, and deterministic scripts handle all the downstream notification scheduling and flight tracking setup.

| | |
|---|---|
| **What you get** | trip-db.py (CLI with 11 subcommands), trip-outbox-gen.py, trip-status.py, trip-flight-state.py, SQLite schema (5 tables) |
| **Dependencies** | Python 3, SQLite, Outbox (above) |
| **macOS-specific** | No (all scripts are standalone CLI tools) |
| **Setup time** | ~15 minutes (after Outbox is set up) |

### 3. [Flight Monitor](./flight-monitor/) โ€” Real-Time Flight Tracking Daemon

A persistent daemon that polls FlightAware AeroAPI, detects events (landing, delay, gate change, diversion), and sends notifications through the outbox. Adaptive polling โ€” 3 minutes during active window, 30 minutes when idle. No LLM in the polling loop.

**Why it exists:** An LLM-mediated flight cron used browser scraping, couldn't interpret "not found," and self-deleted after "completing" with zero notifications sent. The original implementation used `FlightRadarAPI` โ€” a community scraper of FlightRadar24's public data, not an official API โ€” which returned inconsistent results for valid flights. Migrated to FlightAware AeroAPI for stable, authenticated access.

| | |
|---|---|
| **What you get** | flight_monitor.py, track_flight.py, state derivation from trips DB |
| **Dependencies** | Python 3, FlightAware AeroAPI key (~$5/mo), Outbox (above) |
| **macOS-specific** | launchd plist (KeepAlive + PathState). Adaptable to systemd. |
| **Setup time** | ~15 minutes (after Outbox is set up) |

### 4. [Email-to-Orders](./email-to-orders/) โ€” Automatic Order Tracking from Email

An email scanning cron extracts grocery/shopping order details from email confirmations and inserts them into SQLite. Supports Instacart, Amazon Fresh, Whole Foods, DoorDash, and more. No manual entry โ€” orders are ingested automatically from email.

**Why it exists:** "Did we already buy cilantro this week?" is a real question in a household. The orders database makes it queryable.

| | |
|---|---|
| **What you get** | order-ingest.py (CLI), SQLite schema, email scan cron prompt template |
| **Dependencies** | Python 3, SQLite, an email scanning setup (Gmail via gog CLI, Outlook via Microsoft Graph, or any IMAP) |
| **macOS-specific** | No |
| **Setup time** | ~10 minutes |

### 5. [Outlook Graph](./outlook-graph/) โ€” Outlook Email & Calendar via Microsoft Graph

Shell scripts for managing Outlook/Hotmail email and calendar through Microsoft Graph API. Multi-account OAuth2 with auto-refreshing tokens. Calendar events support descriptions, attendees, and multi-calendar targeting โ€” create a family appointment on the "For Family" calendar with attendees and notes in one command.

**Why it exists:** The ClawHub outlook-plus skill only had basic event CRUD โ€” no description/body field, no attendees, no multi-calendar targeting. For a household assistant that needs to create shared calendar events with notes ("doctor appointment โ€” symptoms to discuss: ...") and invite family members, those are table-stakes features.

| | |
|---|---|
| **What you get** | outlook-calendar.sh, outlook-mail.sh, outlook-setup.sh, outlook-token.sh |
| **Dependencies** | bash, curl, jq. Azure CLI for initial setup only. |
| **macOS-specific** | No |
| **Setup time** | ~10 minutes |

### 6. [Places](./places/) โ€” Save & Search Restaurants, Activities, Attractions

A SQLite database for places you want to remember โ€” restaurants, bars, activities, attractions. Share an Instagram post, Google Maps link, Yelp page, or just say "remember that Thai place on Queen West" and it gets saved with category, cuisine, location, tags, and notes. Query by vibe ("date night spots"), location, cuisine, or who saved it. Track visits and ratings.

**Why it exists:** Interesting places come from Instagram stories, friend recommendations, and articles โ€” then get forgotten. This gives the LLM a structured place to save them and a way to surface them when you ask "where should we go for dinner?"

| | |
|---|---|
| **What you get** | SKILL.md (OpenClaw skill definition), SQLite schema, setup script |
| **Dependencies** | SQLite, OpenClaw browser tool (for Instagram/Facebook/TikTok URL extraction) |
| **macOS-specific** | No |
| **Setup time** | ~5 minutes |

### 7. [Card Perks](./card-perks/) โ€” Credit Card Benefits Tracker

Tracks "use it or lose it" credit card benefits โ€” monthly credits, quarterly categories, semi-annual windows. A weekly cron checks what's expiring soon and notifies each cardholder via outbox + Apple Reminders. A monthly LLM-powered refresh searches the web for benefit changes so the database stays current without manual maintenance.

**Why it exists:** AMEX Platinum alone has 7+ expiring credits across monthly, semi-annual, and annual cycles. Nobody remembers them all. Spratt does.

| | |
|---|---|
| **What you get** | card-perks-check.py (weekly cron), card-perks-refresh.py (monthly helper), SQLite schema (4 tables), SKILL.md for interactive acknowledgment |
| **Dependencies** | Python 3, SQLite, Outbox (above), Apple Reminders via remindctl, Claude Haiku API (for monthly refresh, ~$0.03/mo) |
| **macOS-specific** | Apple Reminders via remindctl (optional โ€” remove reminder creation for Linux) |
| **Setup time** | ~10 minutes (after Outbox is set up) |

---

## Architecture

```
Human โ†’ LLM โ†’ trip-db.py CLI (add-trip, add-flight, add-hotel, etc.)
                    โ†“
              trips.sqlite (trips, flights, hotels, reservations, travelers)
                    โ†“
              trip-outbox-gen.py (deterministic templates)
                    โ†“
              outbox.sqlite (scheduled messages)
                    โ†“
              sender.py daemon (60s polling) โ†’ imsg CLI โ†’ iMessage

              trip-flight-state.py โ†’ state.json
                    โ†“
              flight_monitor.py daemon (3 min polling) โ†’ FlightAware AeroAPI
                    โ†“ (on events)
              outbox.sqlite โ†’ sender.py โ†’ iMessage

Human โ†’ LLM โ†’ places.sqlite (save place from URL or description)
              LLM โ† places.sqlite (query: "date night spots we haven't tried")

Email โ†’ email scan cron (Flash triage โ†’ extract)
                    โ†“
              order-ingest.py โ†’ orders.sqlite
              trip-db.py โ†’ trips.sqlite
              outlook-calendar.sh โ†’ Outlook calendar (with attendees + notes)

Saturday cron โ†’ card-perks-check.py (deterministic)
                    โ†“
              cards.sqlite (benefits, usage tracking)
                    โ†“
              outbox.sqlite + Apple Reminders (if expiring within 10 days)

Monthly cron โ†’ card-perks-refresh.py dump โ†’ Haiku (web search + diff)
                    โ†“
              cards.sqlite (benefit updates) โ†’ outbox notification if changed
```

---

## Prerequisites

- macOS (for launchd and iMessage via BlueBubbles) โ€” Linux adaptable with systemd + alternative messaging
- Python 3.9+
- SQLite 3
- [OpenClaw](https://github.com/openclaw/openclaw) installed and running
- [BlueBubbles](https://bluebubbles.app/) + imsg CLI for iMessage delivery (or adapt sender.py for your messaging platform)

---

## Quick Start

```bash
# Clone
git clone https://github.com/kmanan/spratt-skills.git
cd spratt-skills

# Set up environment
cp shared/env/env.example.sh shared/env/env.sh
# Edit env.sh with your API keys

# 1. Start with the Outbox (everything depends on it)
cd outbox
cat schemas/outbox.sql | sqlite3 outbox.sqlite
# Edit the sender.py IMSG

... (truncated)
tools

Comments

Sign in to leave a comment

Loading comments...