Teaching My Dashboard to Think Across Categories

An audit against five Open Brain principles revealed four blind spots in Life Hub: cross-category correlations, co-anomaly detection, and relationship intelligence that the data already supported but nobody was computing.

Teaching My Dashboard to Think Across Categories

A friend sent me Nate's "Open Brain Extensions" article last week. He describes five principles for building AI-powered personal systems: a two-door principle (agent and human access to the same data), time-bridging, cross-category reasoning, proactive surfacing, and a clean division of labor between agent and human. I read it expecting to take notes for a future project. Instead I ended up auditing Life Hub against every principle that same afternoon.

The audit revealed that Life Hub already implements all five deeply: 166 MCP tools on the agent side, 34 UI pages on the human side, 22 proactive advisor triggers, Granger causality testing across 10 metric pairs. But it also exposed four specific gaps that I couldn't unsee once I'd mapped them out.

The Two-Door Audit

The two-door principle says every data domain should be accessible through both an agent door (MCP tools) and a human door (UI), with read and write on both sides. I mapped all 15 data domains in Life Hub against this grid.

11 of 15 had all four doors open. Four had gaps:

  • Finance/Transactions: no human-write. You could log transactions through the MCP tool or the API, but there was no form on the finance page. If you wanted to manually record a cash purchase, you had to talk to the agent.
  • Thoughts: no human-write for edits. You could capture new thoughts from the UI, but editing an existing one required the API. Typo in a thought? Open a terminal.
  • Morning Ritual: no agent-write. The UI had step completion buttons, but there was no MCP tool to mark a step done. The agent could read your ritual status but couldn't help you complete it.
  • Relationships: initially flagged, but when I checked, the detail page already had a working edit form via HTMX. False alarm.

Fixing these was straightforward. A transaction entry form on /finance with amount, description, category, merchant, and date. A thought edit modal with re-classification and embedding regeneration on save. A complete_morning_step MCP tool that mirrors the existing HTMX endpoint. Each fix was small individually, but collectively they closed the last asymmetries in the system.

Cross-Category Blind Spots

Life Hub's correlation engine already computed Pearson correlations across 7 metric pairs: sleep hours to mood, habit completion to mood, exercise to sleep quality, and so on. The Granger causality engine tested 10 pairs for lagged causal relationships. Both were doing useful work.

But the audit revealed four connections the engines were completely blind to, despite the data already existing in the database:

  • Spending → mood. Transaction data was flowing in daily from bank feeds, and mood was being logged every day, but no one was checking whether spending spikes coincided with mood drops (stress spending) or lifts (retail therapy).
  • Meeting density → next-day sleep. CalDAV time blocks already tracked work meeting hours. Sleep logs already tracked quality and duration. But heavy meeting days weren't being tested against next-day sleep recovery.
  • Social energy → next-day mood. Social events already had an energy_impact field (draining, neutral, energizing). This wasn't being correlated with mood at all. Only social frequency was.
  • Weather → habit completion. Activity events already carried weather metadata from the collector. But nobody was asking whether rainy days correlated with lower habit completion.

Adding these was a matter of extending the existing correlation and causality engines. Four new Pearson pairs in correlations.py, three new Granger pairs in causal_inference.py (the meeting→sleep pair was already covered), and corresponding nudge templates so the system could translate raw r-values into human-readable insights like "Heavy meeting days predict worse next-day sleep (r=-0.42). Recovery matters."

Sleep Doesn't Exist in Isolation

The sleep narrative engine was already good at detecting trends: "duration is declining," "your bedtime varies more than your wake time." But it was doing this analysis in isolation. If your sleep was declining and your mood was also tanking and your habit completion was cratering, the sleep narrative had no idea. Three correlated declines would generate three independent, disconnected insights.

The fix was passing cross-domain context into compute_sleep_narrative(). When the engine detects a declining sleep trend, it now checks mood and habit data for the same period. A declining sleep trend that coincides with declining mood generates: "Mood also declined during this period (avg 5.2). Sleep and mood may be reinforcing each other." If habits are also dropping: "Habit completion also dropped (avg 62%). The decline may be systemic, not just sleep."

This is exactly the kind of cross-category reasoning that a human rarely does on their own. You notice you're sleeping badly. You don't naturally cross-reference that against your habit completion rate for the same two weeks. The system does.

Co-Anomaly Detection

Life Hub already had anomaly detection: trends.py flags individual metrics that fall below your personal p25 baseline. Low mood one day? Flagged. Poor sleep? Flagged. But each metric was evaluated independently.

The problem: a single bad mood day is noise. A day where mood, sleep, and habit completion all dropped below your personal baselines simultaneously? That's signal. That's the day worth investigating.

I added a detect_co_anomalies() function that scans the last 30 days for dates where 2 or more metrics are simultaneously below p25. It uses the existing compute_baselines() infrastructure for thresholds, so the baselines are personalized: your "bad" isn't compared against a population average, it's compared against your own rolling 30-day history.

The output is a sorted list of co-anomaly dates with severity (how many metrics dropped) and the specific metrics involved. The worst days float to the top. An advisor trigger fires when Sister Miriam (the wellness-focused council member) detects 2+ co-anomaly dates in a 7-day window, prompting a check-in.

This is available both as an MCP tool (detect_co_anomalies) and through the advisor system. The agent can surface it proactively; the human can query it on demand. Two doors.

Person-Centric Cross-Reference

The last gap was relationship intelligence. Life Hub tracks relationships with cadence monitoring and overdue notifications. But when you're about to call someone, the system couldn't tell you the full context of your interactions with that person, because the data was scattered across five different tables.

Thoughts mentioning a person are in the Thought table (with a structured people field). Social events with them are in SocialEvent. Journal entries mentioning them are in JournalEntry content. Life events involving them are in LifeEvent. Calendar meetings with them are in ActivityEvent.

The new get_relationship_context MCP tool searches all five sources by person name and returns a unified timeline. Ask the agent "what's my history with Sarah?" and it pulls together the dinner you logged in social events three weeks ago, the journal entry where you reflected on a conversation with her, the thought you captured about a book she recommended, and the calendar meeting you had last Tuesday. All in one response, sorted chronologically.

This is time-bridging in its purest form: connecting interactions across months that human memory drops.

The Numbers

The full P21 implementation added:

  • 3 new MCP tools (166 total)
  • 4 new Pearson correlation pairs (11 total)
  • 3 new Granger causality pairs (13 total)
  • 1 new module (co_anomalies.py)
  • 42 new tests (2,317 total, all passing)
  • Transaction entry form, thought editing, morning step agent tool
  • Cross-domain sleep narrative enrichment
  • Co-anomaly advisor trigger

The entire thing (audit, design, implementation, testing) happened in a single session. That's not a flex, it's a statement about what's possible when a codebase has clean patterns, comprehensive tests, and well-defined extension points. Every new correlation pair followed the same shape as the existing seven. Every new MCP tool followed the same session-and-query pattern as the existing 163. The architecture absorbed the changes without friction.

What I Learned

The most valuable thing about Nate's framework isn't any single principle. It's the audit discipline. Mapping your system against a set of principles and looking for gaps is more productive than brainstorming features. The gaps I found weren't things I would have thought to build on my own. They emerged from systematically asking: "where does this principle break down in my system?"

The cross-category reasoning gaps were the most surprising. The data was already there. Spending data, meeting data, social energy data, weather data: all flowing into the database daily. The correlation engine was right there, ready to accept new pairs. The only thing missing was the connection. That's the gap that an audit finds and a feature brainstorm misses.

Co-anomaly detection turned out to be the highest-signal addition per line of code. Individual anomalies are noise. Correlated anomalies are events. The difference between "your mood was low Tuesday" and "Tuesday was your worst day this month: mood, sleep, and habits all dropped" is the difference between data and insight.