Render finance dashboard
Use when the user says "render dashboard", "show my finances", "build the dashboard", or any morning-summary equivalent. Reads SQLite, fetches live prices/FX from Yahoo Finance, fills the HTML template, and writes a self-contained dashboard to `output/dashboard.html`.From its SKILL.md
npx -y skills add ya5huk/findash --skill render-finance-dashboardAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 19 stars19 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.4 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
render-finance-dashboard
You render the booky finance dashboard from the current state of data/finance.db. The visual design is fixed by the template; you only fill it with data. The mechanical part (SQL → HTML, live-price fetch, asset inlining) lives in scripts/render_dashboard.py — invoke it, don't re-derive it.
Where things live
- Canonical renderer:
scripts/render_dashboard.py - HTML template (placeholders in
{{NAME}}form):templates/dashboard.html.tpl - CSS:
templates/styles.css— inlined into the HTML at render time - Chart constructors:
templates/charts.js— inlined into the HTML - Vendored offline assets (gitignored, produced by
scripts/bundle-assets.py):templates/vendor/chart.umd.min.jstemplates/vendor/chartjs-adapter-date-fns.bundle.min.jstemplates/vendor/fonts-inline.css(EB Garamond + Cormorant Garamond, base64 woff2)
- Telegram credentials: the
[telegram]section of.secrets/findash(bot_token=…andchat_id=…) - Local DB:
data/finance.db - Output: a single self-contained file at
output/dashboard.html - SQL schema and example queries:
docs/sqlite-schema.md - Visual rules:
docs/design-system.md
Flow
-
Run the renderer. From the project root:
python3 scripts/render_dashboard.pyThe script handles everything mechanical:
- Live-fetches prices for currently-held securities and
USD/ILS,GBP/ILSFX rates from Yahoo Finance (query1.finance.yahoo.com/v8/finance/chart/{symbol}). User-Agent header required. - Yahoo symbol translation:
RR.LSE→RR.L. Quote units: USD direct; LSE pence (÷100→ GBP); TASE agorot (÷100→ ILS). - Persists fetched prices into
pricesand the new FX intofx_ratesso a history accumulates day-by-day. - Computes net worth in ILS, brokerage market value, unrealized P/L per position.
- Excludes accounts with
closed_on IS NOT NULLfrom Cash and from the headline (they still show in SQLite-data). - Sorts the positions table by ILS-equivalent market value, descending (so SPY ranks above RR.LSE despite fewer shares).
- Orders brokerage deposits newest first.
- Builds the SQLite-data debug tabs (first 50 rows + count per table).
- Inlines CSS, fonts, Chart.js, and the chart-app JS into a single HTML file.
- Writes
output/dashboard.htmland a small meta file at/tmp/dashboard_meta.json(used by the Telegram step).
If any vendor file is missing, the script stops with a clear message. Run
python3 scripts/bundle-assets.pyonce to fix. - Live-fetches prices for currently-held securities and
-
Send to Telegram. Delivery lives in one committed, allowlisted command so the unattended daily
claude -prun can run it without per-call approval (it can't build the read-secret +curlsend inline — the permission analyzer won't auto-approve a command that sources.secretsand expands${bot_token}, and theWritetool isn't granted unattended). The token is read at runtime and never printed.scripts/send_telegram.sh # add: --note "<line>" to append a caption lineWhat it does (= the old steps 2+3, now deterministic):
- Sends
output/dashboard.htmlas a document, captionFinance — <AS_OF_DATE> · <net worth>(literal·U+00B7), read from/tmp/dashboard_meta.json. - If
data/last_sync_summary.mdexists, sends it as a secondsendMessage(HTML parse mode; bold titleSync · <AS_OF_DATE>; split into ≤3900-char parts on\nboundaries;## Ingested/## Triagedheaders render as bold New/Filed, any other##header — e.g.## ⚠️ Warnings— passes through as its own bold line), then deletes it on success. The summary may lead with a⚠️ Warningsblock — that's expected on degraded runs, not an error. Absent → printsSync summary: Skipped (no summary). - Telegram not configured (no
[telegram]in.secrets/findash) → printsTelegram delivery skipped: …and exits 0 (local file still useful). Never deletes the local dashboard on a Telegram failure.
Pass
--note "<line>"to append a caption line — the morning flow uses this to surface a best-effort fetch failure. The script printsSent to chat <id>/Telegram delivery failed: <description>/ theSync summary: …line — relay them in step 3. - Sends
-
Report. Print:
- The absolute path of
output/dashboard.html. - The Telegram delivery status:
Sent to chat <chat_id>,Telegram delivery skipped: …, orTelegram delivery failed: <description>. - The sync summary delivery status:
Sync summary: Sent (<N> bullets),Sync summary: Skipped (no summary), orSync summary: Failed: <description>. - Any tickers Yahoo couldn't price (the script logs them on
FAILED:— flag them so the user knows which positions fell back to cost basis).
- The absolute path of
Where judgment still lives (not in the script)
- Deciding whether a fresh balance figure looks plausible or whether a sync mis-parsed something. If a number looks wrong, check the source doc and explain rather than rendering a broken figure (e.g. a closed Hapoalim sub-account showing an apparent negative balance from a parser artifact when the real closing balance was 0).
- Whether to mention a particular caveat in the Overview footnote (e.g. "no price for X" or "this account was just opened").
- The contents of the Telegram caption when the dashboard contains something unusual.
Principles
- Don't invent design. All visual choices are in
styles.cssand the template. Don't add inline styles, classes, or markup not already defined. - Be honest with empty states. If a section has no data yet, show a brief italic muted note ("No payslips yet"), not a fake placeholder row.
- Number formatting: group thousands; 2 decimals for amounts <10,000, 0 decimals for ≥10,000. Right-align money columns.
- Hebrew text passes through unchanged.
dir="auto"on table cells is already handled by the script. - The "SQLite data" tab is for debugging. Show raw rows truthfully. Don't reformat or hide columns.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most finance skills give in ~1.5k tokens
Counted across 469 of the 469 authors here whose files we hold, read 2026-08-07
- Extract date vendor amount and descriptionin 15 of 469, across 3 files
- Scan folder for invoice filesin 14 of 469, across 2 files
- Rename files to standard formatin 14 of 469, across 2 files
- Show organization plan before movingin 14 of 469, across 2 files
- Generate summary CSVin 14 of 469, across 2 files
- Organize files by categoryin 13 of 469, across 1 file
- Preserve original filesin 13 of 469, across 1 file
- Flag files missing critical infoin 13 of 469, across 1 file
- Produce the requested output filein 9 of 469, across 4 files
- Build best, base, and worst case scenariosin 9 of 469, across 5 files
- Implement backoff if rate limit errors occurin 8 of 469, across 3 files
- Determine the weighted average cost of capitalin 8 of 469, across 4 files
Said here and by no other author read
- run the rendering script
- send the dashboard via the delivery script
- report the file path and delivery status
- flag any tickers lacking live prices
- check the source doc if a figure looks wrong
- explain implausible figures instead of rendering them
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.