# Project export: Edamame

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: TreeHacks 2026
- Tagline: AI Clones for Organizational Memory
- Devpost: https://devpost.com/software/m-4f2iwy
- GitHub: https://github.com/angelinaquan/edamame-treehacks/
- Demo: https://drive.google.com/file/d/1PlhW212AV7tgrNrOqIA84g8R1kn03D-o/view?usp=sharing
- Video: https://www.youtube.com/embed/6HlN98ilkzc?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner ([Greylock] Best multi-turn agent (Courtside tickets to Warriors game ($10k value) Office hours with Greylock Partners))
- Team: 5 GitHub contributor(s) — James Liu (30 commits), Angelina Quan (29 commits), Cursor (21 commits), Videet Mehta (6 commits), lalala-e (1 commits)

## Devpost submission (written by the team)

### Inspiration

Organizations lose institutional knowledge every day. When someone leaves, years of context walk out the door. When someone joins, they spend weeks piecing together tribal knowledge scattered across Slack, Drive, email, and a dozen other tools. We wanted to build a system that creates digital twin clones of every person in your organization, so their knowledge is always accessible — even when they're not. We see Edamame becoming a simpler database for companies, where the AI clones and knowledge bases can simplify finding information like the reasoning behind past product decisions and the context that normally lives only in people’s heads. Instead of searching across fragmented tools or tracking down the right person, you can simply ask, and the system returns the exact answer with the full context behind it.

### What it does

Edamame creates AI clones of every employee by ingesting their Slack messages, Google Drive docs, Gmail threads, GitHub commits, Notion pages, and Jira tickets. Each clone becomes a queryable digital twin that answers questions grounded in real data with source citations. Clones learn continuously -- every new message, conversation, and document gets absorbed in real-time. It has 4 main features: Clone Chat: Talk to anyone's digital twin in text or voice. Each clone has a distinct personality modeled after its person. A live memory panel shows facts being extracted and stored as you talk. Management Insights: Ask a strategic question and Edamame polls every clone simultaneously, generates per-person stances with confidence scores and evidence, then aggregates into themes. An animated agent network shows the multi-clone query in real-time. Onboarding Briefs: Auto-generates "here's what you need to know" docs for new hires by querying relevant clones for key people, recent decisions, and open risks. Offboarding Handoff Packs: When someone leaves, their clone preserves their knowledge -- ownership areas, unresolved work, key links, and suggested new owners. Additional features: Full voice I/O using Whisper transcription and TTS synthesis Real-time Slack webhook -- clones learn new messages as they're sent Semantic memory search across all data sources Real OAuth integrations with Slack, Google Drive, Gmail, GitHub, and Notion

### How we built it

Frontend: Next.js 16 with React 19 and TypeScript, paired with Tailwind CSS for a Cursor-inspired dark theme. Agent network visualization uses animated SVG particles on bezier curves. Clone Memory: Supabase with pgvector. Unified memories table with type discriminators and source tags. IVFFlat indexing for sub-50ms semantic search. Clone Intelligence: GPT-5.3 with personality-aware system prompts. text-embedding-3-small for embeddings. Continual learning extracts facts from every conversation. Voice: Whisper for transcription, TTS for synthesis. Full spoken conversation with any clone. Integrations: Real OAuth to Slack, Google Drive, Gmail, GitHub, Notion. Live data sync with token refresh.

### Challenges we ran into

Making clones sound like distinct people, not generic chatbots Supabase connection limits when querying all clones simultaneously for CEO insights Embedding dimension bug at 3am (3072-d instead of 1536-d -- slower AND less accurate) Silent OAuth token expiry causing clones to "forget" GDrive knowledge mid-demo

### Accomplishments we're proud of

Built fully functional AI clones with real integrations, voice I/O, and continual learning in 12 hours Every clone response is grounded with source citations -- no hallucination Continual learning works live: send a Slack message, ask the clone seconds later, get a cited answer All integrations use real OAuth, not mocked data Code from every abandoned pivot shipped in the final product

### What we learned

Personality modeling matters as much as retrieval quality for making clones feel real Real-time webhook learning is what makes a clone feel "alive" vs. static RAG Scope management is one of the hardest hackathon skills

### What's next

for Me Enterprise Deployment: Multi-tenant isolation, SSO/SAML, role-based clone access control Smarter Clones: Temporal reasoning, cross-clone knowledge graphs, clone-to-clone consultation More Integrations: Calendar, meeting transcripts, Linear, Figma, etc. Our futuristic vision: notion-like database for company knowledge, but better :)

## README (from the GitHub repository)

# Edamame

AI clones for organizational memory. Edamame ingests knowledge from Slack, Google Drive, Gmail, GitHub, Notion, and Jira to create digital twin clones of every person in your organization - queryable 24/7 in text or voice, with source citations and continual learning.

Built at TreeHacks 2026. 

<img width="1512" height="855" alt="chat" src="https://github.com/user-attachments/assets/0be5aa11-bf84-48e1-abbd-88df2c087a38" />

## Features

- **Clone Chat** — Talk to any employee's digital twin in text or voice. Personality-aware responses with inline source citations. Clones learn from every conversation via fact extraction and episodic memory.
- **CEO Insights** — Multi-clone sentiment analysis. Ask a strategic question and poll all clones simultaneously for per-person stances, confidence scores, and aggregated themes. Animated agent network visualization shows the query in real-time.
- **Onboarding Briefs** — Auto-generated "here's what you need to know" docs for new hires: key people, recent decisions, open risks.
- **Offboarding Handoff Packs** — When someone leaves, their clone generates ownership areas, unresolved work, key links, and suggested new owners.
- **Knowledge Base** — Semantic search across all ingested memories with source and type filtering.
- **Clone-to-Clone Consultation** — When a clone doesn't know something, it consults other clones via an agent-to-agent protocol.
- **Voice I/O** — Full spoken conversations with clones using Whisper (STT) and OpenAI TTS.
- **Real-time Slack Learning** — Webhook-driven ingestion. Clones absorb new Slack messages as they're sent.
- **Synthetic Data Generation** — Seeded deterministic generator creates realistic Slack messages, Drive docs, GitHub commits, emails, Jira tickets, and Notion pages for demos.

## Architecture

```
├── frontend/              Next.js 16 app (UI + API routes)
│   ├── app/               Pages and API routes
│   │   ├── page.tsx       Landing / auth page
│   │   ├── ceo/           CEO view (insights, clones, knowledge)
│   │   ├── employee/      Employee view (chat, coworkers, knowledge)
│   │   ├── (app)/         Dashboard, settings, clone management
│   │   └── api/
│   │       ├── edamame/  Clone chat, insights, onboarding, offboarding
│   │       ├── chat/      General chat endpoint
│   │       ├── voice/     Whisper transcription + TTS synthesis
│   │       ├── ingest/    Data ingestion + synthetic generation
│   │       ├── memory/    Memory search + compaction
│   │       ├── clones/    Clone CRUD
│   │       ├── slack/     Slack OAuth, sync, webhook events
│   │       ├── google-drive/ Drive sync
│   │       ├── gmail/     Gmail sync
│   │       ├── github/    GitHub sync
│   │       ├── notion/    Notion sync
│   │       └── auth/      Google OAuth flow
│   ├── components/
│   │   ├── edamame/      InsightsView, ClonesView, EmployeeChatView,
│   │   │                  KnowledgeView, AgentNetworkView, Sidebars
│   │   ├── chat/          ChatWindow, MessageBubble, ThinkingPanel
│   │   ├── voice/         VoiceButton, Waveform
│   │   ├── dashboard/     CloneGrid, CloneCard, ConversationLog
│   │   └── clone-builder/ PersonalityForm, DocumentUpload
│   └── lib/
│       ├── agents/        OpenAI client, clone-brain prompting,
│       │                  collaboration (clone-to-clone), Perplexity
│       ├── core/          Types, Supabase client, chunker, utils
│       ├── integrations/  Slack, Google, GitHub, Notion connectors
│       ├── memory/        Frontend memory search helpers
│       └── edamame/      Edamame API client + types
├── backend/
│   ├── memory/            Memory system: retrieval, compaction,
│   │   │                  continual learning, episodic extraction
│   │   └── synthetic/     Synthetic data generators (Slack, Drive,
│   │                      email, GitHub, Jira, Notion, world builder)
│   ├── modal/             Python modules for Modal deployment
│   │                      (agent, embed, STT, TTS)
│   └── supabase/          SQL schema + migrations
└── synthetic_corpus/      Pre-generated demo data
```

## Tech Stack

| Layer | Technology |
|-------|-----------|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS |
| Database | Supabase (PostgreSQL + pgvector) |
| LLM | OpenAI GPT-4o |
| Embeddings | text-embedding-3-small (1536-d), IVFFlat indexing |
| Voice | Whisper-1 (STT), TTS-1 with Nova voice |
| Integrations | Slack API, Google OAuth (Drive + Gmail), Octokit (GitHub), Notion API |
| ML Infra | Modal (optional, for hosted inference) |
| Memory | Supabase (primary), Mem0 (optional fallback) |

## Prerequisites

- Node.js 20+
- npm
- Supabase project with pgvector extension
- OpenAI API key
- Python 3.11+ (only for `backend/modal/`)

## Quick Start

### 1. Install dependencies

```bash
cd frontend
npm install
```

### 2. Configure environment

Copy `.env.example` to `frontend/.env.local` and fill in your keys (OpenAI, Supabase, and optionally Google OAuth, Slack, GitHub, Notion).

### 3. Initialize database

Run `backend/supabase/schema.sql` in your Supabase SQL editor. This creates:

- `clones` — One per person, includes personality and expertise tags
- `memories` — Unified knowledge store with type discriminators (`document`, `chunk`, `fact`, `snapshot`, `category`, `episodic`) and source tags (`slack`, `gdrive`, `email`, `github`, `notion`, `jira`, `voice`, `conversation`)
- `messages` — Flat chat history grouped by conversation
- `integrations` — OAuth credentials and sync config
- `match_memories` — pgvector cosine similarity search function

If migrating from an older schema, use `backend/supabase/migrate.sql` instead.

### 4. Run the app

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

Open [http://localhost:3000](http://localhost:3000).

### 5. (Optional) Generate synthetic data

Hit `POST /api/ingest/synthetic` with a clone ID to populate a clone with realistic demo data across all sources.

## How Memory Works

All clone knowledge lives in a single `memories` table:

1. **Ingestion** — Data from Slack, Drive, Gmail, GitHub, Notion, Jira is synced and chunked (500-token segments with 50-token overlap)
2. **Embedding** — Each chunk/fact gets a 1536-d embedding via `text-embedding-3-small`
3. **Retrieval** — Semantic vector search via `match_memories` RPC with keyword fallback. Results are re-ranked using a composite score: `similarity + recencyBonus(occurred_at)`
4. **Continual Learning** — Conversations trigger fact extraction and episodic memory extraction. Near-duplicates (similarity > 0.88) are reinforced instead of duplicated
5. **Compaction** — Weekly summarization rolls up stale facts into category summaries. Monthly rewind creates snapshots

## Scripts

From `frontend/`:

| Command | Description |
|---------|-------------|
| `npm run dev` | Start dev server |
| `npm run build` | Production build |
| `npm run start` | Run production server |
| `npm run lint` | Run ESLint |

## Modal (Python Backend)

`backend/modal/` contains optional Python modules for Modal-hosted inference:

- `agent.py` — Clone reasoning
- `embed.py` — Embedding generation
- `stt.py` — Speech-to-text
- `tts.py` — Text-to-speech
- `multi_agent.py` — Multi-agent orchestration

Set `MODAL_BASE_URL` in your env to point to the deployed Modal service.

```bash
cd backend/modal
pip install -r requirements.txt
```


## Detected evidence (automated analysis)

Indexed codebase: 119 recognized source files, 844 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- PostgreSQL (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- Supabase (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Vercel AI SDK (technology) — detected in the code
- AI coding agent: Cursor — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (120 of 127)

```
.cursorignore
.gitignore
backend/memory/clone-repository.ts
backend/memory/flags.ts
backend/memory/index.ts
backend/memory/mem0.ts
backend/memory/mock-data.ts
backend/memory/synthetic/context.ts
backend/memory/synthetic/email.ts
backend/memory/synthetic/gdrive.ts
backend/memory/synthetic/github.ts
backend/memory/synthetic/index.ts
backend/memory/synthetic/jira.ts
backend/memory/synthetic/notion.ts
backend/memory/synthetic/random.ts
backend/memory/synthetic/slack.ts
backend/memory/synthetic/validate.ts
backend/modal/agent.py
backend/modal/app.py
backend/modal/embed.py
backend/modal/multi_agent.py
backend/modal/requirements.txt
backend/modal/stt.py
backend/modal/tts.py
backend/supabase/migrate.sql
backend/supabase/schema.sql
docs/index.html
frontend/app/(app)/clones/[id]/page.tsx
frontend/app/(app)/clones/[id]/train/page.tsx
frontend/app/(app)/clones/page.tsx
frontend/app/(app)/dashboard/page.tsx
frontend/app/(app)/layout.tsx
frontend/app/(app)/my-clone/page.tsx
frontend/app/(app)/settings/page.tsx
frontend/app/api/auth/google/callback/route.ts
frontend/app/api/auth/google/route.ts
frontend/app/api/chat/route.ts
frontend/app/api/clones/[id]/route.ts
frontend/app/api/clones/route.ts
frontend/app/api/edamame/chat/route.ts
frontend/app/api/edamame/clones/route.ts
frontend/app/api/edamame/documents/route.ts
frontend/app/api/edamame/insights/route.ts
frontend/app/api/edamame/offboarding/route.ts
frontend/app/api/edamame/onboarding/route.ts
frontend/app/api/github/sync/route.ts
frontend/app/api/gmail/sync/route.ts
frontend/app/api/google-drive/sync/route.ts
frontend/app/api/ingest/route.ts
frontend/app/api/ingest/synthetic/route.ts
frontend/app/api/ingest/synthetic/smoke/route.ts
frontend/app/api/integrations/route.ts
frontend/app/api/meetings/transcribe-save/route.ts
frontend/app/api/memory/compact/route.ts
frontend/app/api/memory/recent/route.ts
frontend/app/api/notion/sync/route.ts
frontend/app/api/slack/callback/route.ts
frontend/app/api/slack/connect/route.ts
frontend/app/api/slack/events/route.ts
frontend/app/api/slack/sync/route.ts
frontend/app/api/voice/synthesize/route.ts
frontend/app/api/voice/transcribe/route.ts
frontend/app/auth/complete/page.tsx
frontend/app/ceo/page.tsx
frontend/app/employee/page.tsx
frontend/app/globals.css
frontend/app/layout.tsx
frontend/app/page.tsx
frontend/components/chat/ChatInput.tsx
frontend/components/chat/ChatWindow.tsx
frontend/components/chat/CollaborationPanel.tsx
frontend/components/chat/MeetingCard.tsx
frontend/components/chat/MessageBubble.tsx
frontend/components/chat/NotificationBanner.tsx
frontend/components/chat/PersonCard.tsx
frontend/components/chat/ThinkingPanel.tsx
frontend/components/clone-builder/DocumentUpload.tsx
frontend/components/clone-builder/PersonalityForm.tsx
frontend/components/dashboard/CloneCard.tsx
frontend/components/dashboard/CloneGrid.tsx
frontend/components/dashboard/ConversationLog.tsx
frontend/components/edamame/AgentNetworkView.tsx
frontend/components/edamame/CeoSidebar.tsx
frontend/components/edamame/ClonesView.tsx
frontend/components/edamame/EmployeeChatView.tsx
frontend/components/edamame/EmployeeSidebar.tsx
frontend/components/edamame/InsightsView.tsx
frontend/components/edamame/KnowledgeView.tsx
frontend/components/edamame/Sidebar.tsx
frontend/components/layout/Header.tsx
frontend/components/layout/Sidebar.tsx
frontend/components/meetings/MeetingRecorder.tsx
frontend/components/voice/VoiceButton.tsx
frontend/components/voice/Waveform.tsx
frontend/eslint.config.mjs
frontend/lib/agents/clone-brain.ts
frontend/lib/agents/collaboration.ts
frontend/lib/agents/index.ts
frontend/lib/agents/modal.ts
frontend/lib/agents/openai.ts
frontend/lib/agents/perplexity.ts
frontend/lib/core/chunker.ts
frontend/lib/core/index.ts
frontend/lib/core/supabase/client.ts
frontend/lib/core/supabase/server.ts
frontend/lib/core/types.ts
frontend/lib/core/utils.ts
frontend/lib/echo/mock-data.ts
frontend/lib/edamame/api.ts
frontend/lib/edamame/types.ts
frontend/lib/integrations/credentials.ts
frontend/lib/integrations/github.ts
frontend/lib/integrations/google.ts
frontend/lib/integrations/index.ts
frontend/lib/integrations/notion.ts
frontend/lib/integrations/slack.ts
frontend/lib/memory/index.ts
frontend/lib/memory/meeting.ts
frontend/lib/memory/mock-data.ts
frontend/lib/memory/search.ts
[7 more files omitted for size]
```

### Dependencies

- backend/modal/requirements.txt: anthropic, modal, numpy, openai
- frontend/package.json: @notionhq/client@^5.9.0, @octokit/rest@^22.0.1, @supabase/supabase-js@^2.95.3, @tailwindcss/postcss@^4, @types/node@^20, @types/react@^19, @types/react-dom@^19, ai@^6.0.86, class-variance-authority@^0.7.1, clsx@^2.1.1, dotenv@^17.3.1, eslint@^9, eslint-config-next@16.1.6, googleapis@^171.4.0, lucide-react@^0.564.0, next@16.1.6, openai@^6.22.0, pg@^8.18.0, react@19.2.3, react-dom@19.2.3, react-markdown@^10.1.0, tailwind-merge@^3.4.0, tailwindcss@^4, typescript@^5

### Recent commits (newest first)

- Remove GitHub Pages custom domain
- Create CNAME
- Update GitHub Pages custom domain
- docs: add CNAME for edamame-agent.com (GitHub Pages custom domain)
- README: restore intro before project-site and Devpost edits
- Remove docs README (keep README project site note only)
- docs: note where short Pages URL is published from
- README: project site URL uses short edamame Pages path
- README: project site URL after repo rename to edamame-treehacks
- project website
- Remove "built in 12 hours" from tech section heading
- Add static project site for GitHub Pages
- Update README.md
- renaming everything to edamame
- update README
- .
- data quality fix
- .
- rename
- new data aggregation pipeline

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

### package.json

```
{
  "name": "ai-clone-treehacks-root",
  "private": true,
  "scripts": {
    "dev": "npm --prefix frontend run dev",
    "build": "npm --prefix frontend run build",
    "start": "npm --prefix frontend run start",
    "lint": "npm --prefix frontend run lint",
    "install:frontend": "npm --prefix frontend install"
  }
}

```

### frontend/package.json

```
{
  "name": "ai-clone",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  },
  "dependencies": {
    "@notionhq/client": "^5.9.0",
    "@octokit/rest": "^22.0.1",
    "@supabase/supabase-js": "^2.95.3",
    "ai": "^6.0.86",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "googleapis": "^171.4.0",
    "lucide-react": "^0.564.0",
    "next": "16.1.6",
    "openai": "^6.22.0",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "react-markdown": "^10.1.0",
    "tailwind-merge": "^3.4.0"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "dotenv": "^17.3.1",
    "eslint": "^9",
    "eslint-config-next": "16.1.6",
    "pg": "^8.18.0",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}

```

### backend/modal/requirements.txt

```
modal
anthropic
openai
numpy

```

### backend/modal/app.py

```python
"""Modal app configuration for AI Clone Platform."""
import modal

app = modal.App("ai-clone-platform")

image = modal.Image.debian_slim(python_version="3.11").pip_install(
    "anthropic",
    "openai",
    "numpy",
)

```

### frontend/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Edamame — Organizational Intelligence",
  description:
    "Multi-agent population queries and institutional memory for modern organizations.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        {children}
      </body>
    </html>
  );
}

```

### frontend/app/page.tsx

```typescript
"use client";

import { useState, type FormEvent } from "react";
import { Sparkles, Loader2 } from "lucide-react";

const CEO_EMAIL = "ceo@gmail.com";

const EMAIL_TO_CLONE: Record<string, string> = {
  "ella2happy@gmail.com": "Ella Lan",
  "mvideet@gmail.com": "Videet Mehta",
  "angelinaquan2024@gmail.com": "Angelina Quan",
  "jamesliu535b@gmail.com": "James Liu",
};

function GoogleIcon() {
  return (
    <svg width="18" height="18" viewBox="0 0 48 48">
      <path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" />
      <path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" />
      <path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z" />
      <path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" />
    </svg>
  );
}

export default function LandingPage() {
  const [email, setEmail] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const handleSubmit = (e: FormEvent) => {
    e.preventDefault();
    const trimmed = email.trim().toLowerCase();
    if (!trimmed || !trimmed.includes("@")) {
      setError("Please enter a valid email address.");
      return;
    }
    setError("");
    setLoading(true);
    sessionStorage.setItem("edamame_email", trimmed);
    sessionStorage.setItem("edamame_clone_name", EMAIL_TO_CLONE[trimmed] || "");
    window.location.href = trimmed === CEO_EMAIL ? "/ceo" : "/employee";
  };

  const handleGoogleAuth = () => {
    setLoading(true);
    window.location.href = "/api/auth/google";
  };

  return (
    <div className="flex min-h-screen items-center justify-center bg-[#111113]">
      <div className="w-full max-w-[420px] px-4">
        {/* Card */}
        <div className="rounded-2xl border border-[#2a2a2e] bg-[#19191d] px-8 pb-8 pt-10">
          {/* Logo icon */}
          <div className="mb-6 flex justify-center">
            <div className="flex h-10 w-10 items-center justify-center rounded-xl bg-emerald-600 text-white">
              <Sparkles size={20} />
            </div>
          </div>

          {/* Title */}
          <h1 className="mb-1.5 text-center text-[20px] font-semibold text-white">
            Sign in to Edamame
          </h1>
          <p className="mb-7 text-center text-[14px] text-[#888]">
            Enter your email to continue.
          </p>

          {/* Email input */}
          <form onSubmit={handleSubmit} className="mb-4">
            <input
              type="email"
              value={email}
              onChange={(e) => {
                setEmail(e.target.value);
                setError("");
              }}
              placeholder="Business email*"
              autoFocus
              className="mb-3 w-full rounded-lg border border-[#2a2a2e] bg-[#111113] px-4 py-3 text-[14px] text-white placeholder:text-[#555] focus:border-[#444] focus:outline-none"
            />
            {error && (
              <p className="mb-2 text-[12px] text-red-400">{error}</p>
            )}
            <button
              type="submit"
              disabled={loading}
              className="flex w-full items-center justify-center gap-2 rounded-lg bg-white px-4 py-3 text-[14px] font-semibold text-black transition-colors hover:bg-[#e8e8e8] disabled:opacity-50"
            >
              {loading ? (
                <Loader2 size={16} className="animate-spin" />
              ) : (
                "Continue"
              )}
            </button>
          </form>

          {/* Divider */}
          <div className="mb-4 flex items-center gap-3">
            <div className="h-px flex-1 bg-[#2a2a2e]" />
            <span className="text-[12px] font-medium text-[#555]">OR</span>
            <div className="h-px flex-1 bg-[#2a2a2e]" />
          </div>

          {/* Google auth */}
          <button
            onClick={handleGoogleAuth}
            disabled={loading}
            className="flex w-full items-center justify-center gap-3 rounded-lg border border-[#2a2a2e] bg-transparent px-4 py-3 text-[14px] font-medium text-[#ccc] transition-colors hover:border-[#444] hover:text-white disabled:opacity-50"
          >
            <GoogleIcon />
            Continue with Google
          </button>
        </div>
      </div>
    </div>
  );
}

```

### frontend/lib/core/index.ts

```typescript
/**
 * Core — shared utilities, types, and database client.
 * NO domain logic. All layers depend on core.
 */

export { createServerSupabaseClient } from "./supabase/server";
export { supabase } from "./supabase/client";
export { chunkText, type ChunkResult } from "./chunker";
export { cn } from "./utils";

// Re-export all types
export * from "./types";

```

### frontend/app/(app)/layout.tsx

```typescript
"use client";

import { Sidebar } from "@/components/layout/Sidebar";
import { Header } from "@/components/layout/Header";

export default function AppLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex h-screen">
      <Sidebar />
      <div className="flex flex-1 flex-col overflow-hidden">
        <Header />
        <main className="flex-1 overflow-y-auto">{children}</main>
      </div>
    </div>
  );
}

```

### frontend/lib/memory/index.ts

```typescript
/**
 * Memory — organizational knowledge storage and retrieval.
 * Manages documents, chunks, and memories in Supabase.
 * Depends on: core/
 * Independent of: integrations/, agents/
 */

export {
  searchKnowledgeBase,
  searchKnowledgeBaseAsync,
  getCloneMemories,
  extractFacts,
  saveFact,
} from "./search";

// Mock data (used by agents for demo mode)
export {
  mockPeople,
  mockClones,
  mockMeetings,
  mockDocuments,
  mockSlackMessages,
  mockMemories,
  mockReminders,
  getCloneById,
  getCloneByName,
  getPersonByUserId,
  getMeetingById,
  getActiveReminders,
  getCloneForUser,
} from "./mock-data";

```

### frontend/lib/agents/index.ts

```typescript
/**
 * Agents — clone brain, collaboration, and LLM communication.
 * Handles AI reasoning, tool calling, and clone-to-clone consultation.
 * Depends on: core/, memory/
 * Independent of: integrations/
 */

// Clone brain (system prompt, reasoning)
export {
  buildSystemPrompt,
  formatMessagesForAPI,
  findRelevantClone,
} from "./clone-brain";

// Clone collaboration
export {
  findCloneByExpertise,
  findCloneByName,
  canConsult,
  consultClone,
} from "./collaboration";

// OpenAI utilities
export { default as getOpenAIClient } from "./openai";
export {
  transcribeAudio,
  synthesizeSpeech,
  generateEmbedding,
} from "./openai";

// Modal backend calls
export {
  callModalEndpoint,
  runCloneBrain,
  embedText,
  transcribeAudioModal,
  synthesizeSpeechModal,
} from "./modal";

// Web search
export {
  searchWeb,
} from "./perplexity";

```

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