{"slug": "show-hn-daybreak-a-stock-brief-where-the-ai-never-touches-the-numbers", "title": "Show HN: DayBreak, a stock brief where the AI never touches the numbers", "summary": "A developer released DayBreak, a self-hosted morning stock-brief tool for US equities that computes every figure deterministically in TypeScript and uses Google's Gemini only to word a verified fact sheet. DayBreak's guardrail module (src/lib/guard.ts) parses the model's JSON output with Zod and rejects any response containing a number absent from the fact sheet or advisory wording such as \"should,\" \"buy,\" \"will rise\" or \"undervalued,\" falling back to a deterministic template (src/lib/summarize.ts) if the AI breaks a rule twice. The tool pulls quotes, 5-year daily OHLCV bars, earnings dates, fundamentals and headlines from Financial Modeling Prep, Finnhub and Yahoo Finance with Stooq as a final fallback, caches them in Postgres, and sends a brief only when a watchlist stock moves beyond a default ±3% threshold, has earnings within 7 days, or crosses a custom price level.", "body_md": "**A calm, self-hosted morning brief and stock analysis tool for US equities.**\n\nDayBreak watches your US stock list overnight and sends a short morning note only when something actually happened: a big daily move, upcoming earnings, or a custom watch price crossed. When a stock moves, it explains *why* by comparing the move against the broader US market (`SPY`), its sector ETF (` XLK`, `XLF`, etc.), trading volume, and real news headlines.\n\n**Information only, not financial advice.** DayBreak is an opinionated personal tool for US stocks. Every number is computed deterministically in code; the AI only words a verified fact sheet.\n\n| Today & Morning Brief | Stock Analysis & Signal Backtest | \n|---|---|\n\n| Paper Ideas Scorecard | Mobile View | \n|---|---|\n\n- **Calm Morning Brief (Web + Email)** : Runs on a schedule after the US market close. If nothing on your watchlist moved beyond your threshold (default`±3%` ), has earnings within 7 days, or crossed a custom watch price, it sends a single quiet line with no AI call wasted.\n- **Strict AI Guardrails (`src/lib/guard.ts`)** : Numbers come from code, never from the AI. Gemini receives a plain-text fact sheet and returns JSON.`validateBrief()` rejects any output containing a number not in the fact sheet, any buy/sell/recommendation wording, or any price prediction. If the AI breaks a rule twice, DayBreak falls back to a deterministic template (`src/lib/summarize.ts` ).\n- **\"Why Did It Move?\" Explainer (`src/lib/explain.ts`)** : Compares 1D / 1W / 1M returns against` SPY` and the stock's SPDR Sector ETF (`XLK` ,`XLF` ,`XLV` ,`XLE` , etc.) to classify sessions as**Market-wide** ,**Sector-wide** ,**Company-specific** , or**Quiet** , paired with 20-day volume ratios and date-matched news headlines.\n- **5-Year Interactive Chart & Technical Indicators (`src/lib/indicators.ts`)** : Pure TypeScript calculations for 20/50/200-day SMAs, Golden/Death crosses, Wilder's RSI(14), MACD(12,26,9), Bollinger Bands, 30-day annualized volatility, and max drawdown.\n- **Transparent Signal Hints & Per-Stock Backtest (`src/lib/signal.ts`)** : Computes a`-100` to`+100` hint score (`Strong Sell` to`Strong Buy` ) with every contributing factor and point weight visible, then replays that exact scoring rule across the stock's own stored history (20-day forward returns vs. random-day baseline) so you can see whether the signal actually worked on that stock in the past.\n- **Fundamentals & Valuation Context (`src/lib/fundamentals.ts`)** : Displays Market Cap, P/E Ratio, EPS, Dividend Yield, and Beta (cached weekly in Postgres).\n- **Custom Watch Price Levels** : Set optional low/high price levels on any stock to get alerted in your morning brief when price crosses your level.\n- **Paper Ideas & Honest Scorecard (`src/lib/scorecard.ts`)** : Log pretend long/short ideas (linked to a morning alert or on your own) and track win rate and follow-through before risking real money.\n- **Command Palette (`Ctrl+K` / `Cmd+K`)** : Jump directly to any US stock's analysis page, add tickers to your watchlist, trigger a brief, or switch between light and dark frosted-glass themes.\n\n1. **Deterministic Data (`src/lib/market/`)** : Quotes, 5-year daily OHLCV bars, earnings dates, fundamentals, and headlines are fetched from**Financial Modeling Prep (FMP)** ,**Finnhub** , and**Yahoo Finance** (with**Stooq** as a final fallback) and cached in Postgres.\n2. **Code-Built Fact Sheet (`src/lib/facts.ts`)** : All percentages, 52-week range positions, volume ratios, and caution notes are calculated in TypeScript and serialized into a strict fact sheet.\n3. **Zero-Trust Validation (`src/lib/guard.ts`)** : The LLM output is parsed with Zod and checked token-by-token. Any invented number, missing symbol, or advisory/predictive phrase (`\"should\"` ,`\"buy\"` ,`\"will rise\"` ,`\"undervalued\"` , etc.) is rejected.\n\nWant to explore the UI immediately with demo data? DayBreak includes an embedded Postgres dev runner:\n\n```\nnpm install\nnpm run dev:db    # starts embedded Postgres on :5432 and seeds demo@daybreak.local / demo-password-123\n```\n\nThen in a second terminal:\n\n```\nSESSION_SECRET=demo-secret-at-least-32-characters-long npm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) and sign in with `demo@daybreak.local` / `demo-password-123`.\n\n```\ncp .env.example .env        # fill in your API keys (all free tiers work)\ndocker compose up -d db     # start Postgres 16\nnpm run migrate             # apply db/schema.sql\nnpm run create-user -- you@example.com 'a-password-of-12+-chars'\nnpm run dev                 # http://localhost:3000\nnpm run brief               # run the morning brief job once right now\n```\n\n| Variable | Description | \n|---|---|\n| `DATABASE_URL` | Postgres connection string ( `postgres://daybreak:...@localhost:5432/daybreak` ) | \n| `SESSION_SECRET` | 32+ character secret for signing `HttpOnly` JWT session cookies | \n| `FMP_API_KEY` | [Financial Modeling Prep](https://site.financialmodelingprep.com/) API key (free tier) | \n| `FINNHUB_API_KEY` | [Finnhub](https://finnhub.io/) API key (free tier; fallback quotes, fundamentals & news headlines) | \n| `GEMINI_API_KEY` | [Google Gemini](https://aistudio.google.com/) API key (free tier; words the morning brief) | \n| `SMTP_HOST` ,`SMTP_PORT` ,`SMTP_USER` ,`SMTP_PASS` ,`MAIL_FROM` | Optional SMTP settings (e.g., Resend, Postmark, Gmail) for morning emails | \n| `BRIEF_CRON` &`BRIEF_TZ` | Cron schedule for the worker (default `0 7 * * 2-6` in`Asia/Dubai` , after US Mon–Fri close) | \n| `MOVE_THRESHOLD_PCT` | Daily `%` move that triggers a jump/drop alert (default`3` ) | \n| `HEALTHCHECK_URL` | Optional [Healthchecks.io](https://healthchecks.io/) dead-man's switch URL | \n\nDayBreak is designed to run on a single Ubuntu VPS via **Docker Compose** or **Coolify**:\n\n```\ndocker compose up -d --build\ndocker compose exec web npm run create-user -- you@example.com 'a-password-of-12+-chars'\n```\n\nThis starts three containers from a single build:\n\n- `db` : Postgres 16 with persistent volume (`dbdata` )\n- `web` : Next.js 15 server (runs idempotent`npm run migrate` automatically on startup)\n- `worker` :`node-cron` scheduler for the daily brief and history sync\n\n- **Failure Alert** : If any step of the morning job fails,`worker` emails`ADMIN_EMAIL` and pings`${HEALTHCHECK_URL}/fail` .\n- **Dead-Man's Switch** : Pings`${HEALTHCHECK_URL}/start` and`${HEALTHCHECK_URL}` on completion so total server outages never go unnoticed.\n- **Health Endpoint** :`GET /api/health` returns HTTP`200` if Postgres is healthy and a brief succeeded within the last 76 hours (or`503` otherwise, ready for UptimeRobot / Coolify healthchecks).\n\n- **Framework** : Next.js 15 (App Router) + React 19, TypeScript\n- **Database** : PostgreSQL (`postgres` driver, raw SQL, zero ORM overhead)\n- **Styling** : Custom frosted-glass CSS with light/dark view transitions & SVG charts (`src/app/globals.css` )\n- **Tests** : Vitest (`tests/` )\n\n```\nnpm run dev         # start Next.js dev server\nnpm test            # run Vitest unit test suite\nnpm run typecheck   # run TypeScript compiler check\nnpm run build       # production Next.js build\nnpm run migrate     # apply idempotent db/schema.sql\nnpm run brief       # trigger the morning brief job immediately\n```\n\nContributions are welcome! Please read [CONTRIBUTING.md](https://github.com/XahidEx/DayBreak/blob/main/CONTRIBUTING.md) for local setup instructions and project guidelines before opening a pull request.\n\nDayBreak is for **informational and educational purposes only** and does **not** constitute financial, investment, trading, or legal advice. Signal scores, technical indicators, and backtests describe past price patterns only and cannot predict future market performance. Always do your own research and consult a qualified financial professional before making investment decisions.\n\nReleased under the [MIT License](https://github.com/XahidEx/DayBreak/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-daybreak-a-stock-brief-where-the-ai-never-touches-the-numbers", "canonical_source": "https://github.com/XahidEx/DayBreak", "published_at": "2026-11-10 10:36:27+00:00", "updated_at": "2026-11-10 10:53:32.553325+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "developer-tools", "ai-products"], "entities": ["DayBreak", "Gemini", "Financial Modeling Prep", "Finnhub", "Yahoo Finance", "Stooq", "Postgres", "Zod"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-daybreak-a-stock-brief-where-the-ai-never-touches-the-numbers", "markdown": "https://wpnews.pro/news/show-hn-daybreak-a-stock-brief-where-the-ai-never-touches-the-numbers.md", "text": "https://wpnews.pro/news/show-hn-daybreak-a-stock-brief-where-the-ai-never-touches-the-numbers.txt", "jsonld": "https://wpnews.pro/news/show-hn-daybreak-a-stock-brief-where-the-ai-never-touches-the-numbers.jsonld"}}