This is a submission for the
There's also no usage dashboard. No app that tells you how fast you're burning through units or when you'll run out. The only way to check your balance is to walk to the meter and press 20# on the keypad. Most people don't bother until the power cuts.
On top of that, Kenya Power publishes a weekly PDF listing planned maintenance outages by area. If your neighborhood is on the list, you'll lose power for 8-10 hours on the scheduled day. These notices get posted on their website and sometimes shared on social media, but most people miss them entirely.
. Install it with clawhub install kplc-sentinel.
The agent is the brain, the scripts are the data layer. This is the core design decision. The Python entrypoint returns structured JSON, not formatted text. The agent reads the data, applies the Stima persona from SOUL.md, and composes a natural response. The skill never prints a user-facing message. It returns things like {"action": "balance", "runway_hours": 18.0, "estimate_source": "appliances", "tip": "avoid running the water heater"} and the agent turns that into "Stima yako iko na roughly 18 hours. That's tight — avoid running the water heater to stretch your units."
This matters because it means the personality, tone, and language all come from the agent, not hardcoded strings. The same JSON data could be presented differently depending on the SOUL.md persona, the user's language preference, or the chat platform.
Natural language in three languages. The SKILL.md routing table maps natural language to commands. Users can say "stima itaisha lini?" (Sheng), "nimebakisha units ngapi?" (Swahili), or "will my power last until Monday?" (English) and the agent routes all three to the balance check. No translation code in Python. The agent handles it because SKILL.md tells it how to map intent to commands.
Appliance-based estimates from day one. During onboarding, the skill asks what appliances you have. It maps each one to realistic consumption using a (wattage × typical hours per day) model. A fridge is 150W × 24h. A water heater is 3000W × 5 minutes. An iron is 1000W × 10 minutes. This means the skill can predict how long your tokens will last before you've ever taken a meter reading. As real readings come in, the actual burn rate takes over.
M-Pesa top-up instructions. When your balance is low, the agent doesn't just warn you. It tells you exactly how to buy more tokens: M-Pesa Paybill 888880, account number = your meter number, and asks you to forward the confirmation SMS back so it can track the purchase.
Budget tracking. Users set a monthly electricity budget (stima budget 3000). The skill tracks spending against it and warns at 80% and 100% thresholds.
Usage insights. The skill compares this week's consumption against last week and identifies which days of the week are heaviest. Turns raw data into something actionable.
PDF scraping for outage alerts. The skill downloads KPLC's Power Maintenance Notice PDF directly from their website, splits the two-column layout, and regex-parses all scheduled outages with areas, dates, and times. It then matches against the user's area. The PDF is cached for 1 hour to avoid hammering KPLC's server.
pdf_path = os.path.join(tempfile.gettempdir(), "kplc_schedule.pdf")
urllib.request.urlretrieve(KPLC_SCHEDULE_URL, pdf_path)
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
# Split two-column layout into left and right halves
left = page.crop((0, 0, page.width / 2, page.height)).extract_text()
right = page.crop((page.width / 2, 0, page.width, page.height)).extract_text()
# Regex-parse AREA, DATE, TIME from each column
for text in [left, right]:
for area, date, time in re.findall(
r'AREA:\s*(.+?)\n.*?DATE:\s*(.+?)\s*TIME:\s*(.+?)[\n\r]',
text, re.IGNORECASE
):
if user_area.lower() in area.lower():
alerts.append({"area": area, "date": date, "time": time})
Sheng personality via SOUL.md. The agent persona ("Stima") speaks casual English with Kenyan Sheng/Swahili flavor. But the personality lives in SOUL.md, not in the Python code. The scripts return data; the agent adds the flavor. This is how OpenClaw skills should work.
Local SQLite storage. All data stays on the user's machine. No cloud sync, no external API beyond the LLM provider. The database auto-initializes on first message with owner-only file permissions.
Security hardening. Parameterized SQL everywhere. User input via stdin heredoc (no shell injection). Profile values sanitized before display (no chat injection). DB error messages don't leak internals. Input length capped. Outbound requests locked to kplc.co.ke HTTPS only.
Demo
The Sheng personality makes a real difference. Early versions responded in plain English and felt like a utility. Adding "Sawa! Token imeingia" and "Stima yako iko na roughly 14 hours" made testers actually enjoy using it. But moving the personality from Python strings to SOUL.md was the right call. The agent should own the voice.
Local storage was the right call. Electricity usage data is personal, and Kenyan households shouldn't need to send consumption patterns to a cloud service to get a "you're running low" alert.
Security caught me early. The first version told the agent to run python3 entrypoint.py "<user message>", which meant shell metacharacters in a message could execute arbitrary commands. The fix was switching to stdin heredoc. User input never touches the shell interpreter.
ClawCon Michigan
No did not attend

SOCIAL SHARE CARD GENERATOR