skills/household-finance-dashboard-builder/SKILL.md
Generates a single self-contained static HTML dashboard for a household finance JSON store, with embedded D3.js, inlined data, and six standard panels (net worth over time, monthly cash flow, recurring & subscriptions, goals progress, asset allocation, vigilance feed). Applies cognitive-design principles for visual hierarchy and visual-storytelling-design for narrative annotations. Use when emitting a weekly or monthly finance dashboard, or when user mentions weekly dashboard, household dashboard, finance HTML report, or static dashboard.
npx skillsauth add lyndonkl/claude household-finance-dashboard-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This is the static-output cousin of the more general d3-visualization skill. It produces a single self-contained HTML file that opens in any browser without a server, with all data and chart code inlined. The dashboard is designed to be regenerated weekly from the household's JSON data store and committed to reports/dashboards/YYYY-MM-DD-weekly.html.
The skill assumes a JSON store conforming to the household-finance schema (accounts, transactions, balances, recurring, goals, investments, mortgage, alerts).
A single HTML file containing:
<style> block (no external CSS).<script id="dashboard-data" type="application/json">{...}</script>.<script> tag with integrity hash if offline-rendering is acceptable).visual-storytelling-design.File size target: < 1 MB. If the data exceeds this, downsample time-series before embedding (daily → weekly aggregation is usually enough).
The caller provides:
data_root — path to the household-finance data/ directory.output_path — where to write the HTML.generated_for — weekly or monthly (changes the time scope and headline).as_of — ISO date for the snapshot.prior_snapshot_path (optional) — a previous dashboard's data block for week-over-week deltas.The skill reads:
accounts.jsonbalances.jsontransactions.json (filtered to relevant window)recurring.jsongoals.jsoninvestments.jsonmortgage.jsonreports/alerts/reports/monthly/*.json for narrative context.Dashboard Build Progress:
- [ ] Step 1: Read data; validate completeness; compute snapshot
- [ ] Step 2: Compute the six panel datasets
- [ ] Step 3: Apply cognitive-design principles to layout choices
- [ ] Step 4: Generate narrative header via visual-storytelling-design
- [ ] Step 5: Render HTML scaffold + inline data + D3 code per panel
- [ ] Step 6: Run cognitive-fallacies-guard self-check on charts
- [ ] Step 7: Write to output_path; emit data quality footer
Compute the headline numbers:
net_worth_cents — sum of cash + invested + home equity estimate − liabilities (mortgage + other).delta_vs_prior_cents — vs. the prior snapshot if available.month_to_date_spend_cents, month_to_date_income_cents, month_to_date_savings_rate.goals_on_track, goals_behind, goals_ahead counts.alerts_open count.If any required file is missing, fall back gracefully: hide that panel and surface a data_gap line in the footer.
Compute exactly the data each panel needs (see The six panels). Keep arrays small — pre-aggregate to the resolution the chart needs.
Apply these defaults (delegate detailed reasoning to cognitive-design):
Invoke visual-storytelling-design to generate a 3–5 line narrative:
Build the HTML scaffold (see HTML scaffold). Inline:
renderPanel*() function per panel.Each render function follows the standard D3 data-join pattern from d3-visualization.
Before writing, run a cognitive-fallacies-guard pass on the rendered SVGs (or their data + axis configurations):
If the self-check finds issues, fix and re-render.
Write to output_path. Emit a footer with generation timestamp, schema version, last-drop date, and any data gaps.
Data: monthly net worth points from balances.json + investments.json + mortgage.json (current_principal as liability) + home equity estimate (home value - current_principal).
Chart: line chart with annotated key events (mortgage origination, large contributions, market dislocations). Y-axis starts at 0 (this is a net-worth scale where 0 matters); X-axis covers the full history.
Headline annotation: latest value + delta vs prior snapshot.
Data: per-month income (positive bars) and spending (negative bars) over the trailing 12 months, with a line showing the rolling 6-month savings rate.
Chart: diverging bar chart (income up, spending down) with savings-rate line overlay. Color: muted teal for income, muted coral for spending.
Drill-down (optional, hover): top 5 spending categories for the latest month.
Data: every active row from recurring.json, sorted by annualized_cost_cents descending.
Chart: horizontal bar chart of the top 15 by annualized cost. Each bar labeled with merchant + cadence + monthly equivalent.
Annotation: total annualized cost across all active recurring at the top. Highlight any with status: suspected_dormant or amount-changed events.
Data: every entry in goals.json with current_cents, target_cents, target_date.
Chart: horizontal stacked bar — completed vs. remaining — one row per goal. Annotate "On track / Behind / Ahead" per goal based on linear pacing to target date.
Headline: "X of Y goals on track."
Data: aggregated holdings by asset_class from investments.json (across taxable + 401k + HSA), plus the target allocation.
Chart: two donuts side by side (current vs target) OR a single donut with a target ring overlay. Label each slice directly with asset class + percentage.
Annotation: max drift in percentage points; flag if > 5pp.
Data: most recent 10 entries from reports/alerts/, severity-tagged.
Chart: a styled list — not a chart. Each entry: severity badge + one-line evidence + suggested action.
This panel is intentionally text-heavy. The dashboard is informational and operational; the user should be able to scan it and find things to do.
| Principle | Application in this dashboard | |---|---| | Pre-attentive attributes | Severity badges in the vigilance panel use color hue; everything else uses position | | Gestalt proximity | Each panel is bounded with whitespace, then a thin border, then a header | | Gestalt similarity | All numeric labels use the same monospaced font; all charts use the same axis style | | Reading order (F-pattern) | Net worth top-left; vigilance bottom-right (the actionable end of the read) | | Working memory | Max 6 categories per chart; rest aggregated | | Recognition over recall | Direct labeling — no legend-only charts | | Data-ink ratio | No 3D, no chartjunk, no decorative gradients | | Mental models | Cash flow chart uses the universally-recognized green-up/red-down convention |
The narrative header follows: Context → Change → Drivers → What needs attention.
Example:
Net worth $1,247,300 — up $4,200 this week. The increase came mostly from a $3,800 401k contribution and a small market gain in your taxable brokerage. Spending was steady at $7,840 month-to-date, slightly under your $8,500 target. One thing to watch: your portfolio drifted to 62.5% US equity, 7.5pp above your 55% target — a rebalance proposal is queued in this week's alerts.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Household Finance — [date]</title>
<style>
/* layout: 3x2 grid; max-width 1280px; light theme */
/* typography: Inter for text, JetBrains Mono for numbers */
/* colors: muted, accessible, single accent for "needs attention" */
</style>
</head>
<body>
<header>
<h1 class="net-worth-headline">$<!-- net worth --></h1>
<p class="net-worth-delta">[+/-]$<!-- delta --> this <!-- week|month --></p>
<p class="narrative">[generated narrative]</p>
</header>
<main class="grid">
<section id="panel-net-worth"></section>
<section id="panel-cash-flow"></section>
<section id="panel-recurring"></section>
<section id="panel-goals"></section>
<section id="panel-allocation"></section>
<section id="panel-vigilance"></section>
</main>
<footer>
<p>Generated [timestamp] from data/ as of [last-drop-date]. Schema version [X].</p>
<p>Data gaps: [if any].</p>
</footer>
<script id="dashboard-data" type="application/json">
{ /* inlined data */ }
</script>
<script src="https://cdn.jsdelivr.net/npm/d3@7" integrity="sha384-..." crossorigin></script>
<script>
/* renderPanelNetWorth(), renderPanelCashFlow(), renderPanelRecurring(),
renderPanelGoals(), renderPanelAllocation(), renderPanelVigilance() */
</script>
</body>
</html>
For full offline use, vendor D3 inline rather than via CDN. The dashboard agent decides per-environment.
****1234), never full account numbers. No SSNs, no full names where masks suffice.aria-labels; tabular data alternative for each chart accessible via a "Show data" toggle.testing
Cluster a conference's event records into a small set of coarse themes with finer sub-clusters, an explicit outlier bucket, and soft (multi-membership) affinities — using the hybrid embed-then-label pipeline (embed abstracts, reduce, density-cluster, then LLM-label the clusters) when embedding libraries are available, and an LLM-reasoned hierarchical fallback when they are not. Embeddings do the grouping; the LLM only names the groups. Conference-agnostic. Use when turning structured event records into a navigable theme map for preference elicitation and scheduling, when you need 6-8 reasonable themes rather than 20 muddy ones, or when overlapping talks must belong to more than one theme. Trigger keywords - theme clustering, cluster talks, embed then label, soft membership, outlier talks, conference themes, topic map.
development
Build a personal conference schedule as a constraint-optimization problem — hard constraints (no time overlap, room-to-room travel time, capacity/registration, the attendee's own must-attends and blackouts) plus a user-owned weighted objective trading interest against breadth, pacing (maximize contiguous free time), and serendipity. Surfaces unbreakable conflicts (two high-value overlapping talks the model cannot rank) as decisions for the human rather than silently picking, and reports what each choice traded away. Conference-agnostic. Use to turn a preference profile plus a theme map into a day-by-day plan, to resolve overlapping sessions, or to balance a packed vs paced schedule. Trigger keywords - schedule optimization, conference schedule, constraint optimization, overlapping talks, contiguous free time, conflict surfacing, packed vs paced.
development
Parse a heterogeneous conference program (markdown, HTML, PDF-derived text, or JSON) into normalized event records with per-field confidence scores and independent classification axes (topic, depth, format, prerequisites, recorded, capacity). Detects the program's format before extracting, treats every inferred field as uncertain (present vs inferred vs missing), and flags thin or missing abstracts so downstream enrichment can target them. Conference-agnostic. Use when ingesting a conference or event schedule into a structured store, normalizing a talk/session list, or extracting per-session metadata with calibrated confidence. Trigger keywords - program ingestion, parse schedule, session extraction, event records, conference program, talk metadata, per-field confidence.
development
Build a personalized preference profile from a small number of well-chosen, cluster-grounded questions instead of a long survey. Represents the person's interests as an uncertainty region over the theme map, picks the single highest-information-gain choice-based question (contrasting real talks from different clusters), balances exploiting known interests against exploring uncertain ones, deliberately injects outlier probes to fight selection bias, and stops as soon as the schedule would be stable. Also elicits the user-owned objective weights and hard constraints. Interactive — runs where it can actually ask the person. Conference-agnostic. Use to turn a theme map into a preference profile, to decide what to ask a conference attendee, or to elicit scheduling priorities. Trigger keywords - preference elicitation, ask few questions, information gain, choice-based questions, selection bias probe, objective weights, attendee preferences.