Skip to content

noahkostesku/wealthmind

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

20 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

WealthMind

WealthMind

AI-powered financial intelligence for Canadian investors.

WealthMind is a multi-agent system that monitors a client's full financial profile β€” TFSA, RRSP, FHSA, non-registered, margin, crypto, and chequing β€” and surfaces ranked, dollar-quantified insights in real time. Five specialist LLM agents run in parallel via LangGraph, each analyzing a different financial domain. A synthesis layer merges their findings into plain-language recommendations delivered through "Welly," a conversational AI interface.

No trades are executed. No money moves. The system surfaces intelligence. The human acts.


Table of Contents


What It Does

WealthMind ingests a Canadian investor's complete financial picture and answers one question: "What should I do with my money right now?"

The system:

  • Runs 5 specialist agents in parallel against live portfolio data and CRA tax rules
  • Calculates dollar-quantified impact for every recommendation (e.g. "$4,297 RRSP tax refund")
  • Ranks findings by urgency and dollar impact
  • Delivers insights through Welly, a conversational AI that streams responses via SSE
  • Supports what-if scenario analysis (e.g. "What if I contribute $5,000 to my RRSP?")
  • Provides a full portfolio management dashboard with live prices via yfinance
  • Simulates buy/sell/deposit/withdraw/transfer/currency exchange operations
  • Tracks CRA contribution room for TFSA, RRSP, and FHSA with deadline awareness
  • Computes capital gains tax exposure on non-registered positions in real time

System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                            WEALTHMIND                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚          FRONTEND          β”‚               BACKEND                  β”‚
β”‚          Next.js 16        β”‚               FastAPI                  β”‚
β”‚                            β”‚                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Dashboard           β”‚  β”‚  β”‚         API Routes               β”‚  β”‚
β”‚  β”‚  Portfolio           │◄─┼───  /portfolio   /accounts          β”‚  β”‚
β”‚  β”‚  Accounts            β”‚  β”‚  β”‚  /trade       /markets           β”‚  β”‚
β”‚  β”‚  Markets             β”‚  β”‚  β”‚  /chat        /analyze           β”‚  β”‚
β”‚  β”‚  History             β”‚  β”‚  β”‚  /fx          /health            β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                            β”‚                 β”‚                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Welly Chat Panel    │◄─┼───       LangGraph Engine           β”‚  β”‚
β”‚  β”‚  (SSE Streaming)     β”‚  β”‚  β”‚  Supervisor β†’ Synthesis          β”‚  β”‚
β”‚  β”‚  Onboarding          β”‚  β”‚  β”‚       β†’ HITL β†’ Stream            β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                            β”‚                 β”‚                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Auth.js             β”‚  β”‚  β”‚         Services Layer           β”‚  β”‚
β”‚  β”‚  Google OAuth        β”‚  β”‚  β”‚  Portfolio Β· Prices Β· Trading    β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚  FX Β· CRA Rules                  β”‚  β”‚
β”‚                            β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                            β”‚                 β”‚                      β”‚
β”‚                            β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚                            β”‚  β”‚     SQLite + aiosqlite           β”‚  β”‚
β”‚                            β”‚  β”‚  Users Β· Accounts Β· Positions    β”‚  β”‚
β”‚                            β”‚  β”‚  Transactions Β· Conversations    β”‚  β”‚
β”‚                            β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          External: Anthropic API  Β· yfinance Β· Google OAuth

LangGraph Agent Architecture

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚    START    β”‚
                         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                         β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                         β”‚  SUPERVISOR β”‚
                         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚          β”‚          β”‚          β”‚          β”‚
   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β–Όβ”€β”€β”€β”€β”€β”€β”
   β”‚ Allocation β”‚ β”‚  Tax   β”‚ β”‚  TLH   β”‚ β”‚  Rate  β”‚ β”‚ Timing β”‚
   β”‚   Agent    β”‚ β”‚ Agent  β”‚ β”‚ Agent  β”‚ β”‚  Arb.  β”‚ β”‚ Agent  β”‚
   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
          β”‚          β”‚         β”‚          β”‚          β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                   (asyncio.gather β€” all run in parallel)
                                β”‚
                         β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                         β”‚    MERGE    β”‚
                         β”‚  domain_    β”‚
                         β”‚  findings   β”‚
                         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                         β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                         β”‚  SYNTHESIS  β”‚
                         β”‚ Deduplicate β”‚
                         β”‚  Rank by $  β”‚
                         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                         β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                         β”‚    HITL     β”‚
                         β”‚ Human-in-   β”‚
                         β”‚  the-Loop   β”‚
                         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                         β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                         β”‚     END     β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Agent Domain Grid

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      AGENT       β”‚                    RESPONSIBILITY                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Allocation      β”‚  TFSA/RRSP/FHSA contribution room analysis           β”‚
β”‚                  β”‚  Cash placement optimization                         β”‚
β”‚                  β”‚  Registered account gap detection                    β”‚
β”‚                  β”‚  Idle cash identification                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Tax             β”‚  Capital gains tax consequences of trades            β”‚
β”‚  Implications    β”‚  Tax exposure on unrealized gains                    β”‚
β”‚                  β”‚  CRA inclusion rate calculations                     β”‚
β”‚                  β”‚  Marginal rate impact analysis                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  TLH             β”‚  Tax-loss harvesting opportunities                   β”‚
β”‚  (Harvesting)    β”‚  Unrealized losses eligible for harvest              β”‚
β”‚                  β”‚  Superficial loss rule awareness (30-day)            β”‚
β”‚                  β”‚  Wash sale avoidance                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Rate            β”‚  Margin interest vs cash savings rate                β”‚
β”‚  Arbitrage       β”‚  Capital inefficiency detection                      β”‚
β”‚                  β”‚  Debt cost vs opportunity cost analysis              β”‚
β”‚                  β”‚  6.2% margin vs 2.5% chequing arbitrage              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Timing          β”‚  RRSP contribution deadline awareness                β”‚
β”‚                  β”‚  Tax-year-end opportunities                          β”‚
β”‚                  β”‚  Time-sensitive financial actions                    β”‚
β”‚                  β”‚  Seasonal optimization windows                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Agent Workflow Pipeline

Full Analysis Pipeline (POST /analyze)

Client Request
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Load Live      │────▢│  Build Graph    │────▢│   Supervisor    β”‚
β”‚  Portfolio      β”‚     β”‚  State          β”‚     β”‚   Node          β”‚
β”‚  Snapshot       β”‚     β”‚                 β”‚     β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                          β”‚
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬
                          β”‚          β”‚          β”‚         β”‚         β”‚          
                     β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”
                     β”‚ Alloc-  β”‚ β”‚  Tax  β”‚ β”‚  TLH  β”‚ β”‚ Rate  β”‚ β”‚Timing β”‚
                     β”‚  ation  β”‚ β”‚       β”‚ β”‚       β”‚ β”‚  Arb. β”‚ β”‚       β”‚
                     β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜
                          β”‚          β”‚          β”‚         β”‚        β”‚
                          β”‚     Each agent:     β”‚         β”‚        β”‚
                          β”‚     1. Load prompt  β”‚         β”‚        β”‚
                          β”‚     2. Inject data  β”‚         β”‚        β”‚
                          β”‚     3. Call Claude  β”‚         β”‚        β”‚
                          β”‚     4. Parse JSON   β”‚         β”‚        β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                β”‚
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚          Merge domain_findings              β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                β”‚
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚  Synthesis Node                             β”‚
                          β”‚  β€’ Validate required keys                   β”‚
                          β”‚  β€’ Deduplicate by title                     β”‚
                          β”‚  β€’ Rank by dollar_impact DESC               β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                β”‚
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚  HITL Node                                  β”‚
                          β”‚  β€’ Status: "surfaced"                       β”‚
                          β”‚  β€’ Insights ready for human review          β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                β”‚
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚  WebSocket Broadcast                        β”‚
                          β”‚  β€’ Push ranked insights to frontend         β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Chat Pipeline (SSE Streaming)

User Message
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Conversation       │──── SSE: "routing" ────────────────▢ Frontend
β”‚  Router             β”‚
β”‚  (Claude call)      β”‚
β”‚                     β”‚
β”‚  Decides:           β”‚
β”‚  β€’ which agents     β”‚
β”‚  β€’ can answer from  β”‚
β”‚    context?         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚         Can answer from context?            β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ YES                   β”‚ NO
               β–Ό                       β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  Return direct   β”‚   β”‚  SSE: "agent_start" (Γ—N)  β”‚
    β”‚  response        β”‚   β”‚  SSE: "handoff" (Γ—N)      β”‚
    β”‚  SSE: "response" β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
                                         β–Ό
                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                             β”‚  Run agents in parallel   β”‚
                             β”‚  (asyncio.gather)         β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                           β”‚
                                SSE: "agent_complete" (Γ—N)
                                           β”‚
                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                             β”‚  Synthesize Response      β”‚
                             β”‚  (Claude call)            β”‚
                             β”‚  β€’ Enforces <60 words     β”‚
                             β”‚  β€’ Dollar figures only    β”‚
                             β”‚  β€’ No process talk        β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                           β”‚
                                    SSE: "response"
                                           β”‚
                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                             β”‚  Cross-Referral Check     β”‚
                             β”‚  (up to 2 auto-refs)      β”‚
                             β”‚  Evaluates: would another β”‚
                             β”‚  agent add value?         β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                           β”‚
                       SSE: "handoff" + "auto_referral_response"
                                           β”‚
                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                             β”‚  Follow-Up Chips          β”‚
                             β”‚  (2–3 suggestions)        β”‚
                             β”‚  with real $ figures      β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                           β”‚
                                    SSE: "follow_ups"
                                    SSE: "done"

Cross-Referral System

After every agent response, WealthMind evaluates whether additional agents should automatically run:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Source Agent   β”‚           Candidate Agents to Auto-Invoke            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Allocation      β”‚  Timing, Rate Arbitrage                              β”‚
β”‚  Tax Implic.     β”‚  TLH, Timing                                         β”‚
β”‚  TLH             β”‚  Tax Implications, Timing                            β”‚
β”‚  Rate Arbitrage  β”‚  Allocation                                          β”‚
β”‚  Timing          β”‚  Allocation, Tax Implications                        β”‚
β”‚  Direct Response β”‚  All 5 agents (evaluated individually)               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Max auto-referrals per turn: 2. Each candidate is evaluated by Claude for relevance before invocation.


Tech Stack

Frontend

Technology Purpose
Next.js 16 React framework with App Router
React 19 UI library
TypeScript Type safety
Tailwind CSS 4 Utility-first styling
shadcn/ui UI component primitives (Radix UI)
Recharts Portfolio charts and visualizations
Lucide React Icon system
Auth.js (NextAuth) Google OAuth authentication
SSE (EventSource) Real-time chat streaming

Backend

Technology Purpose
FastAPI Async Python web framework
LangGraph Multi-agent orchestration graph
LangChain Anthropic Claude API integration
Claude Sonnet 4.6 LLM for all agent reasoning
SQLAlchemy 2.0 Async ORM (aiosqlite driver)
SQLite Database (zero-config, file-based)
yfinance Live stock prices and market data
SSE-Starlette Server-Sent Events for chat streaming
Uvicorn ASGI server
Pydantic Request/response validation

Infrastructure

Technology Purpose
Railway Cloud deployment (both services)
Nixpacks Build system
WebSockets Real-time insight broadcasting
JWT (demo) Stateless auth token passing

Project Structure

wealthmind/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ main.py                      # FastAPI app, CORS, JWT middleware, lifespan
β”‚   β”œβ”€β”€ database.py                  # SQLAlchemy models, async engine, demo seeder
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   └── routes.py                # All REST + SSE + WebSocket endpoints
β”‚   β”œβ”€β”€ graph/
β”‚   β”‚   β”œβ”€β”€ graph.py                 # LangGraph compilation (supervisor β†’ synthesis β†’ HITL)
β”‚   β”‚   β”œβ”€β”€ agents.py                # 5 domain agent functions (Claude calls)
β”‚   β”‚   β”œβ”€β”€ router.py                # Conversation router (intent classification)
β”‚   β”‚   β”œβ”€β”€ synthesizer.py           # Response synthesis + cross-referral + follow-up chips
β”‚   β”‚   β”œβ”€β”€ proactive.py             # Proactive greeting generation
β”‚   β”‚   β”œβ”€β”€ state.py                 # GraphState TypedDict
β”‚   β”‚   └── conversation_state.py    # ConversationState TypedDict
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ portfolio.py             # Portfolio snapshots, tax exposure calculations
β”‚   β”‚   β”œβ”€β”€ prices.py                # yfinance wrapper with 60s cache
β”‚   β”‚   └── trading.py               # Simulated trade execution (buy/sell/deposit/withdraw/fx)
β”‚   β”œβ”€β”€ prompts/
β”‚   β”‚   β”œβ”€β”€ allocation.txt           # Allocation agent system prompt
β”‚   β”‚   β”œβ”€β”€ tax_implications.txt     # Tax agent system prompt
β”‚   β”‚   β”œβ”€β”€ tlh.txt                  # Tax-loss harvesting agent prompt
β”‚   β”‚   β”œβ”€β”€ rate_arbitrage.txt       # Rate arbitrage agent prompt
β”‚   β”‚   β”œβ”€β”€ timing.txt               # Timing agent system prompt
β”‚   β”‚   β”œβ”€β”€ conversation_router.txt  # Router system prompt
β”‚   β”‚   β”œβ”€β”€ response_synthesizer.txt # Synthesizer system prompt
β”‚   β”‚   └── welly_persona.txt        # Welly personality definition
β”‚   β”œβ”€β”€ data/
β”‚   β”‚   β”œβ”€β”€ demo_profile.json        # Synthetic client seed data
β”‚   β”‚   └── cra_rules_2024.json      # CRA tax rules injected into agents
β”‚   β”œβ”€β”€ requirements.txt
β”‚   └── railway.toml
β”‚
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ layout.tsx               # Root layout with providers
β”‚   β”‚   β”œβ”€β”€ page.tsx                 # Landing page
β”‚   β”‚   β”œβ”€β”€ login/page.tsx           # Google OAuth login
β”‚   β”‚   β”œβ”€β”€ dashboard/page.tsx       # Portfolio dashboard
β”‚   β”‚   β”œβ”€β”€ portfolio/page.tsx       # Positions & trading
β”‚   β”‚   β”œβ”€β”€ accounts/page.tsx        # Account management
β”‚   β”‚   β”œβ”€β”€ markets/page.tsx         # Market search & quotes
β”‚   β”‚   └── history/page.tsx         # Transaction history
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ AppShell.tsx             # Layout shell with sidebar + Welly panel
β”‚   β”‚   β”œβ”€β”€ Sidebar.tsx              # Navigation sidebar
β”‚   β”‚   β”œβ”€β”€ Providers.tsx            # Auth + context providers
β”‚   β”‚   β”œβ”€β”€ chat/
β”‚   β”‚   β”‚   └── ChatPanel.tsx        # Welly conversational interface
β”‚   β”‚   β”œβ”€β”€ onboarding/
β”‚   β”‚   β”‚   β”œβ”€β”€ IntroScreen.tsx      # First-time intro overlay
β”‚   β”‚   β”‚   └── WellyIntro.tsx       # Programmatic onboarding sequence
β”‚   β”‚   β”œβ”€β”€ trading/
β”‚   β”‚   β”‚   β”œβ”€β”€ TradeModal.tsx       # Buy/sell order modal
β”‚   β”‚   β”‚   └── ExchangeModal.tsx    # Currency exchange modal
β”‚   β”‚   └── ui/                      # shadcn/ui primitives
β”‚   β”œβ”€β”€ contexts/
β”‚   β”‚   └── PortfolioContext.tsx      # Global portfolio state
β”‚   β”œβ”€β”€ lib/
β”‚   β”‚   β”œβ”€β”€ api.ts                   # API client (REST + SSE streaming)
β”‚   β”‚   β”œβ”€β”€ websocket.ts             # WebSocket client for insights
β”‚   β”‚   └── utils.ts                 # Utility functions
β”‚   β”œβ”€β”€ types/
β”‚   β”‚   └── index.ts                 # TypeScript interfaces
β”‚   β”œβ”€β”€ middleware.ts                # Auth middleware (route protection)
β”‚   β”œβ”€β”€ package.json
β”‚   └── railway.toml
β”‚
β”œβ”€β”€ CLAUDE.md                        # AI development guidelines
└── README.md

Getting Started

Prerequisites

  • Python 3.14+
  • Node.js 20+
  • Anthropic API key
  • Google OAuth credentials

Backend

cd backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Create .env file
echo "ANTHROPIC_API_KEY=your_key_here" > .env
echo "FRONTEND_URL=http://localhost:3000" >> .env

uvicorn main:app --reload --port 8000

Frontend

cd frontend
npm install

# Create .env.local file
echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local
echo "NEXTAUTH_SECRET=your_secret_here" >> .env.local
echo "NEXTAUTH_URL=http://localhost:3000" >> .env.local
echo "GOOGLE_CLIENT_ID=your_google_client_id" >> .env.local
echo "GOOGLE_CLIENT_SECRET=your_google_client_secret" >> .env.local

npm run dev

The backend auto-creates the SQLite database and seeds a demo user on first startup.


Environment Variables

Backend (.env)

Variable Description
ANTHROPIC_API_KEY Anthropic API key
DATABASE_URL SQLite path
FRONTEND_URL Frontend origin for CORS

Frontend (.env.local)

Variable Description
NEXT_PUBLIC_API_URL Backend API URL
NEXTAUTH_SECRET NextAuth session encryption secret
NEXTAUTH_URL Canonical app URL
GOOGLE_CLIENT_ID Google OAuth client ID
GOOGLE_CLIENT_SECRET Google OAuth client secret

License

Β© Noah Kostesku. All rights reserved.

This project and its source code are proprietary. No part of this codebase may be reproduced, distributed, or transmitted in any form without prior written permission from the author.

About

LangGraph-based multi-agent financial analysis system for Canadian portfolios, delivering real-time, ranked, dollar-impact insights.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors