Skip to content

How it works

The pipeline in one diagram

Public news sources (RSS, Yahoo Finance, ...)
        │ shared ingestion every 20 minutes (Celery Beat)
┌─────────────────────────────────────────────────────────┐
│  Per-user fanout                                         │
│                                                          │
│   For each active user:                                  │
│     1. Filter raw items against that user's watchlist    │
│        aliases (cheap, local keyword match).             │
│     2. Synthesis Engine runs 5 agents in parallel        │
│        against each passing item.                        │
│     3. Aggregate + Reflexion to produce top signal.      │
│     4. Persist Signal row (Postgres, RLS-scoped).        │
│     5. Embed into user's ChromaDB collection.            │
│     6. Publish to Redis channel signals:<user_id>.       │
│     7. Deliver FLASH + ALERT to Telegram (if linked).    │
│     8. Deliver FLASH + ALERT to Web Push (if subscribed).│
└─────────────────────────────────────────────────────────┘
Your dashboard (real-time via WebSocket), your phone, your desktop.

Key ideas

Shared ingestion, per-user synthesis

Public news scraping happens once globally — otherwise ten users watching NVDA would each hit Yahoo ten times. But the LLM-heavy synthesis step runs once per (user, news-item) pair, so scoring and ticker impact is your watchlist's context, not a one-size-fits-all score.

Five specialist agents, not one

Instead of asking a single big prompt “is this news important and why”, we run five smaller, focused agents in parallel — each with its own lane (ticker-level facts, macro context, sector dynamics, retail sentiment, regulatory). Their outputs are weighted-averaged into the final signal. See Agents.

Reflexion on low-confidence drafts

When the aggregated score is borderline, the engine runs a reflexion pass: a second LLM call that critiques and rewrites the draft. You can see how often this fires in each signal's Agent breakdown panel.

Row-level security at the database

Every user-owned table (signals, watchlists, user_settings, rag_query_logs, ...) has a PostgreSQL RLS policy: user_id = current_setting('app.current_user'). The FastAPI session runs as Postgres role authenticated — not superuser — so RLS is actively enforced. Cross-user data leaks are blocked by Postgres itself, not by application code.

Next

  • Agents — what each of the five does
  • Scoring — urgency tiers, impact / confidence, and link types
  • Claw chat (RAG) — how free-form questions get answered from your own signals