# Project export: Compass

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2026
- Tagline: Your kid's diagnosed. You get a pamphlet and "good luck." Autism's up 5x since 2000 (1 in 150 → 1 in 31). We built the roadmap that should've existed: clinics, letters, real answers, all personalized.
- Devpost: https://devpost.com/software/compass-hdpfnb
- GitHub: https://github.com/abissi17/berkeley_hackathon_proj
- Video: https://www.youtube.com/embed/h3A94QYWywA?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 4 GitHub contributor(s) — Abigail Chang (9 commits), Jerry Z (3 commits), Claude Sonnet 4.6 (1 commits), Charles (1 commits)

## Devpost submission (written by the team)

### Inspiration

When one of our teammate's younger brother was diagnosed with Level 2 Autism Spectrum Disorder, the family expected answers — a plan, a next step, a direction. Instead, they were handed a diagnosis and left to figure out the rest alone. Appointments stretched weeks out. Resources were buried behind insurance jargon and specialist waitlists. Nobody guided them through what came next. That experience became the foundation for Compass. Millions of families face the same wall every year — not because the resources don't exist, but because navigating them is a full-time job nobody signed up for. Compass exists to change that. In under five minutes, it delivers a personalized care roadmap, actionable next steps, and real local provider connections — meeting families exactly where they are. What It Does Compass serves two users simultaneously. For parents, the flow is simple: complete a short intake describing their child's age, location, diagnosis status, and concerns — by typing or by voice. Compass returns: A prioritized care roadmap with urgency-labeled action steps Real local providers scraped live from the web, filtered by zip code and insurance Ready-to-send advocacy letters (IEP requests, referral letters, insurance appeals) A context-aware AI chat assistant that remembers the entire session — no re-explaining required For clinics and care providers, Compass offers a persistent case management dashboard. Practitioners manage multiple children, each with stored roadmaps, letters, provider results, and full chat history — all backed by a cloud database. How We Built It Every technology in our stack is load-bearing. Remove any one of them and a core feature disappears. Claude (Anthropic) is the AI backbone. A single, carefully engineered prompt generates the full care roadmap and all three advocacy letters in one API call — minimizing latency while maximizing coherence. The roadmap prompt injects the child's complete intake profile and instructs Claude to reason about age-appropriate services, California-specific programs like Early Start and regional centers, and insurance-specific guidance. The chat assistant runs on a scoped system prompt grounded in the child's context, with strict clinical guardrails — Claude navigates, never diagnoses. All calls use claude-sonnet-4-6. Browserbase + Stagehand handle live provider discovery. Rather than a static database, we deploy a headless browser agent that searches live directories — Psychology Today, Google Maps, and others — filtered by zip code and relevant specialty. Results are parsed, deduplicated, and cleaned before returning. A hardcoded fallback ensures the providers tab is never empty under network failure. Redis manages two data layers. Provider results are cached by zip code with a 24-hour TTL — repeated searches for the same area return instantly without re-scraping. Chat conversation history is stored per session, giving the assistant persistent memory across the full parent interaction without requiring a login. PostgreSQL via Supabase backs the clinic dashboard. All child records, roadmaps, letters, and provider results for clinic-mode users are stored as structured and JSONB data — designed for fast inserts and simple queries at hackathon scope. Flask serves as the backend, using ThreadPoolExecutor to run the Claude API call and the Browserbase scraper in parallel — cutting intake response time roughly in half. Routes are organized as registered blueprints. SQLAlchemy manages the clinic-facing data layer; a lightweight psycopg layer handles parent-mode persistence. React + Tailwind CSS power the frontend, with React Router for client-side navigation across four pages. The parent dashboard renders four tabs — Roadmap, Letters, Providers, and Chat. Session data lives in the browser for the parent flow; clinic data is fetched from the database on demand. Challenges We Ran Into For most of our team, this was a first hackathon. The transition from classroom projects to a live, high-stakes build environment was steep. Technically, Git conflicts were our most persistent friction — four people pushing code across the same codebase simultaneously taught us more about collaborative engineering in 30 hours than months of solo work. The hardest challenge, though, was the idea itself. Landing on something meaningful, feasible, and worth building — all in the first few hours — required more iteration than we anticipated. Several pivots cost us time we couldn't afford. But the exhaustion was part of it. We came out the other side with something we're proud of. Accomplishments We're Proud Of A fully integrated, end-to-end working product — intake through roadmap through providers through chat — in under 32 hours Every sponsor tool used meaningfully: remove any one and a core feature breaks A dual-mode architecture serving both individual parents and clinical teams from a single codebase The personal story behind the product, and what it could actually mean for families like ours What We Learned How to turn an idea into a working product under pressure. How to divide technical work across a team without stepping on each other. How to make real decisions fast — about scope, about pivots, about what actually matters to build. And how to ship something we're genuinely proud of. What's Next for Compass The core infrastructure is in place. The roadmap ahead is clear: Retention features — progress tracker, therapy journal, appointment prep, and an IEP hub where parents upload documents and Claude explains every section in plain language. Platform expansion — a verified provider directory with parent reviews, a provider portal where clinics list availability and accept referrals directly, and a parent community connecting families navigating the same diagnoses. B2B growth — employer benefit packages (1 in 36 children in the US is autistic; every large company has parents navigating this right now), a therapist co-pilot for clinical workflows, and school district API integrations for IEP process management. The market is real. The need is urgent. And we're just getting started.

## README (from the GitHub repository)

# 🧭 Compass

AI-powered care navigation for families of children with developmental concerns. Built for the UC Berkeley AI Hackathon (June 20–21, 2026).

## What It Does

Compass takes a 5-minute intake form and generates:

1. **Personalized action roadmap** — prioritized next steps
2. **Ready-to-send letters** — school, insurance, and regional center
3. **Local therapy providers** — scraped by zip code
4. **AI chatbot** — context-aware follow-up assistant

Two user modes: **Parent** (session-based, no login) and **Clinic** (persistent PostgreSQL storage).

## Tech Stack

| Layer | Technology |
|---|---|
| Frontend | React, React Router, Tailwind CSS, Vite |
| Backend | Flask (Python) |
| AI | Anthropic Claude (mock fallback included) |
| Scraping | Browserbase (mock fallback included) |
| Cache | Redis (in-memory fallback included) |
| Database | PostgreSQL |

## Quick Start (Local Dev)

### 1. Backend

```bash
cd backend
pip install -r requirements.txt
flask run --port 5000
```

The backend starts on http://localhost:5000. `init_db()` runs automatically on startup.

### 2. Frontend

```bash
cd frontend
npm install
npm run dev
```

The frontend starts on http://localhost:3000. API calls are proxied to the Flask backend.

### 3. Optional Services

```bash
# Redis (for provider caching + chat history)
docker run -p 6379:6379 redis
# OR: redis-server

# PostgreSQL (for clinic persistence)
createdb compass
```

**The app runs without Redis or PostgreSQL** — in-memory fallbacks are built in.

## Environment Variables

Copy `.env.example` to `.env` and fill in your keys. The app works with mock data when keys are absent.

```
ANTHROPIC_API_KEY=
BROWSERBASE_API_KEY=
BROWSERBASE_PROJECT_ID=
REDIS_URL=redis://localhost:6379
DATABASE_URL=postgresql://localhost:5432/compass
FLASK_SECRET_KEY=any-random-string-here
```

## Project Structure

```
compass/
├── CLAUDE.md
├── .env.example
├── README.md
├── backend/
│   ├── app.py                    # Flask app + all routes
│   ├── requirements.txt
│   ├── models/
│   │   └── database.py           # PostgreSQL schema + queries
│   ├── services/
│   │   ├── claude_service.py     # Anthropic API (w/ mock)
│   │   ├── browserbase_service.py # Provider scraping (w/ mock)
│   │   └── redis_service.py      # Caching + chat memory (w/ fallback)
│   └── prompts/
│       ├── roadmap_prompt.py     # Roadmap + letters system prompt
│       └── letter_prompt.py      # Chat system prompt
└── frontend/
    ├── package.json
    ├── index.html
    ├── vite.config.js
    ├── tailwind.config.js
    └── src/
        ├── main.jsx
        ├── App.jsx               # React Router (4 routes)
        ├── index.css             # Tailwind + component classes
        ├── api/
        │   └── compassApi.js     # All fetch() calls
        ├── pages/
        │   ├── LandingPage.jsx   # Parent vs Clinic CTA
        │   ├── IntakePage.jsx    # Intake form
        │   ├── DashboardPage.jsx # Parent dashboard (4 tabs)
        │   └── ClinicPage.jsx    # Clinic dashboard
        └── components/
            ├── RoadmapTab.jsx
            ├── LettersTab.jsx
            ├── ProvidersTab.jsx
            ├── ChatTab.jsx
            └── ChildRow.jsx
```


## Detected evidence (automated analysis)

Indexed codebase: 37 recognized source files, 140 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- Flask (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Redis (technology) — detected in the code
- SQL (language) — detected in the code
- Tailwind CSS (technology) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code
- PostgreSQL (technology) — claimed on Devpost, not found in the code
- Supabase (technology) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository; commit authorship or trailers

## Codebase structure (from repository index)

### Files (43 of 43)

```
.env.example
.gitignore
backend/app.py
backend/legacy_db/database.py
backend/models.py
backend/models/__init__.py
backend/models/database.py
backend/prompts/letter_prompt.py
backend/prompts/roadmap_prompt.py
backend/requirements.txt
backend/routes/__init__.py
backend/routes/chat.py
backend/routes/children.py
backend/routes/clinic.py
backend/routes/letters.py
backend/routes/roadmap.py
backend/schema.sql
backend/scrape_providers.mjs
backend/services/browserbase_service.py
backend/services/claude_service.py
backend/services/redis_service.py
CLAUDE.md
frontend/index.html
frontend/package.json
frontend/postcss.config.js
frontend/src/api/compassApi.js
frontend/src/App.jsx
frontend/src/components/ChatTab.jsx
frontend/src/components/ChildRow.jsx
frontend/src/components/Disclaimer.jsx
frontend/src/components/LettersTab.jsx
frontend/src/components/ProvidersTab.jsx
frontend/src/components/RoadmapTab.jsx
frontend/src/index.css
frontend/src/main.jsx
frontend/src/pages/ClinicPage.jsx
frontend/src/pages/DashboardPage.jsx
frontend/src/pages/IntakePage.jsx
frontend/src/pages/LandingPage.jsx
frontend/tailwind.config.js
frontend/vite.config.js
package.json
README.md
```

### Dependencies

- backend/requirements.txt: anthropic@==0.49.0, browserbase@==1.0.2, flask@==3.1.0, flask-cors@==5.0.1, flask-sqlalchemy, gunicorn@==23.0.0, psycopg[binary]@>=3.2, psycopg2-binary, python-dotenv@==1.1.0, redis@==5.2.1
- frontend/package.json: @vitejs/plugin-react@^4.3.1, autoprefixer@^10.4.20, postcss@^8.4.41, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^6.26.0, tailwindcss@^3.4.10, vite@^5.4.0
- package.json: @browserbasehq/stagehand@^3.6.0, zod@^4.4.3

### Recent commits (newest first)

- - everything works!!
- made everything faster
- - push everything
- - push everything
- - commited and added all files
- Add live Browserbase + Stagehand provider scraper for autism/mental health professionals
- - added files model.py and schema.sql
- - implemented database
- updated roadmap and dashboard page 'Compass' now blue
- roadmap now more aesthetically pleasing
- Add back buttons to all sub-pages, clean .env.example template
- changed port from 5000 to 5001, added button animations on the landing page and changed the age slider from _ months to _y _m
- update to backend and usage of claude api
- button animation on landing page and 'months' to '_y _m' on the age selection bar
- - set up roadmap, letters, and chat feature
- updated landing page
- initial commit
- @
- @
- gitignore file

## Key source files (fetched from GitHub, selected and truncated for size)

### CLAUDE.md

```markdown
# CLAUDE.md — Compass Project Context

> This file gives Claude Code full context on the Compass project. Read it before touching any code.

---

## What Is This Project?

**Compass** is an AI-powered care navigation tool with two distinct user types:

**Parents** — families of children with developmental and neurological conditions (autism, ADHD, speech delays, etc.) who fill out an intake form and receive a personalized care plan.

**Clinics** — therapy centers or care providers who use Compass as a case management tool, with a database of multiple children and their roadmaps stored persistently.

The core parent problem: when a parent suspects something is wrong with their child, they face a 6–18 month maze of specialists, therapists, insurance, school IEPs, and regional centers — with zero guidance on where to start.

Compass solves this with 4 core features generated from a 5-minute intake form:
1. A **personalized action roadmap** — prioritized next steps specific to the child's situation
2. **Ready-to-send letters** — draft letters to schools, insurance companies, and regional centers
3. **Local therapy centers** — live-scraped providers near the family's zip code
4. **AI chatbot** — context-aware follow-up assistant that knows the child's profile

This is built for the UC Berkeley AI Hackathon (June 20–21, 2026). The MVP must be demoed live on Sunday afternoon.

---

## The Two User Modes

### Parent Mode
A parent visits the app, fills out the intake form about their child, and lands on their personal dashboard with all 4 features. Their child's data lives in the Flask session (browser cookie) for the duration of the visit. No login required.

### Clinic Mode
A clinic logs in and sees a dashboard listing all children in their care, each with their own stored roadmap. Child records are persisted in PostgreSQL. The clinic can click into any child's profile and view their full roadmap, letters, providers, and chat. The clinic can also add new children via the same intake form.

These are two separate pages with separate flows. They share the same backend services (Claude, Browserbase, Redis) but differ in how data is stored and who is using them.

---

## The 4 Pages

### Page 1: Landing Page (`/`)
The entry point. Two clear calls to action:
- "I'm a parent" → goes to `/intake`
- "I'm a clinic" → goes to `/clinic`

Explains what Compass does in plain language. Shows the disclaimer. No form, no login.

### Page 2: Intake Form (`/intake`)
Parent-facing. Collects:
- Child's name
- Child's age (in months, via a slider or number input)
- Zip code
- Free-text description of concerns
- Diagnosis status: None / Suspected / Confirmed
- Diagnosis name (optional, appears only if Confirmed is selected)
- Insurance provider (optional)

On submit: POST to `/api/intake`. Shows a loading screen while Claude and Browserbase run in parallel. On completion, redirects to `/dashboard`.

### Page 3: Parent Dashboard (`/dashboard`)
Four tabs — one per core feature
[truncated — 16086 more characters]
```

### package.json

```
{
  "name": "berkeley_hackathon_proj",
  "version": "1.0.0",
  "description": "AI-powered care navigation for families of children with developmental concerns. Built for the UC Berkeley AI Hackathon (June 20–21, 2026).",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/abissi17/berkeley_hackathon_proj.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs",
  "bugs": {
    "url": "https://github.com/abissi17/berkeley_hackathon_proj/issues"
  },
  "homepage": "https://github.com/abissi17/berkeley_hackathon_proj#readme",
  "dependencies": {
    "@browserbasehq/stagehand": "^3.6.0",
    "zod": "^4.4.3"
  }
}

```

### backend/requirements.txt

```
flask==3.1.0
flask-sqlalchemy
flask-cors==5.0.1
psycopg2-binary
python-dotenv==1.1.0
anthropic==0.49.0
browserbase==1.0.2
redis==5.2.1
psycopg[binary]>=3.2
gunicorn==23.0.0

```

### frontend/package.json

```
{
  "name": "compass",
  "version": "1.0.0",
  "private": true,
  "description": "Compass — AI-powered care navigation for families",
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.26.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^4.3.1",
    "autoprefixer": "^10.4.20",
    "postcss": "^8.4.41",
    "tailwindcss": "^3.4.10",
    "vite": "^5.4.0"
  },
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

```

### backend/app.py

```python
"""
Compass — Flask backend.

AI-powered care navigation tool for parents of children with
developmental concerns and clinics managing multiple children.

Run:
    pip install -r requirements.txt
    flask run --port 5000
"""

import os
import uuid
from concurrent.futures import ThreadPoolExecutor

from dotenv import load_dotenv
from flask import Flask, request, session, jsonify
from flask_cors import CORS

# Load .env before importing services that read os.getenv
load_dotenv(verbose=False)  # searches cwd and parent dirs, finds project-root .env

from models import db
from services.claude_service import generate_roadmap, get_chat_reply
from services.browserbase_service import scrape_providers, FALLBACK_PROVIDERS
from services.redis_service import (
    get_cached_providers,
    set_cached_providers,
    get_chat_history,
    append_chat_message,
)
from models.database import init_db, save_child, get_all_children, get_child
from routes.clinic import clinic_bp
from routes.children import children_bp
from routes.roadmap import roadmap_bp
from routes.letters import letters_bp
from routes.chat import chat_bp

# ---------------------------------------------------------------------------
# App factory
# ---------------------------------------------------------------------------


def create_app() -> Flask:
    app = Flask(__name__)
    app.secret_key = os.getenv("FLASK_SECRET_KEY", "compass-dev-secret-key-change-in-production")

    # SQLAlchemy
    db_url = os.getenv("DATABASE_URL", "")
    # SQLAlchemy requires postgresql:// not postgres://
    if db_url.startswith("postgres://"):
        db_url = db_url.replace("postgres://", "postgresql://", 1)
    app.config["SQLALCHEMY_DATABASE_URI"] = db_url
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    db.init_app(app)

    # Allow frontend dev server on :3000
    CORS(app, supports_credentials=True, origins=["http://localhost:3000"])

    # Register blueprints
    app.register_blueprint(clinic_bp, url_prefix="/api/clinic")
    app.register_blueprint(children_bp, url_prefix="/api/children")
    app.register_blueprint(roadmap_bp, url_prefix="/api/roadmap")
    app.register_blueprint(letters_bp, url_prefix="/api/letters")
    app.register_blueprint(chat_bp, url_prefix="/api/chat/clinic")

    # Create SQLAlchemy tables
    with app.app_context():
        try:
            db.create_all()
            print("[db] SQLAlchemy tables created (or already exist).")
        except Exception as exc:
            print(f"[db] SQLAlchemy setup failed ({exc}) — clinic persistence disabled.")

    # --- startup: init legacy psycopg table (best-effort) ---
    try:
        init_db()
        print("[db] Legacy PostgreSQL table initialized (or already exists).")
    except Exception as exc:
        print(f"[db] Legacy PostgreSQL not available ({exc}).")

    return app


app = create_app()
executor = ThreadPoolExecutor(max_workers=4)


# ===================================================================
# POST /api/intake
# ===================================================================
@app.route("/api/intake", methods=["POST"])
def intake():
    """
    Main intake endpoint.  Accepts child's profile, runs Claude (roadmap
    + letters) and Browserbase (providers) in parallel, and returns all
    results.  Stores child data in the Flask session cookie.
    """
    data = request.get_json(silent=True) or {}

    # --- required fields ---
    child_name = data.get("child_name", "").strip()
    child_age_months = data.get("child_age_months")
    zip_code = data.get("zip_code", "").strip()
    concerns = data.get("concerns", "").strip()
    diagnosis_status = data.get("diagnosis_status", "none")
    diagnosis_name = data.get("diagnosis_name", "")
    insurance = data.get("insurance", "")
    save_to_db = data.get("save_to_db", False)

    if not child_name or child_age_months is None:
        return jsonify({"error": "child_name and child_age_months are required."}), 400

    intake_data = {
        "child_name": child_name,
        "child_age_months": int(child_age_months),
        "zip_code": zip_code,
        "concerns": concerns,
        "diagnosis_status": diagnosis_status,
        "diagnosis_name": diagnosis_name if diagnosis_status == "confirmed" else "",
        "insurance": insurance,
    }

    # --- check provider cache ---
    cached = get_cached_providers(zip_code) if zip_code else None

    # --- run Claude and Browserbase in parallel ---
    with ThreadPoolExecutor(max_workers=2) as pool:
        claude_future = pool.submit(generate_roadmap, intake_data)

        if cached:
            providers = cached
        else:
            browser_future = pool.submit(
                lambda: scrape_providers(zip_code) if zip_code else FALLBACK_PROVIDERS
            )
            providers = browser_future.result() or FALLBACK_PROVIDERS
            if zip_code and providers:
                set_cached_providers(zip_code, providers)

        roadmap = claude_future.result()

    # --- assemble response ---
    session_id = str(uuid.uuid4())
    letters = {}

    response = {
        "session_id": session_id,
        "roadmap": roadmap,
        "letters": letters,
        "providers": providers,
    }

    # --- store child in Flask session ---
    session["child"] = intake_data
    session["session_id"] = session_id

    # --- persist to PostgreSQL if clinic mode ---
    if save_to_db:
        try:
            child_id = save_child(
                {**intake_data, "roadmap": roadmap, "letters": letters, "providers": providers}
            )
            response["child_db_id"] = child_id
        except Exception as exc:
            print(f"[db] Failed to save child: {exc}")
            response["child_db_id"] = None

    return jsonify(response)


# ===================================================================
# POST /api/chat
# ===================================================================
@app.route("/api/chat", methods=["POST"])
def chat(
[truncated — 2730 more characters]
```

### frontend/src/main.jsx

```javascript
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

```

### frontend/src/App.jsx

```javascript
import { Routes, Route } from "react-router-dom";
import LandingPage from "./pages/LandingPage";
import IntakePage from "./pages/IntakePage";
import DashboardPage from "./pages/DashboardPage";
import ClinicPage from "./pages/ClinicPage";

export default function App() {
  return (
    <div className="min-h-screen">
      <Routes>
        <Route path="/" element={<LandingPage />} />
        <Route path="/intake" element={<IntakePage />} />
        <Route path="/dashboard" element={<DashboardPage />} />
        <Route path="/clinic" element={<ClinicPage />} />
      </Routes>
    </div>
  );
}

```

### frontend/postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

```

### frontend/vite.config.js

```javascript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    proxy: {
      "/api": "http://localhost:5001",
    },
  },
});

```

### frontend/tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,jsx}"],
  theme: {
    extend: {
      colors: {
        compass: {
          50: "#eff6ff",
          100: "#dbeafe",
          200: "#bfdbfe",
          300: "#93c5fd",
          400: "#60a5fa",
          500: "#3b82f6",
          600: "#2563eb",
          700: "#1d4ed8",
          800: "#1e40af",
          900: "#1e3a8a",
        },
      },
    },
  },
  plugins: [],
};

```

[28 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]