# Project export: Lighthouse: a safety net for a loved one's digital life

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: Lighthouse protects the digital life of someone whose memory is fading.It quarantines scams on its own and asks family before money ever moves. Smart enough to act, safe enough to ask.
- Devpost: https://devpost.com/software/lighthouse-ai-safety-net-for-a-loved-one-s-digital-life
- GitHub: https://github.com/ChaitanyaUppalapati/LightHouse
- Video: https://www.youtube.com/embed/C3fvp4xwbtc?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 4 GitHub contributor(s) — Claude Opus 4.8 (52 commits), chaitanyaUppalapati (37 commits), Sonakshi Panda (12 commits), keyachaudhari (9 commits)

## Devpost submission (written by the team)

### Inspiration

Everyone has someone they worry about. A parent who forwards every "you've won a prize" email. A grandparent who almost wired money to a stranger who said he was from the bank. As memory fades, the instincts that keep us safe online fade with it, and scammers know exactly who to look for. Older adults lose billions of dollars to online fraud every year, and most of it never gets reported because the people it happens to feel ashamed. The usual fixes do not fit. You cannot sit beside your mother's inbox all day. Locking her out of her own accounts takes away her independence and her dignity. We wanted something gentler: a quiet helper that stays in the background, steps in only when it should, and keeps the family in the loop without taking over a person's life.

### What it does

Lighthouse is an AI safety net for the digital life of someone who needs a little help, with their family standing behind it. It watches the incoming flow of a person's digital life and decides, case by case, what to do. It runs on one rule: safe and reversible means it acts, risky and irreversible means it asks. Every time. A phishing email is safe to handle, so Lighthouse quarantines it on its own, before it is ever seen. A demand to "pay $200 to unlock your account" is high stakes, so Lighthouse refuses to act alone. It holds the request and asks a family member, in plain language, to approve or deny it. The person being protected sees a calm, reassuring screen. No jargon, no alarms, and no off switch, because only family can change the protection. They can even ask Lighthouse a question out loud and hear a gentle answer back. The family sees a dashboard with three things: what needs a decision, what Lighthouse already handled on its own, and a complete history of everything it has done.

### How we built it

Lighthouse is a small team of cooperating agents, each with one job. A Watcher reads an incoming signal and classifies the threat. A Guardian proposes a single response, chosen only from a fixed registry of allowed actions, so it can never invent something dangerous. A deterministic safety gate routes that proposal: act, ask, or just watch. An Escalation agent turns a risky proposal into a plain question for the family and waits for the answer. An Executor carries out approved actions on real web pages the way a person would, by clicking and typing in a live browser. The agents talk to each other over Fetch.ai's uAgents and are reachable through the ASI:One chat protocol, so the whole system can be driven by an ordinary conversation. Claude does the reasoning behind the Watcher and Guardian. The Executor uses Browserbase and Stagehand to operate a real inbox and a real banking page. A FastAPI and Postgres service holds the shared state, the approval bridge between the agents and the dashboard, and an append-only, tamper-evident ledger. The family dashboard, the protected person's screen, and the mock inbox and bank are a React app. We traced and scored the agents' decisions with Arize Phoenix, and used Sentry to catch failures in the parts that touch the real world.

### Challenges we ran into

Drawing the line between act and ask so it stays predictable instead of a model's guess. We solved it with a deterministic gate and a frozen list of allowed actions, so the model proposes but the rules decide. Getting four moving parts, the agents, the gate, the backend, and the web app, to behave as one system without a single broken piece taking down the demo. We built every external call with a fallback and a demo mode, so bad wifi or a missing key never stops the story. And keeping the protected person's screen genuinely calm, with no control anywhere that could undo their safety, which took real restraint to design. Multi-agent system on Fetch.ai & ASI:One Lighthouse runs as a team of cooperating Fetch.ai uAgents, published on Agentverse and reachable through the ASI:One Chat Protocol. You can talk to the coordinator in plain language and watch the pipeline (classify, propose, gate, act) play out. Live ASI:One chat session: https://asi1.ai/shared-chat/6f328aeb-7e9c-4f34-9f62-f7ecc7e117b3 Agent profiles on Agentverse: lighthouse-ai (coordinator) lighthouse-watcher lighthouse-guardian lighthouse-executor Sponsors & integrations Claude (Anthropic) - reasoning behind the Watcher (threat classification) and Guardian (action choice). Fetch.ai / ASI:One - multi-agent orchestration over the Chat Protocol; agents published on Agentverse. ASI:One chat: https://asi1.ai/shared-chat/6f328aeb-7e9c-4f34-9f62-f7ecc7e117b3 Agents: coordinator · watcher · guardian · executor ASI:One chat: https://asi1.ai/shared-chat/6f328aeb-7e9c-4f34-9f62-f7ecc7e117b3 Agents: coordinator · watcher · guardian · executor Arize Phoenix - tracing + an LLM-as-judge evaluator. The Watcher improved from 86.7% to 93.3% on our hard adversarial email set after acting on the eval's explanations. Browserbase + Stagehand - the Executor operates the inbox and bank in a real browser. Deepgram - voice helper on Margaret's screen (speech to text + text to speech). Sentry - error capture on the data service (verified via /sentry-test).

### Accomplishments we're proud of

It works end to end. Both demo scenarios run start to finish over a real agent chat protocol with real Claude reasoning: a phishing email gets quarantined automatically, and a payment scam is held until a family member denies it. Safety is built in, not bolted on. A deterministic gate, a frozen action registry, reversible actions with undo, and a human in the loop for anything high stakes mean the system cannot quietly do harm. Every decision is accountable. Each action, request, and decision is written to a tamper-evident ledger the family can audit. Independence and protection coexist. The person keeps a calm, dignified screen with no way to disable their own safety, and the family keeps control without taking over. A real, integrated stack. Fetch.ai agents, Claude, Browserbase, Arize, and Sentry all working together, with a demo mode so nothing on stage depends on perfect conditions.

### What we learned

The hard part of an agent that touches the real world is not making it capable. It is making it know when to stop. Constraints, reversibility, and a human in the loop are not limits on the product. They are the product. Trust is the feature people actually need.

### What's next

Real email and bank connections, more kinds of signals like texts and phone calls, a fully voice-first experience for the protected person, which we have already prototyped with Deepgram, and a shareable trust report so the whole family stays informed. Lighthouse is not about replacing a person's judgment. It is about giving a worried family a way to protect someone they love without taking away that person's independence. Smart enough to act, safe enough to ask.

## README (from the GitHub repository)

# Lighthouse

A multi-agent system that quietly protects the digital life of someone whose memory is declining —
acting on safe, reversible things on its own, and asking the family before anything risky or
irreversible. Built for the UC Berkeley AI Hackathon 2026.

**One-line architecture:** signals in → agents reason → a deterministic gate decides act-alone vs
ask-a-human → real actions on real interfaces → an immutable ledger watches all of it.

See `docs/1-MASTER-PLAN.md` for the build plan and `docs/2-architecture-reference.md` for the design.

## Repo layout — one owner per folder

| Folder | Owner | What's in it |
|---|---|---|
| `pipeline/` | Chaitanya | the AI agents (Watcher / Guardian / Escalation), the deterministic safety gate, the Browserbase + Stagehand executor, Arize |
| `data/` | Keya | Postgres schema, the append-only ledger, the mock email feed, the approval bridge, Sentry |
| `web/` | Sonakshi | the family dashboard, the protected-person screen, the mock inbox & bank, the pitch |
| `lighthouse_common/` | shared | the frozen contract: `schemas.py`, `action_registry.yaml`, `demo_ids.py` |

**Only edit your own folder.** `lighthouse_common/schemas.py` and `lighthouse_common/action_registry.yaml`
are **FROZEN** — they're the shared contract; changing one breaks everyone. Ask the team first.

## Quick start

```bash
cp .env.example .env          # then paste your sponsor credit codes into .env
docker compose up -d          # start Postgres (pgvector/pgvector:pg16)
pip install -r requirements.txt
```

The `web/` track uses its own Node toolchain (`cd web && npm install && npm run dev`).


## Detected evidence (automated analysis)

Indexed codebase: 73 recognized source files, 314 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- FastAPI (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
- SQL (language) — detected in the code
- Tailwind CSS (technology) — detected in the code
- Docker (technology) — claimed on Devpost, not found in the code
- PostgreSQL (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 (81 of 81)

```
.claude/commands/handoff.md
.claude/commands/preflight.md
.claude/scripts/require-preflight.sh
.claude/settings.json
.env.example
.gitignore
0-START-HERE.md
CLAUDE.md
data/.gitkeep
data/approvals.py
data/db.py
data/gmail_feed.py
data/init_db.py
data/ledger_append_only.sql
data/ledger.py
data/main.py
data/README.md
data/requirements.txt
data/sample_emails.py
data/schema.sql
data/seed.py
data/sentry_setup.py
data/tests/__init__.py
data/tests/test_sentry.py
docker-compose.yml
docs/1-MASTER-PLAN.md
docs/2-architecture-reference.md
docs/agentverse-profiles.md
docs/asi-one-agent.md
docs/DEMOS.md
lighthouse_common/__init__.py
lighthouse_common/action_registry.yaml
lighthouse_common/demo_ids.py
lighthouse_common/schemas.py
pipeline/__init__.py
pipeline/_orch_demo_driver.py
pipeline/asi_agent.py
pipeline/chat_cli.py
pipeline/chat_web.py
pipeline/classifier.py
pipeline/demo_e2e.py
pipeline/demo_global.py
pipeline/escalation.py
pipeline/evaluator.py
pipeline/executor.py
pipeline/guardian.py
pipeline/orchestration.py
pipeline/phoenix_eval.py
pipeline/phoenix_tracing.py
pipeline/tests/__init__.py
pipeline/tests/eval_emails_hard.py
pipeline/tests/eval_emails.py
pipeline/tests/sample_assessments.py
pipeline/tests/sample_signals.py
pipeline/tests/test_classifier.py
pipeline/watcher.py
README.md
requirements.txt
web/.gitignore
web/index.html
web/package.json
web/README.md
web/src/App.jsx
web/src/components/ApprovalCard.jsx
web/src/components/HandledActionCard.jsx
web/src/components/Header.jsx
web/src/components/Icons.jsx
web/src/components/Timeline.jsx
web/src/data/bankData.js
web/src/data/fakeData.js
web/src/data/inboxData.js
web/src/index.css
web/src/lib/api.js
web/src/lib/formatTime.js
web/src/lib/voice.js
web/src/main.jsx
web/src/pages/Bank.jsx
web/src/pages/Dashboard.jsx
web/src/pages/Inbox.jsx
web/src/pages/Me.jsx
web/vite.config.js
```

### Dependencies

- data/requirements.txt: fastapi, google-api-python-client, google-auth, google-auth-oauthlib, psycopg2-binary, python-dotenv, sentry-sdk[fastapi], uagents, uvicorn
- requirements.txt: anthropic, arize-phoenix-client, arize-phoenix-evals, arize-phoenix-otel, fastapi, openinference-instrumentation-anthropic, pandas, psycopg2-binary, pydantic, python-dotenv, pyyaml, stagehand, uagents, uvicorn
- web/package.json: @tailwindcss/vite@^4.0.0, @vitejs/plugin-react@^4.3.1, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^6.26.2, tailwindcss@^4.0.0, vite@^5.4.8

### Recent commits (newest first)

- docs: Agentverse About + README copy for all four agents
- Merge ASI:One approve/deny fix via PR #16
- Fix ASI:One approve/deny: strip @mention + robust pending handling
- Merge pull request #14 from ChaitanyaUppalapati/pipeline/asi-one-agent
- asi_agent: support endpoint registration (Agentverse 'add endpoint' wizard)
- Demo prep: register all 4 agents on Agentverse + runbooks
- C7: global hero-demo driver (pipeline/demo_global.py)
- Local web chat UI (pipeline/chat_web.py)
- Interactive chat CLI (pipeline/chat_cli.py)
- Enable DEMO_MODE=0 over a tunnel: allow tunnel hosts in Vite
- docs: DEMO_MODE=0 (real computer-use) setup — Stagehand + public mock pages
- C5: fix the live Browserbase executor against the real Stagehand 3.x API
- docs: Agentverse go-live steps + which warnings are benign
- Merge web S8 voice helper on /me (Deepgram) via PR #15
- S8: fix answer routing so money questions get the money reply
- Genuine agent-to-agent orchestration (pipeline/orchestration.py)
- ASI:One end-to-end demo over the Chat Protocol (pipeline/demo_e2e.py)
- S8: voice helper on /me (stretch)
- Fetch/ASI:One coordinator agent (pipeline/asi_agent.py)
- Merge pull request #13 from ChaitanyaUppalapati/pipeline/c5-c6-executor-arize

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

### 0-START-HERE.md

```markdown
# Lighthouse team kit — start here

Files in this kit:
- `1-MASTER-PLAN.md` — THE plan. Shared timeline, all three tracks side by side, copy-paste prompts.
  Everyone reads this fully.
- `2-architecture-reference.md` — the design and the reasoning. Skim once.
- `CLAUDE.md` — rules Claude Code reads automatically. Goes in the repo root.
- `.claude/` — the preflight system (commands + the enforcement hook + settings). Goes in the repo root.

## The preflight system (so nobody builds on a broken dependency)

Two safety nets, both automatic once the `.claude/` folder is in the repo:

1. Soft: `CLAUDE.md` tells Claude Code to run `/preflight <TASK ID>` itself before starting any task,
   and `/handoff <TASK ID>` when it finishes something a teammate depends on.
2. Hard: a hook blocks code edits until `/preflight` has passed for your task. If you see
   "BLOCKED: run /preflight", that's the system working — run the check first.

You can also run them by hand anytime: `/preflight C5` before you build C5, `/handoff K4` before you
tell a teammate K4 is ready.

## Setup order
1. Chaitanya runs task C0 (creates the repo + foundation), then copies this kit's `CLAUDE.md` and
   `.claude/` folder into the repo root, and the two docs into `docs/`. Commit and push.
2. Keya and Sonakshi clone, and the preflight system is active for everyone automatically.

```

### CLAUDE.md

```markdown
# Lighthouse — Claude Code rules (read automatically every session)

You are building Lighthouse. The full plan is in `docs/1-MASTER-PLAN.md`; the design is in
`docs/2-architecture-reference.md`. You work in ONE folder (pipeline/, data/, or web/) — only edit
that folder plus your own tests. Never edit `lighthouse_common/schemas.py` or
`lighthouse_common/action_registry.yaml` — they are frozen; adapt the calling code instead.

## Automatic preflight — do this without being asked

Before starting ANY task from the plan, FIRST run the preflight check for that task:
`/preflight <TASK ID>`. Do not begin editing or creating code until preflight reports
"SAFE TO PROCEED". If preflight reports "DO NOT PROCEED YET", stop and tell me the fallback or which
teammate to message — do not work around a missing dependency.

When you finish a task that has an "UNBLOCKS:" line, run `/handoff <TASK ID>` and give me the exact
message to send the teammate. Don't tell anyone a piece is ready until handoff confirms it.

## Why edits may be blocked

A safety hook blocks Edit/Write until a fresh preflight marker exists. If you see
"BLOCKED: run /preflight", that is expected — run `/preflight <TASK ID>` first, then continue. The
hook does not gate docs or config, only source edits. If preflight passed over 90 minutes ago it goes
stale on purpose; just re-run it.

## Working rules
- Use plan mode first on every task. Show the plan before editing.
- One task at a time. Commit after each with a clear message.
- When something breaks, report the exact error and propose a fix — don't silently change unrelated files.

```

### docker-compose.yml

```yaml
# Postgres with pgvector for Lighthouse. Start with: docker compose up -d
services:
  db:
    image: pgvector/pgvector:pg16
    container_name: lighthouse-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: lighthouse
      POSTGRES_PASSWORD: lighthouse
      POSTGRES_DB: lighthouse
    ports:
      - "5432:5432"
    volumes:
      - lighthouse_pgdata:/var/lib/postgresql/data

volumes:
  lighthouse_pgdata:

```

### requirements.txt

```
# Shared Python dependencies for the pipeline/ and data/ tracks.
uagents
pydantic
anthropic
fastapi
uvicorn
psycopg2-binary
pyyaml
python-dotenv

# C5 executor — Browserbase + Stagehand (computer-use)
stagehand
# C6 — Phoenix (Arize Phoenix) tracing + Anthropic auto-instrumentation
arize-phoenix-otel
openinference-instrumentation-anthropic
# C6 — Phoenix evals + client (LLM-as-judge over traces, log annotations back)
arize-phoenix-client
arize-phoenix-evals
pandas

```

### data/requirements.txt

```
# Python deps for the data/ service. Install with:
#   pip install -r data/requirements.txt
# (The repo-root requirements.txt covers the shared deps; this adds sentry-sdk
# for K5 and pins the data service's full set so it runs standalone.)
fastapi
uvicorn
psycopg2-binary
python-dotenv
uagents
sentry-sdk[fastapi]
# K6 real Gmail feed (stretch)
google-api-python-client
google-auth
google-auth-oauthlib

```

### web/package.json

```
{
  "name": "lighthouse-web",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.26.2"
  },
  "devDependencies": {
    "@tailwindcss/vite": "^4.0.0",
    "@vitejs/plugin-react": "^4.3.1",
    "tailwindcss": "^4.0.0",
    "vite": "^5.4.8"
  }
}

```

### data/main.py

```python
"""Lighthouse data service — FastAPI app (data/ track).

K2: the mock email feed — GET /signals/next gives Chaitanya's Watcher (C1) a
real HTTP source of email Signals.
K3: the append-only ledger — POST /ledger writes an event, GET /ledger reads a
person's events newest-first. ledger_events is locked append-only at startup
(our tamper-evidence feature, arch §9).
Later tasks (K4 approval bridge, K5 Sentry) extend this app.

Run it:
    uvicorn data.main:app --port 8001      # from the repo root
    python data/main.py                    # equivalent, runs on :8001
"""

import json
import os
import sys
import uuid
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from itertools import cycle
from typing import Optional

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel

# Make the repo root importable so lighthouse_common resolves regardless of how
# the app is launched (uvicorn data.main:app, or python data/main.py).
_HERE = os.path.dirname(os.path.abspath(__file__))
_REPO_ROOT = os.path.dirname(_HERE)
for _p in (_HERE, _REPO_ROOT):
    if _p not in sys.path:
        sys.path.insert(0, _p)

from lighthouse_common.schemas import Signal          # noqa: E402
from lighthouse_common.demo_ids import MARGARET_PERSON_ID  # noqa: E402
from sample_emails import SAMPLE_EMAILS               # noqa: E402
from init_db import apply_schema                      # noqa: E402
import ledger                                         # noqa: E402
import approvals                                      # noqa: E402
from sentry_setup import init_sentry                  # noqa: E402

# K6 (real Gmail) is an optional stretch feature. Guard its import so the core
# data service still starts when the google libraries aren't installed — without
# this, a missing google dep would crash the whole service (feed, ledger,
# approvals) on the mock/demo path. None -> always use the mock feed.
try:
    import gmail_feed                                  # noqa: E402
except ImportError:
    gmail_feed = None

# Initialize Sentry before the app is created so every route is instrumented.
# No-ops if SENTRY_DSN is empty, so the app still runs without a Sentry account.
init_sentry()


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Ensure the tables exist and the ledger is locked append-only before serving.
    apply_schema()
    ledger.apply_append_only()
    yield


app = FastAPI(title="Lighthouse data service", version="0.3.0", lifespan=lifespan)

# Sonakshi's dashboard (Vite) runs on :5173 and calls this API from the browser.
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Tracks which real Gmail messages we've already served this run (read-only scope
# can't mark mail as read, so we de-dupe in memory).
_served_gmail_ids: set = set()

# Endless rotation over the built-in emails so /signals/next always returns the
# "next" one and wraps around forever.
_email_cycle = cycle(SAMPLE_EMAILS)


def _email_to_signal(email: dict) -> Signal:
    """Wrap a raw email dict as a well-formed email Signal."""
    # Drop our internal-only 'label' so the payload is just the raw email; the
    # Watcher must judge it itself, never read a pre-baked verdict.
    payload = {k: v for k, v in email.items() if k != "label"}
    return Signal(
        signal_id=str(uuid.uuid4()),
        person_id=MARGARET_PERSON_ID,
        source="email",
        payload=payload,
        observed_at=datetime.now(timezone.utc),
    )


@app.get("/")
def health():
    return {"service": "lighthouse-data", "status": "ok", "emails": len(SAMPLE_EMAILS)}


@app.get("/sentry-test")
def sentry_test():
    """Deliberately raise so Sentry captures it — confirm it lands in the dashboard."""
    raise RuntimeError(
        "Sentry test error from the Lighthouse data service. "
        "If you can see this in Sentry, error capture is working."
    )


@app.get("/signals/next")
def next_signal() -> dict:
    """Return the next fake email as a Signal (cycles through the built-in list).

    Note: the shared schemas subclass uagents.Model, which is built on pydantic
    v1; current FastAPI no longer accepts a v1 model as response_model. So we
    construct a Signal (validating against the frozen schema), then serialize it
    via pydantic's own .json() — which renders observed_at as an ISO string —
    and return a plain JSON-ready dict.
    """
    # Prefer a real unread Gmail message (K6); fall back to the mock list so the
    # feed never breaks if Gmail/OAuth is unavailable or the inbox is empty.
    signal = None
    if gmail_feed is not None and gmail_feed.has_token():
        try:
            signal = gmail_feed.next_unread_signal(_served_gmail_ids)
        except Exception as exc:  # noqa: BLE001 — any Gmail hiccup -> use the mock
            print(f"[gmail] falling back to mock feed: {exc}")
    if signal is None:
        signal = _email_to_signal(next(_email_cycle))

    # Persist the signal so a later ThreatAssessment can reference it (FK seam).
    ledger.save_signal(
        signal.signal_id,
        signal.person_id,
        signal.source,
        signal.payload,
        signal.observed_at,
    )
    return json.loads(signal.json())


# --- Ledger (K3) --------------------------------------------------------------
# The immutable audit trail (arch §9). Every meaningful thing Lighthouse does is
# appended here; the table is locked append-only at startup so history cannot be
# rewritten. This is a local request model (pydantic v2) — unrelated to the
# frozen uagents schemas.

class LedgerEventIn(BaseModel):
    event_type: str
    details: dict = {}
    person_id: Optional[str] = None


@app.post("/ledger")
def post_ledger(event: LedgerEventIn) -> dict:
    """Append an event to the immutable ledger and return the stored row."""
    retu
[truncated — 2371 more characters]
```

### web/src/App.jsx

```javascript
import { Outlet } from "react-router-dom";

// App shell. Pages render through <Outlet />. Kept thin so each web task owns its own page.
export default function App() {
  return (
    <div className="min-h-screen">
      <Outlet />
    </div>
  );
}

```

### web/src/main.jsx

```javascript
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App.jsx";
import Dashboard from "./pages/Dashboard.jsx";
import Me from "./pages/Me.jsx";
import Inbox from "./pages/Inbox.jsx";
import Bank from "./pages/Bank.jsx";
import "./index.css";

// Routing is set up now so later web tasks (S3 /me, S4 /inbox, S5 /bank) just add routes.
ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <BrowserRouter
      future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
    >
      <Routes>
        <Route path="/" element={<App />}>
          <Route index element={<Dashboard />} />
          <Route path="me" element={<Me />} />
          <Route path="inbox" element={<Inbox />} />
          <Route path="bank" element={<Bank />} />
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

```

### lighthouse_common/__init__.py

```python
"""Lighthouse shared contract: schemas, action registry, and demo identities."""

```

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