# Project export: Zero.to

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 2025
- Tagline: From chaos to clarity: your AI workspace for going from idea to launch.
- Devpost: https://devpost.com/software/zero-to-l0f54w
- GitHub: https://github.com/Zalinto/startup-hacks
- Demo: https://github.com/Zalinto/startup-hacks-server
- Video: https://www.youtube.com/embed/OhJy_94jN4I?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Pranav Nutalapati (29 commits), Jeff Zhang (7 commits), Zalinto (3 commits)

## Devpost submission (written by the team)

### Inspiration

In the fast-moving startup world, we noticed a growing number of "vibe coders" — builders who jump straight into shipping without structure, validation, or planning. While this creative energy is powerful, it often results in scattered execution, missed market opportunities, and burnout. We wanted to create something that empowers both technical and non-technical users to move from idea to execution — without needing a team of consultants, planners, or marketers. That’s where Code Zeroto was born. What We Built Code Zeroto is a multimodal AI workspace that uses agent-based orchestration to guide users through the startup lifecycle: Brainstorming and Idea Validation with LLM agents Technical Planning via auto-generated SDLC and PRD documents Outreach Automation with script, video, and email generation Campaign Management with analytics, voice support, and follow-up tracking Whether you’re a solo developer, a business major with an idea, or a founder with no AI knowledge — Code Zeroto is your co-pilot from zero to launch. How We Built It Frontend: Next.js Tailwind CSS ShadCN for UI components and analytics graphs Backend: Nest.js Supabase (auth + database) Clerk for authentication (Google SSO) Agentic Orchestration: Letta Cloud for master orchestration Fetch.ai for per-user agent execution (clarifier, SWOT, outreach, etc.) Memory Blocks to track conversations and user sessions Vapi for real-time voice interaction RAG pipelines for grounding chatbot responses with company/user data Models Used: Groq for fast inference Claude 4 for reasoning and code generation Gemini API, LLaMA, and Veo 2 for video generation LMNT + Vapi for voice synthesis Supporting Tools: Inspectmind: turns images into structured notes and reports Resend API for email automation RAG-over-uploaded FAQ PDFs for contextual chat Challenges We Faced Orchestrating multiple agents with memory while maintaining user context Integrating voice with real-time LLM streaming responses Creating a user-friendly experience that hides complexity behind helpful interactions Designing a smooth flow between ideation, planning, and outreach Balancing AI capabilities with user trust and education What We Learned How to build composable, multi-agent systems using Letta and Fetch.ai Best practices for building voice-based agents with Vapi Structuring user feedback and marketing campaigns using AI-generated content Designing intuitive UX for users unfamiliar with startup planning tools Creating scalable memory and RAG pipelines for agent personalization What’s Next Deeper Inspectmind integration for campaign and analytics reports Support for additional startup types (non-profit, creator tools, SaaS, etc.) Smarter onboarding with educational prompts and in-context help Scaling the platform into a fully self-serve workspace for early-stage builders

## README (from the GitHub repository)

# Startup Hacks Frontend

### Local Setup

1. `npm i`
2. Copy `.env.example` to `.env` and populate the variables.


## Detected evidence (automated analysis)

Indexed codebase: 67 recognized source files, 185 KB.
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Supabase (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (73 of 73)

```
.env.example
.gitignore
app/(public)/landing/CTA.tsx
app/(public)/landing/Features.tsx
app/(public)/landing/Footer.tsx
app/(public)/landing/Hero.tsx
app/(public)/landing/Problem.tsx
app/(public)/landing/Solution.tsx
app/(public)/layout.tsx
app/(public)/page.tsx
app/constants.ts
app/dashboard/layout.tsx
app/dashboard/page.tsx
app/dashboard/projects/[id]/brainstorming/components/chat.tsx
app/dashboard/projects/[id]/brainstorming/components/summary.tsx
app/dashboard/projects/[id]/brainstorming/page.tsx
app/dashboard/projects/[id]/brainstorming/templates/prd.tsx
app/dashboard/projects/[id]/brainstorming/templates/style-guide.tsx
app/dashboard/projects/[id]/hooks.tsx
app/dashboard/projects/[id]/outreach/[campaignId]/hooks.ts
app/dashboard/projects/[id]/outreach/[campaignId]/page.tsx
app/dashboard/projects/[id]/outreach/[campaignId]/queries.ts
app/dashboard/projects/[id]/outreach/[campaignId]/types/email.tsx
app/dashboard/projects/[id]/outreach/[campaignId]/types/pitchdeck.tsx
app/dashboard/projects/[id]/outreach/[campaignId]/types/video.tsx
app/dashboard/projects/[id]/outreach/components/ctr.tsx
app/dashboard/projects/[id]/outreach/components/impressions.tsx
app/dashboard/projects/[id]/outreach/page.tsx
app/dashboard/projects/[id]/outreach/queries.ts
app/dashboard/projects/[id]/page.tsx
app/dashboard/projects/[id]/queries.ts
app/dashboard/projects/[id]/support/page.tsx
app/dashboard/projects/page.tsx
app/dashboard/queries.ts
app/globals.css
app/layout.tsx
app/providers.tsx
components.json
components/app-sidebar.tsx
components/magicui/hero-video-dialog.tsx
components/magicui/particles.tsx
components/magicui/safari.tsx
components/ui/alert-dialog.tsx
components/ui/badge.tsx
components/ui/breadcrumb.tsx
components/ui/button.tsx
components/ui/card.tsx
components/ui/chart.tsx
components/ui/dialog.tsx
components/ui/form.tsx
components/ui/icon-select.tsx
components/ui/input.tsx
components/ui/label.tsx
components/ui/page-header.tsx
components/ui/section.tsx
components/ui/separator.tsx
components/ui/sheet.tsx
components/ui/sidebar.tsx
components/ui/skeleton.tsx
components/ui/sonner.tsx
components/ui/table.tsx
components/ui/tooltip.tsx
components/ui/wysiwyg-editor.tsx
hooks/use-mobile.ts
lib/utils.ts
middleware.ts
next.config.ts
package.json
postcss.config.mjs
queryClients/useFetchChat.ts
queryClients/useFetchProjectDetails.ts
README.md
tsconfig.json
```

### Dependencies

- package.json: @clerk/nextjs@^6.22.0, @clerk/themes@^2.2.50, @hookform/resolvers@^5.1.1, @phosphor-icons/react@^2.1.10, @radix-ui/react-alert-dialog@^1.1.14, @radix-ui/react-dialog@^1.1.14, @radix-ui/react-label@^2.1.7, @radix-ui/react-separator@^1.1.7, @radix-ui/react-slot@^1.2.3, @radix-ui/react-tooltip@^1.2.7, @react-pdf/renderer@^4.3.0, @tailwindcss/postcss@^4, @tailwindcss/typography@^0.5.16, @tanstack/react-query@^5.81.1, @tiptap/extension-placeholder@^2.22.3, @tiptap/pm@^2.22.3, @tiptap/react@^2.22.3, @tiptap/starter-kit@^2.22.3, @types/node@^20, @types/react@^19, @types/react-dom@^19, axios@^1.10.0, class-variance-authority@^0.7.1, clsx@^2.1.1, date-fns@^4.1.0, groq-sdk@^0.25.0, lucide-react@^0.522.0, motion@^12.18.1, next@15.3.8, next-themes@^0.4.6, react@^19.0.0, react-dom@^19.0.0, react-hook-form@^7.58.1, react-icons@^5.5.0, react-markdown@^8.0.6, recharts@^2.15.4, sonner@^2.0.5, tailwind-merge@^3.3.1, tailwindcss@^4, tw-animate-css@^1.3.4, typescript@^5, zod@^3.25.67

### Recent commits (newest first)

- Merge pull request #3 from Zalinto/vercel/react-server-components-cve-vu-f03ppq
- Fix React Server Components CVE vulnerabilities
- feat: disable button when empty
- feat: docgen
- feat: added integration with agents
- fix: accessibility for alert dialog
- chore: added api url to env
- feat: added logo and favicon
- feat: added script gen for video
- Merge branch 'main' of github.com:zalinto/startup-hacks
- feat: added placeholder charts
- brainstorming chat progress
- feat: video generation preview
- feat: fixed package lock
- connect campaign
- campaign
- fix fetch query for project sidebar
- sidebar
- fix layout url routes
- dashboard project fix

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

### package.json

```
{
  "name": "nextjs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@clerk/nextjs": "^6.22.0",
    "@clerk/themes": "^2.2.50",
    "@hookform/resolvers": "^5.1.1",
    "@phosphor-icons/react": "^2.1.10",
    "@radix-ui/react-alert-dialog": "^1.1.14",
    "@radix-ui/react-dialog": "^1.1.14",
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-separator": "^1.1.7",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-tooltip": "^1.2.7",
    "@react-pdf/renderer": "^4.3.0",
    "@tanstack/react-query": "^5.81.1",
    "@tiptap/extension-placeholder": "^2.22.3",
    "@tiptap/pm": "^2.22.3",
    "@tiptap/react": "^2.22.3",
    "@tiptap/starter-kit": "^2.22.3",
    "axios": "^1.10.0",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "date-fns": "^4.1.0",
    "groq-sdk": "^0.25.0",
    "lucide-react": "^0.522.0",
    "motion": "^12.18.1",
    "next": "15.3.8",
    "next-themes": "^0.4.6",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-hook-form": "^7.58.1",
    "react-icons": "^5.5.0",
    "react-markdown": "^8.0.6",
    "recharts": "^2.15.4",
    "sonner": "^2.0.5",
    "tailwind-merge": "^3.3.1",
    "zod": "^3.25.67"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@tailwindcss/typography": "^0.5.16",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "tailwindcss": "^4",
    "tw-animate-css": "^1.3.4",
    "typescript": "^5"
  },
  "overrides": {
    "react-is": "19.1.0"
  }
}

```

### app/layout.tsx

```typescript
import { ClerkProvider } from "@clerk/nextjs";
import { dark as clerkDark } from "@clerk/themes";
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { Providers, ThemeProvider } from "./providers";
import { Toaster } from "@/components/ui/sonner";

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

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

export const metadata: Metadata = {
  title: "Zeroto",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider
      appearance={{
        baseTheme: clerkDark,
      }}
    >
      <Providers>
        <html lang="en" suppressHydrationWarning>
          <body
            className={`${geistSans.variable} ${geistMono.variable} antialiased`}
            suppressHydrationWarning
          >
            <ThemeProvider
              attribute="class"
              defaultTheme="dark"
              enableSystem
              disableTransitionOnChange
            >
              {children}
            </ThemeProvider>
            <Toaster />
          </body>
        </html>
      </Providers>
    </ClerkProvider>
  );
}

```

### app/dashboard/page.tsx

```typescript
import { redirect } from "next/navigation";

export default function Dashboard() {
  redirect("/dashboard/projects");
}

```

### app/(public)/page.tsx

```typescript
import CTA from "./landing/CTA";
// import Features from "./landing/Features";
import Footer from "./landing/Footer";
import Hero from "./landing/Hero";
// import Problem from "./landing/Problem";
// import Solution from "./landing/Solution";

export default function Landing() {
  return (
    <>
      <main>
        <Hero />
        {/* <Problem />
        <Solution /> */}
        {/* <Features /> */}
        {/* <CTA /> */}
      </main>
      {/* <Footer /> */}
    </>
  );
}

```

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

```typescript
import { Button } from "@/components/ui/button";
import { SignedIn, SignedOut, SignInButton, UserButton } from "@clerk/nextjs";
import Link from "next/link";
import { DM_Sans } from "next/font/google";

const dmSans = DM_Sans({
  variable: "--font-dmSans",
  subsets: ["latin"],
  weight: ["400", "500", "700"],
});

export default function PublicLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <>
      <nav className="fixed w-screen z-20">
        <div className="max-w-7xl mx-auto px-4 w-full flex justify-between h-[64px] items-center">
          <a href="/" className="font-bold text-2xl flex items-center gap-4">
            <img src="/favicon.png" className="h-8 w-8" />
            Zeroto
          </a>
          <div className="flex gap-4 items-center">
            <SignedIn>
              <Button asChild>
                <Link href="/dashboard">Go to Dashboard</Link>
              </Button>
              <div className="w-[28px] h-[28px] hover:cursor-pointer">
                <UserButton />
              </div>
            </SignedIn>
            <SignedOut>
              <SignInButton mode="modal" fallbackRedirectUrl={"/dashboard"}>
                <Button className="cursor-pointer">Sign In</Button>
              </SignInButton>
            </SignedOut>
          </div>
        </div>
      </nav>
      {children}
    </>
  );
}

```

### app/dashboard/layout.tsx

```typescript
"use client";

import { AppSidebar, SidebarItem } from "@/components/app-sidebar";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
import {
  CaretLeftIcon,
  ClipboardTextIcon,
  HouseIcon,
  LightbulbIcon,
  MegaphoneIcon,
  QuestionIcon,
} from "@phosphor-icons/react/dist/ssr";
import { useQuery } from "@tanstack/react-query";
import { useMemo } from "react";
import { getProjectDetailQuery, getProjectsQuery } from "./queries";
import { useParams } from "next/navigation";

function DashboardSidebar() {
  const params = useParams();

  const projectId = params.id as string | undefined;

  const projectDetail = useQuery(getProjectDetailQuery(projectId));
  const recentProjects = useQuery(getProjectsQuery);

  const mainItems = useMemo<SidebarItem[]>(
    () => [
      {
        title: "Projects",
        url: "/dashboard/projects",
        icon: ClipboardTextIcon,
        items: recentProjects.data?.map(
          (project: { title: any; project_id: any }) => ({
            title: project.title,
            url: `/dashboard/projects/${project.project_id}`,
          })
        ),
      },
    ],
    [recentProjects.data]
  );

  const projectDetailItems = useMemo<SidebarItem[]>(() => {
    if (!projectDetail.data) return [];
    return [
      {
        title: "All Projects",
        icon: CaretLeftIcon,
        url: "/dashboard/projects",
        matcher: () => false,
      },
      {
        title: projectDetail.data.title,
        url: `/dashboard/projects/${projectDetail.data.project_id}/brainstorming`,
        icon: ClipboardTextIcon,
        matcher: () => false,
        items: [
          {
            icon: LightbulbIcon,
            title: "Brainstorming",
            url: `/dashboard/projects/${projectDetail.data.project_id}/brainstorming`,
          },
          {
            icon: MegaphoneIcon,

            title: "Outreach",
            url: `/dashboard/projects/${projectDetail.data.project_id}/outreach`,
          },
          {
            icon: QuestionIcon,
            title: "Customer Support",
            url: `/dashboard/projects/${projectDetail.data.project_id}/support`,
          },
        ],
      },
    ];
  }, [projectDetail.data]);

  return <AppSidebar items={projectId ? projectDetailItems : mainItems} />;
}

export default function DashboardLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <SidebarProvider>
      <DashboardSidebar />
      <SidebarInset>{children}</SidebarInset>
    </SidebarProvider>
  );
}

```

### app/dashboard/projects/page.tsx

```typescript
"use client";

import {
  Breadcrumb,
  BreadcrumbList,
  BreadcrumbPage,
} from "@/components/ui/breadcrumb";
import { Button } from "@/components/ui/button";
import { format } from "date-fns";
import PageHeader from "@/components/ui/page-header";
import { PlusIcon } from "@phosphor-icons/react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { getProjectsQuery, Project } from "../queries";
import {
  Card,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import Link from "next/link";
import { z } from "zod/v4";
import { useForm } from "react-hook-form";
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
import { useEffect, useState } from "react";
import {
  AlertDialog,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { AlertDialogHeader } from "@/components/ui/alert-dialog";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { api } from "@/app/providers";
import { toast } from "sonner";

const newProjectSchema = z.object({
  project_name: z.string().min(1, "Title is required"),
});

function StartNewDialog() {
  const form = useForm<z.infer<typeof newProjectSchema>>({
    resolver: standardSchemaResolver(newProjectSchema),
    defaultValues: {
      project_name: "",
    },
  });

  const queryClient = useQueryClient();
  const createMutation = useMutation({
    mutationFn: async (data: z.infer<typeof newProjectSchema>) => {
      await api.post("/project", data);
    },
    onSuccess: () => {
      toast.success("Project created successfully!");
      queryClient.invalidateQueries({
        queryKey: getProjectsQuery.queryKey,
      });
    },
  });

  const [open, setOpen] = useState(false);
  useEffect(() => {
    if (open) {
      form.reset();
    }
  }, [open]);

  return (
    <AlertDialog open={open} onOpenChange={setOpen}>
      <AlertDialogTrigger asChild>
        <Button variant={"outline"}>
          <PlusIcon />
          Start New
        </Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Start New Campaign</AlertDialogTitle>
          <AlertDialogDescription>
            Begin a new outreach campaign to grow your userbase.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <Form {...form}>
          <form
            onSubmit={form.handleSubmit(async (data) => {
              await createMutation.mutateAsync(data);
              setOpen(false);
            })}
          >
            <div className="grid gap-4">
              <FormField
                control={form.control}
                name="project_name"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Title</FormLabel>
                    <FormControl>
                      <Input {...field} placeholder="Exciting New Feature" />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <AlertDialogFooter className="">
                <AlertDialogCancel>Cancel</AlertDialogCancel>
                <Button
                  type="submit"
                  disabled={
                    !form.formState.isValid || form.formState.isSubmitting
                  }
                >
                  Create
                </Button>
              </AlertDialogFooter>
            </div>
          </form>
        </Form>
      </AlertDialogContent>
    </AlertDialog>
  );
}

function ProjectCard({ project }: { project: Project }) {
  return (
    <Link href={`/dashboard/projects/${project.project_id}`}>
      <Card className="hover:border-accent-foreground">
        <CardHeader>
          <CardTitle>{project.title}</CardTitle>
          <CardDescription>
            {format(project.created_at, "MM/dd/yyyy")}
          </CardDescription>
        </CardHeader>
      </Card>
    </Link>
  );
}

export default function MyProjects() {
  const projects = useQuery(getProjectsQuery);

  return (
    <>
      <PageHeader
        title={
          <Breadcrumb>
            <BreadcrumbList>
              <BreadcrumbPage className="line-clamp-1 font-bold">
                My Projects
              </BreadcrumbPage>
            </BreadcrumbList>
          </Breadcrumb>
        }
        nav={<StartNewDialog />}
      />
      <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 p-4">
        {projects.data?.map((project) => (
          <ProjectCard key={project.project_id} project={project} />
        ))}
      </div>
    </>
  );
}

```

### app/dashboard/projects/[id]/page.tsx

```typescript
"use client";
import { redirect, usePathname } from "next/navigation";

export default function ProjectDetail() {
  const pathname = usePathname();
  redirect(`${pathname}/brainstorming`);
}

```

### app/dashboard/projects/[id]/support/page.tsx

```typescript
"use client";
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import PageHeader from "@/components/ui/page-header";
import { QuestionIcon } from "@phosphor-icons/react/dist/ssr";
import { useActiveProject } from "../hooks";

export default function ProjectSupport() {
  const project = useActiveProject().data;
  return (
    <>
      <PageHeader
        title={
          <Breadcrumb>
            <BreadcrumbList>
              <BreadcrumbItem>{project?.title ?? "Loading..."}</BreadcrumbItem>
              <BreadcrumbSeparator />
              <BreadcrumbPage className="line-clamp-1 font-bold flex gap-2 items-center">
                <QuestionIcon />
                <span>Customer Support</span>
              </BreadcrumbPage>
            </BreadcrumbList>
          </Breadcrumb>
        }
      />
    </>
  );
}

```

### app/dashboard/projects/[id]/brainstorming/page.tsx

```typescript
"use client";

import { api } from "@/app/providers";
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { Button } from "@/components/ui/button";
import PageHeader from "@/components/ui/page-header";
import {
  ChatDotsIcon,
  FloppyDiskBackIcon,
  LightbulbIcon,
} from "@phosphor-icons/react/dist/ssr";
import { useMutation } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { useState } from "react";
import { useActiveProject } from "../hooks";
import BrainstormingChat, { Message } from "./components/chat";
import BrainstormingSummary from "./components/summary";

export default function ProjectBrainstorming() {
  const params = useParams();

  const project = useActiveProject();

  const [messages, setMessages] = useState<Message[]>([]);
  const [summary, setSummary] = useState<{
    summary: string;
    prd: any;
    styleGuide: any;
  } | null>(null);

  const [isBrainstorming, setIsBrainstorming] = useState(true);

  const summarizeMutation = useMutation({
    mutationFn: async (messages: Message[]) => {
      const megaMessage = messages
        .map((msg) => `Sender: ${msg.sender}\nMessage: ${msg.message}`)
        .join("\n\n---\n\n");

      const response = await api.post<{
        summary: string;
        prd: any;
        styleGuide: any;
      }>("groq/summary", {
        message: megaMessage,
      });
      setSummary(response.data);
    },
  });

  return (
    <>
      <PageHeader
        title={
          <Breadcrumb>
            <BreadcrumbList>
              <BreadcrumbItem>
                {project.data?.title ?? "Loading..."}
              </BreadcrumbItem>
              <BreadcrumbSeparator />
              <BreadcrumbPage className="line-clamp-1 font-bold flex gap-2 items-center">
                <LightbulbIcon />
                <span>Brainstorming</span>
              </BreadcrumbPage>
            </BreadcrumbList>
          </Breadcrumb>
        }
        nav={
          <Button
            onClick={async () => {
              if (isBrainstorming) {
                await summarizeMutation.mutateAsync(messages);
                setIsBrainstorming(false);
              } else {
                setIsBrainstorming(true);
                setMessages([]);
              }
            }}
            variant={"outline"}
            disabled={
              summarizeMutation.isPending ||
              (isBrainstorming && messages.length === 0)
            }
          >
            {isBrainstorming ? (
              <>
                <FloppyDiskBackIcon />
                End Session
              </>
            ) : (
              <>
                <ChatDotsIcon />
                Start Brainstorming
              </>
            )}
          </Button>
        }
      />
      {isBrainstorming && (
        <BrainstormingChat messages={messages} setMessages={setMessages} />
      )}
      {!isBrainstorming && summary && (
        <BrainstormingSummary
          summary={summary.summary}
          prd={summary.prd}
          styleGuide={summary.styleGuide}
        />
      )}
    </>
  );
}

```

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