homebase
Family household coordinator: calendar, briefings, kids' meals, school email, groceries, health log, receipts. Every tool goes through tools.py — read this before calling one.
Harsh Chawla
@hchawla
What This Skill Does
Family household coordinator that aggregates Google Calendar, Gmail, and config-driven data to run a daily morning briefing, manage meal plans and grocery lists, track health doses, and monitor school emails. All family-specific settings live in a single config file.
Replaces juggling multiple separate calendars, notes, and reminders by unifying the morning routine, meal planning, school inbox, and health tracking into one automated system.
When to Use It
- Get a daily morning briefing with weather, schedule, kids meals, and school snacks
- Plan a weekly family meal with Saturday draft and Sunday auto-lock approval cycle
- Track Tylenol or ibuprofen doses per kid with weight-based safety limits
- Monitor school Gmail for flyers and PDF attachments every two hours
- Log restaurant visits and ratings from receipt photos sent via WhatsApp
- Manage per-store grocery lists for Costco, Indian grocery, and Target
Install
$ openclaw skills install @hchawla/homebaseHomebase
A household data layer for a family: the calendar, the morning and evening
briefings, the kids' meals, the grocery list, the school inbox, medication and
receipts — one place, configured per family in config.json, no code per
family.
Python returns data. The caller composes and sends. Nothing in this skill formats a message, delivers one, calls an LLM, or schedules anything. That division is the whole architecture: the agent (or a scheduler you write) reads these tools and decides what to say.
Calling a tool
python3 {baseDir}/tools.py <tool_name> '<json_args>'
- Always give
tools.pyan absolute path, and nevercdfirst. This is the one shell habit that predicts failure:cd-then-relative-path calls fail at 20% against a 1.6% baseline, because the working directory the exec host hands you is not the one you assumed. - One tool per exec call. Chaining with
&&/||is a smaller but real risk (4.9% vs 1.6%): the second command runs against state you have not read, and a failure in the first is easy to miss. ~,$(...)and pipes are fine — measured within noise of baseline. Don't contort a command to avoid them.- Tools taking no arguments need no third argument;
'{}'is equivalent. - A non-zero exit is a failure even when there is no
❌— the command broke before the tool ran. Say so; never treat it as "nothing to report". The reverse also holds: most❌returns exit 0, so judge by the output.
If any value contains an apostrophe, use the stdin form. A ' inside the
single-quoted argument closes it and the shell dies before Python runs — you
get unmatched ", not a ❌. Backslash-escaping does not work inside single
quotes. Pass - as the argument and heredoc the JSON:
python3 {baseDir}/tools.py log_restaurant_visit - <<'JSON'
{"restaurant":"Romy's","meal_type":"lunch","date":"2026-06-12","total":42.50}
JSON
Use the stdin form whenever a value holds ', emoji, newlines, or text you
extracted from an email, a photo or a message — anything you did not author.
The quoted <<'JSON' matters: it stops the shell expanding $ and backticks.
Non-agent callers use the shim: {baseDir}/bin/homebase.sh <tool> '<json>'.
It pins the interpreter to homebase's venv. Prefer it in any script or
scheduler — tools.py can re-exec itself under the venv, but only when the
calling interpreter both lacks pypdf and resolves to a different binary than
.venv/bin/python, which is not true of a Homebrew python3.12.
Finding a tool
tools.py list prints all 48 tool names. An unknown name returns a
Did you mean: suggestion rather than a silent failure. Use it instead of
guessing a name — invented names like check_school_emails are a known way to
burn a turn.
Tool surface
All 48 tools. W marks a tool that writes state. Exact arguments for every
one are in {baseDir}/references/agent.md.
Briefings, weather, travel
| Tool | Does |
|---|---|
get_morning_briefing W | The whole morning payload: date, weather, events, snack, travel, warnings. Syncs the calendar and updates the 60-day reliability tracker. |
get_evening_prep W | Tomorrow's events and the kids' locked meals, for the "so do this tonight" message. Syncs the calendar. |
get_weather | Today's raw forecast. |
get_weather_context | Hourly forecast across a window (default 08–17) plus US AQI. |
get_travel_status | Is the household away on a date, and where. {"sync":true} forces a calendar refresh first (W). |
get_message_targets | The configured owner, family group, alert webhook and calendar_id — use this id for any gog calendar call, never gog's default. |
Kids' meals and the weekly plan
| Tool | Does |
|---|---|
get_kids_meals | The locked plan's breakfast/lunch/side per kid for a date. |
get_meal_suggestions | Today's pre-picked suggestion per kid, when no plan is locked. |
log_kids_meal W | Record one food, for one kid, in one slot. |
get_meal_history | Recent meal log. |
get_weekly_meal_pool | The per-day, per-kid, per-slot menu pool. |
get_morning_meal_checkin_text | The canonical "what did the kids eat?" question. |
draft_meal_plan | A starting-point draft. |
save_meal_plan W | Validate and stage a plan. Rejects meals outside the catalog. |
get_pending_meal_plan | The staged draft awaiting a reply. |
handle_meal_plan_response W | Approve and lock, or revise. Max 2 revisions, then auto-locks. |
approve_meal_plan W | Approve with no changes. |
get_pending_catalog_reviews | Off-catalog meals awaiting approval. |
apply_catalog_review W | Accept or reject them into the learned catalog. |
School: snacks, email queue, proposed events
| Tool | Does |
|---|---|
get_school_roster | School name and the kids with their teachers. |
get_snack_schedule | The stored snack schedule for the month. |
save_snack_schedule W | Save a month of snack duty. Refuses a write that looks like the same photo read twice; "force":true overrides. |
fetch_school_emails W | A queue, not a mail reader — see below. |
mark_email_synced W | Advance the queue. Call after acting, never before. |
save_pending_school_events W | Stage events extracted from an email for the family to approve. |
get_pending_school_events W | The approval queue (purges entries older than 3 days on read). |
confirm_pending_school_events W | Create the approved events on Google Calendar. The only calendar write homebase still makes. |
reject_pending_school_events W | Drop them without creating anything. |
Groceries and restaurants
| Tool | Does |
|---|---|
get_grocery_list | The list, optionally for one store. |
add_to_grocery_list W | Add items to a store bucket. |
remove_from_grocery_list W | Remove by name match. |
log_restaurant_visit W | Record a visit. Merges on (date, restaurant). |
rate_restaurant W | Attach a rating and notes, per person. |
get_restaurant_recommendations | Suggestions, optionally by meal type. |
get_top_restaurants | Highest-rated places. |
Health — advisory, not a gate. Every dose is logged; warnings never block.
| Tool | Does |
|---|---|
log_medication W | Log a dose. Warns on weight-based range, minimum interval and the 24h count. |
log_fever W | Log a temperature, or a subjective fever. |
log_symptom W | Log symptoms. |
get_health_summary | A doctor-friendly summary over N days. |
update_child_weight W | Update a weight. A child with no weight gets no dose-range checking at all. |
schedule_medication_reminder W | Note a follow-up dose time. |
Kid profiles and trips
| Tool | Does |
|---|---|
log_kid_observation W | Append an observation to a child's profile. |
get_kid_profile | Weight, observations, preferences. |
get_trip_data | Destination forecast, environment tags, per-kid prep notes. |
get_trip_prep | Legacy text form of the same. |
mark_trip_prep_sent W | Record that prep went out, so it doesn't repeat. |
Bills — only when bills.enabled is true in config.json.
| Tool | Does |
|---|---|
fetch_bill_emails W | At most one bill per call, with its PDF text extracted. Marks nothing. |
mark_bill_processed W | The second half: fetch → deliver → then mark. |
Two of these are queues, not mail readers
fetch_school_emails and fetch_bill_emails exist to feed a scheduled caller.
They filter aggressively, return at most a narrow slice, and hand back a bare
[] on several different drop paths. Never call either to answer a person
asking about their mail — gog gmail messages search "<q>" --max 5 --json
does that in one call.
Both are half of a two-phase contract: they return work unmarked, and the caller marks it only after the message actually went out. Marking first is how an email gets consumed by a send that failed.
Rules that are not guessable
- Route every household action through
tools.py. Never usewrite/editto save household data. - One call per kid per meal slot. Never compound foods into one call.
- Only claim a tool succeeded if you have seen its confirmation string this
turn. If it returns an error starting with
❌, surface that verbatim. - After any state-changing call, reply with a one-line summary. An empty turn after a flurry of tool calls is a known failure mode.
- homebase has no calendar tools. It keeps a read-only sync of the family
calendar for the briefings and travel mode; Google is the
gogskill's. Read and write the calendar withgogdirectly. - If you run a feature script directly (only those with a
__main__block), use.venv/bin/python3. Barepython3resolves to an interpreter without this skill's packages. Measured:.venv/bin/python3132 calls / 0 failures, barepython312 calls / 9 failures.features/meals/meal_tracker.pyis a library with no__main__— never run it directly. - The skill is
homebase. There is nofamily-calendar-aggregator.
Incoming images: act, don't describe
Read the photo with the view_image tool (path as a string, not a list), infer
the action from context and document type — snack calendar → save_snack_schedule,
receipt → log_restaurant_visit, itinerary → a calendar write through gog —
then take it. Never end the turn having only extracted the content.
- Give the
view_imagecall a target. Ask it for the fields the tool you are about to call needs. A bare "what is this and what should be done?" gets answered from the sender's point of view — a restaurant bill came back as "process a payment from the customer", which is advice for the restaurant. - There is no "personal" exemption. One adult's dinner receipt is household data. Classifying a photo as personal and asking what to do with it is the same failure as describing it.
- Each photo lands in its own
openclaw-staged-<uuid>/directory. Two images sent minutes apart do not share one. To re-read an earlier photo, take its path from that photo's own earlierview_imagecall in this transcript — do not reuse the most recent path, and do notlsone staged directory and conclude it is the only image.view_imageanswers the prompt it is given: asked for "the morning snack schedule" while pointed at the afternoon calendar, it will return afternoon items under a "Morning" heading.
log_restaurant_visit merges on (date, restaurant), so a receipt for a meal
the evening sync already auto-logged enriches that record rather than creating a
second one. Log it; do not check first.
Travel: put the trip on the calendar
When the family says they are travelling — "we're in Seattle next week", "I'm
away the 3rd to the 7th", a forwarded itinerary — that means one calendar write.
Create it with gog, using the calendar_id from get_message_targets:
gog calendar create <calendar-id> --summary "Trip to Seattle" \
--from 2026-08-29 --to 2026-09-07 --all-day \
--location "Seattle, WA" --json --no-input
Google's all-day end date is exclusive: a trip whose last night away is
Sep 6 is written --to 2026-09-07.
Three properties are load-bearing — do not improvise them:
- All-day, spanning every night away.
get_travel_statusreads only all-day events, because a timed one is something that happens during a day rather than a statement about where the household is sleeping. Booking the flight is not enough: "Flight UA2316 LAX to SEA" is timed and changes nothing. - A title the matcher recognises —
Trip to X,Travel to X(alsoTravelling/Traveling),X trip,Vacation in/to/at X, bareVacation,Out of town, orIn X (trip). Anything else silently does nothing. ⚠️X tripmatches any word before "trip", so an all-dayField tripon the family calendar will read as the household being away. Title school outings something else. --locationas a geocodable place — "Seattle, WA", not a nickname. It is what the forecast is fetched for.
Say what you created and over which dates. This event is why the briefings follow the family, so a wrong range is a week of wrong weather. Telling you is not enough: a scheduled briefing never talks to the agent, and the calendar is the only thing you both read.
What homebase does not do
- Never composes or sends a message. No WhatsApp, no email, no LLM call.
- Never schedules anything. No cron, no timers. Drive it from your own
scheduler through
bin/homebase.sh. - Holds no credentials.
gogowns the Google OAuth token and mints an access token per invocation.core/gcal.pyandcore/gmail.pyare the only modules that reach Google, and both do it by exec'inggog. - Never reads OpenClaw's own state — no session store, no cron tables.
Requirements and setup
- Python 3.12+ and a populated
.venv(the most common install failure). - The
gogCLI, authenticated for Gmail + Calendar. It is a binary dependency; pip cannot install it.
cp config.example.json config.json && chmod 600 config.json # then fill it in
gog auth add <your-google-account> --services gmail,calendar
pip install -e .
python -m pytest # 587 tests
python setup_check.py # config + gog auth + live calendar sanity check
config.json is the only file holding anything private — group ids, phone
numbers, kid names, the calendar id, school addresses. Keep it chmod 600;
setup_check.py verifies that. Tests never read it: they run against their own
fixture via HOMEBASE_CONFIG.
State and privacy
All household state is local JSON under household/ and calendar_data/,
written atomically (tempfile + fsync + rename) so a crash mid-write cannot
leave corrupt JSON. Files land at mode 600.
Outbound network, the complete list:
- Google Gmail + Calendar, reached indirectly — homebase execs
gog, andgogmakes the HTTPS call. No Google traffic starts in this skill's process. - Open-Meteo, keyless and account-less, no PII sent:
api.open-meteo.com(forecasts),geocoding-api.open-meteo.com(destination → coordinates),air-quality-api.open-meteo.com(AQI). zenquotes.iofor the briefing's thought of the day. No key; on any failure it falls back to a local pool.
No telemetry, no analytics, no third-party tracking. Nothing else is contacted.
Limitations
- Google access requires
gog, which stores its refresh token in the macOS Keychain. Elsewhere it depends on whatever keyring backend gog finds;gog auth statusreports which. - The calendar sync merges every
supported_calendarsentry withenabled: true. Disabling an entry also evicts its cached events. - Health warnings are advisory. Nothing refuses a dose.
Troubleshooting
- Briefing missing weather — Open-Meteo rate limit. The 60-day reliability
tracker in
household/briefing_reliability.jsonflags the daydegraded. - Gmail or Calendar auth error — check
gog auth status, re-authorize withgog auth add <account> --services gmail,calendar. The school email monitor alerts once on an auth failure, then goes silent until fixed. - JSON file corrupt — atomic writes prevent this normally. If it happens (e.g. disk full), delete the file and the loader recreates an empty one.
Reference
{baseDir}/references/agent.md— exact arguments for all 48 tools.{baseDir}/README.md— installation and configuration.{baseDir}/CHANGELOG.md— what changed, and when.
License
MIT
Top skills in this category
gmail
@byungkyuGmail API integration with managed OAuth. Read, send, and manage emails, threads, labels, and drafts. Use this skill when users want to interact with Gmail. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Calls run through the `maton` CLI with OAuth login, or over raw HTTP with a Maton API key where the CLI cannot be installed. Every call is authenticated as the user's connection and reaches only what that connection's authorization allows, which the provider enforces on every request; the endpoints documented here are the ones this skill uses, and any other endpoint of this app needs the user to ask for it by name. Default to read and list calls, and confirm every write or new connection with the user. This file also documents the three constructs that turn a Gmail connection into automation, in the order they are used: the connection (the first step), a hosted function that runs a Gmail action through the Maton SDK, and a trigger that calls that function on a schedule or on an event. Those sections are the platform's own reference text, shared with the api-gateway skill, with Gmail examples; they add no Gmail capability - Gmail is itself an event source, so its own events are in `references/google-mail/triggers.md`, and the files under `references/<source>/triggers.md` are the platform's event catalogues for the sources Maton offers (time, Calendly, GitHub, Gmail, HubSpot, Linear, Notion, Slack, Stripe).
WhatsApp Business
@byungkyuWhatsApp Business API integration with managed OAuth. Send messages, manage templates, and handle conversations. Use this skill when users want to interact with WhatsApp Business. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Calls run through the `maton` CLI with OAuth login, or over raw HTTP with a Maton API key where the CLI cannot be installed. Every call is authenticated as the user's connection and reaches only what that connection's authorization allows, which the provider enforces on every request; the endpoints documented here are the ones this skill uses, and any other endpoint of this app needs the user to ask for it by name. Default to read and list calls, and confirm every write or new connection with the user. This file also documents the three constructs that turn a WhatsApp Business connection into automation, in the order they are used: the connection (the first step), a hosted function that runs a WhatsApp Business action through the Maton SDK, and a trigger that calls that function on a schedule or on an event. Those sections are the platform's own reference text, shared with the api-gateway skill, with WhatsApp Business examples; they add no WhatsApp Business capability - WhatsApp Business is not an event source, a trigger cannot read WhatsApp Business data, and the files under `references/<source>/triggers.md` are the platform's event catalogues for the sources Maton offers (time, Calendly, GitHub, Gmail, HubSpot, Linear, Notion, Slack, Stripe).
WeChat MP CN
@guohongbin-git微信公众号监控 - 文章监控、阅读量追踪、舆情分析(WeChat Official Account)
Wechat Article Search
@wuchubuzai2018搜索微信公众号文章技能。通过微信搜索获取文章列表,覆盖科技/AI、社会热点、财经、教育、职场等各类中文资讯;可按关键词检索并返回标题、概要、发布时间、来源公众号与链接。当用户需要查找微信公众号文章、整理参考资料或快速获取文章信息时使用此技能。
Wechat Publisher
@0731coderlee-sudo一键发布 Markdown 到微信公众号草稿箱。基于 wenyan-cli,支持多主题、代码高亮、图片自动上传。