One Session, One Codebase: How Claude Code Audited, Fixed, and Hardened My Life Dashboard
A single Claude Code session found 4 bugs via Playwright, shipped 5 UX features, built 7 new skills, fixed 5 architectural weaknesses, and split two monolith files. All deployed to production with zero regressions.
I sat down for what I thought would be a quick audit of my personal life dashboard. Eight hours later, I'd shipped 30+ changes across three repositories, built 7 new skills, split two monolith files into 37 domain modules, and added 84 tests, all without a single regression. Here's how.
The Setup
I run a personal infrastructure stack on a two-node Kubernetes homelab (Talos Linux, Flux GitOps). The centerpiece is Life-Hub, a 64K-line FastAPI dashboard that tracks habits, mood, sleep, goals, journal entries, and finances across 37 pages with 200+ MCP tools. It's connected to OpenClaw, an AI agent platform where Henry (my Chief of Staff agent) orchestrates 8 specialist agents through a Mission Control task board.
Both systems had been in “feature complete” mode for weeks. Time to stress-test.
The Playwright Audit
I started Claude Code's bug-hunter skill and pointed Playwright at a fresh local instance with an empty database. The goal: visit every page, test every CRUD workflow, and find what breaks.
37 pages tested. 4 bugs found.
The most interesting was a cascade failure I never would have caught manually. Three pages (/time-tracking, /screen-time, and /llm-costs) were missing the API key in their Jinja2 template context. Every other page had it, but these three didn't.
The sequence: page loads → HTMX lazy-loads navigation badges → request goes out without auth → 401 → rate limiter increments. After browsing those pages a few times, the rate limiter triggered globally. Suddenly every authenticated request, even valid ones, returned 429. The entire app locked up until server restart.
The root cause was copy-paste. The api_key was manually passed in 40 separate route handlers. Three of them forgot it.
The fix: One line.
templates.env.globals["api_key"] = settings.API_KEYJinja2 template globals inject the variable into every render automatically. I deleted all 40 manual copies. No future route can forget it.
UX Hardening
With bugs fixed, I shifted to the user experience. I identified 5 weaknesses that spanned both Life-Hub and Mission Control:
1. Command Palette (Cmd+K)
50+ pages across both systems with no way to jump directly to what you need. I built a command palette that searches across pages, goals, people, journal entries, and thoughts, backed by a new search API endpoint. Type “kube” and it instantly surfaces the “Learn Kubernetes” goal and related thoughts from the brain.
2. Loading States for AI Features
The daily brief, masterpiece day planner, roundtable discussions, and council sessions all take 5-15 seconds with zero visual feedback. Users think the feature is broken. Every AI-powered section now shows a spinner with time estimates: “Generating your masterpiece day plan... (typically 5-10s).”
3. Consistent Empty States
Seven pages rendered completely blank when there was no data: no message, no guidance, no call to action. Now each shows a helpful message with a link to the Today page.
4. Mobile Task Board
Mission Control's 5-column Kanban board was unusable on phones. I added a mobile-optimized list view that auto-activates below 768px: single column, grouped by status, with inline expand and status dropdowns.
5. Cross-System Awareness
Life-Hub and Mission Control were islands. Now MC's sidebar shows current mood and wellness score (pulled from Life-Hub MCP), and Life-Hub's Today page shows active agent tasks from MC.
7 Skills for Agent-Human Collaboration
The biggest gap wasn't in the code. It was in the workflow between me and my agents. I built 7 new Claude Code skills that bridge Life-Hub personal data with OpenClaw agent orchestration:
- agent-standup: Unified view of agent tasks + personal wellness
- energy-router: Routes work based on mood, energy, burnout risk
- agent-debrief: Post-task review with scorecard and memory updates
- life-sync: Pushes personal context to agents before delegation
- ritual-builder: Creates recurring rituals spanning both systems
- council-consult: On-demand advisory council sessions from the CLI
- agent-onboard: Scaffolds new agents with persona, workspace, and routing
The agent-standup skill was the validation moment. I ran it live and it pulled real data from both systems: 6 in-progress tasks (all assigned to Henry, none delegated to specialists), wellness score of 82, energy forecast of 4.9/10 with 2 baby wake-ups factored in. The recommendation: “Energy is predicted low: defer infrastructure work and focus on review tasks.”
Architectural Hardening
The audit also identified 5 structural weaknesses lurking beneath the polished UI:
- LLM Circuit Breaker: Added 30-second timeout and circuit breaker that opens after 3 consecutive failures, blocking calls for 5 minutes.
- Cascade Deletes: Fixed orphaned
GoalDependencyandGoalReviewrecords on goal delete. - MC Data Durability: Atomic writes with
.bakbackup and corruption recovery. - MC Authentication: Bearer token middleware on all API routes, backward compatible.
- Pillar Scores Cache: 5-minute TTL cache with invalidation on writes.
Splitting the Monoliths
Two files had grown unwieldy:
htmx_routes.py: 7,500 lines → 21 domain modules inapp/htmx/mcp_server.py: 9,200 lines → 16 domain modules inapp/mcp/
Both original files are now thin re-export shims for backward compatibility. Every test passes without modification.
The Numbers
| Metric | Before | After |
|---|---|---|
| Tests | 2,426 | 2,510 |
| Skills | 26 | 33 |
| Bugs found & fixed | n/a | 4 |
| Monolith files | 2 (16.7K lines) | 37 modules |
| CI coverage gate | None | 60% minimum |
| Regressions | n/a | 0 |
Everything was deployed to production and validated with Playwright against the live cluster.
What I Learned
The cascade bug was the headline, but the real insight was simpler: copy-paste is a design smell. Forty route handlers each manually passing api_key isn't “consistent”: it's 40 chances to forget. One template global replaced all of them.
The same principle applied everywhere: pillar scores recomputed on every page load (cache once, invalidate on write), JSON files written without backup (atomic rename + .bak), test files sharing date ranges (assign unique ranges upfront).
The Architect builds systems where the default is correct. The Slumlord copies and pastes until something breaks at 2am.