Data Plane vs Control Plane: The Architecture That Actually Worked
When I separated Life Hub (data collection, storage, scoring) from OpenClaw (action, orchestration, communication), everything clicked. Here is the architecture, the webhook pipeline, and what I learned about making personal data meaningful.
The single best architectural decision I made in Life Hub was not building it. It was separating what Life Hub does from what acts on it.
Life Hub is the data plane: it collects, stores, analyzes, and scores. OpenClaw is the control plane: it acts, communicates, and orchestrates. The two systems talk through webhooks and MCP tools, and the boundary between them is the cleanest line in either codebase.
The W10 Architecture
I call this the W10 Intelligence Integration, named after the work session where it came together. The core principle:
- Life Hub computes your state: pillar scores, baselines, burnout risk, streak health, anomaly detection. It knows what is happening.
- OpenClaw decides what to do about it: create tasks, send messages, adjust agent schedules, deliver briefings. It knows what to do next.
Neither system tries to do the other system's job. Life Hub does not send notifications. OpenClaw does not compute pillar scores. They meet at the API boundary and stay in their lanes.
The Webhook Pipeline
Life Hub fires six event types via fire-and-forget HTTP POST to registered targets:
EVENT_TYPES = {
"trigger_fired", # Advisor trigger condition met
"anomaly_detected", # Statistical anomaly in metrics
"burnout_risk_change", # Burnout risk level changed
"pillar_alert", # Pillar score crossed threshold
"streak_at_risk", # Active streak about to break
"collector_complete", # Data collection cycle finished
}Targets are configured via a JSON environment variable. Currently the only target is OpenClaw Mission Control at http://life-hub.life-hub.svc.cluster.local:80/mcp/. Internal Kubernetes DNS, no public exposure.
When a webhook lands at Mission Control's /api/triggers endpoint, it gets classified by severity:
- P1 (Immediate): Auto-creates an urgent task for Henry and triggers a Telegram notification within seconds. Examples: burnout risk going to "high", a critical pillar dropping below 3.0.
- P2 (Next heartbeat): Queued for Henry's next processing cycle (every 30 minutes). Examples: streak about to break, pillar alert on a secondary metric.
- P3 (Batch): Accumulated and included in the next daily briefing. Examples: collector completions, minor anomalies, informational triggers.
The severity classification is not hard-coded per event type. Mission Control evaluates the payload: a burnout risk change from "none" to "moderate" is P2, but "moderate" to "high" is P1. Context determines urgency.
The MCP Bridge
Webhooks handle push notifications: Life Hub telling OpenClaw something happened. But Henry also needs to pull data. That is where MCP comes in.
Life Hub exposes 240 MCP tools over Streamable HTTP. When Henry runs his morning briefing cron job, he calls tools like:
get_life_wheel → Current pillar scores and trends
get_personal_baselines → 30-day rolling averages
get_wellness_score → Composite wellness metric
get_mood_history → Recent mood patterns
get_activity_streaks → Active and at-risk streaks
get_calendar_intelligence → Today's meeting load
get_interests → Personal activity preferencesHenry synthesizes these into a Telegram message that lands at 7 AM. He knows my pillar scores, whether I slept well, what is on my calendar, and what activities I enjoy. He does not compute any of this himself. He reads from the data plane.
Teaching AI What You Actually Enjoy
One of the more interesting additions was the interest discovery system. Life Hub stores 40 personal interests across four categories (activities, social, aspirations, family), each with metadata like energy level, social context, and personal notes.
The discovery engine uses these existing interests to suggest new ones. If I have Tennis in my activities, it suggests padel and badminton as related options. If my Play pillar score drops, it suggests high-energy activities from my interests list. If my son reaches certain age milestones, it suggests age-appropriate family activities.
These suggestions surface in two places: the Life Wheel expanded cards ("Try Something New" section per pillar) and the Today page discover widget. Henry also has access via the suggest_new_interests MCP tool, so he can weave them into morning briefings: "Your Play pillar dropped 1.1 points this week. You mentioned wanting to try padel. The weather is good for outdoor activities today."
Making Data Personally Meaningful
Generic health apps tell you "you slept 7.2 hours" and compare you to a population average. That is useless. Seven hours might be great for you or terrible. The number alone does not tell you.
Life Hub computes 30-day rolling baselines per metric: mean, standard deviation, percentiles, and trend direction. When you expand a pillar card on the Life Wheel, each sub-score has a small arrow indicator:
- Green ↑: Above your personal mean + 1 standard deviation. You are doing notably better than your normal.
- Red ↓: Below your mean - 1 standard deviation. Something is off.
- Gray —: Within your normal range. No action needed.
Hover over the arrow and you see "30d avg: 7.2". The context is your context.
The Environment pillar goes further. When you expand it, a weather context section shows current conditions pulled from the weather intelligence module: "Overcast, 54°F, 12.5h daylight, Good for outdoors." This is not decoration: it directly explains why the temperature_comfort sub-score is 3.4/10 (it is cold) while daylight_quality is 7.7/10 (spring is bringing longer days).
The Lesson
The data architecture took months to build and it is the part I never have to apologize for. Every feature I add (baselines, interest discovery, weather context, webhook events) plugs into a coherent data model. The 51 ORM models relate to each other in ways that support queries I did not anticipate when I wrote them.
The UI is the part that grew without a plan. I can compute your burnout risk with statistical rigor, but the page that shows it to you looks different from every other page in the app.
The lesson: if you only have time to design one layer, design the data layer. APIs can always be added. UIs can always be redesigned. But migrating a poorly designed data model while 240 tools depend on it is a project-ending event.
The data plane is solid. The control plane works. Now I need the presentation layer to catch up.
This is part 2 of a 4-part series. Next: the redesign manifesto, consolidating 55 pages into a product.