CLAUDE.md
Documents the architecture, data flow, and API integration of a Next.js chat frontend for a data analysis agent.
What this file does
Documents the architecture, data flow, and API integration of a Next.js chat frontend for a data analysis agent.
When to use it
- You are onboarding to a Next.js project with SSE streaming and tool calls
- You need to understand how a single-page chat UI manages state and session isolation
- You are building a frontend that renders inline charts from base64 or D3 markers
- You want to see how a dataset browser with instant-load flow is structured
Assumes this stack
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Dash UI is the Next.js frontend for the Dash data agent. It provides a chat interface for data analysis — fetch URLs, query databases, run Python/R, and create charts. Works with any data source, not just SQL.
Commands
# Install dependencies
npm install
# Run development server (port 3000)
npm run dev
# Build for production
npm run build
# Start production server
npm start
Note: The backend API server (FastAPI) must be running on port 8000. See ../dash-repo/ for backend setup.
Architecture
Single-Page Application
The entire UI is in app/page.js (~1750 lines). Key sections:
| Lines | Component | Purpose |
|---|---|---|
| 1-90 | Utilities | extractChart(), extractD3Chart(), renderMarkdown() |
| 90-270 | Chart Components | ChartImage, D3Chart, ImageModal |
| 270-400 | UI Components | Icons, CopyableCode, CodeBlockItem |
| 400-630 | CodePanel | Slide-out panel showing all executed code, export to .py/.R/.ipynb |
| 630-660 | ContextBox | Collapsible plain text box for data dictionaries/readmes |
| 660-780 | ToolCall | Collapsible tool execution display (SQL, Python, R) |
| 780-940 | Message Components | Message, StreamingMsg with inline charts |
| 940-1750 | Home (main) | State management, SSE streaming, chat flow, sidebar, Kaggle/TidyTuesday tabs |
Data Flow
User Input → POST /chat/stream → SSE Events → UI Updates
↓
tool_start → ToolCall (running)
tool_complete → ToolCall (result) + inline Chart
delta → Streaming text
done → Finalize message
State Management
// In Home component
const [messages, setMessages] = useState([]) // Chat history
const [streamEvents, setStreamEvents] = useState([]) // Current streaming response
const [language, setLanguage] = useState('python') // Python or R preference
const [conversationId, setConversationId] = useState(null) // Current conversation UUID
const sessionIdRef = useRef(generateSessionId()) // Backend session ID (= conversationId)
Session Isolation
Each conversation gets its own backend session — no cross-contamination:
sessionIdRef.currentis set toconversationIdwhen a conversation is created or loaded- New conversation: generates a fresh
sessionIdRef, creates a new conversation viaPOST /conversations - Load old conversation: sets
sessionIdRef.current = convId, calls/restoreto rebuild agent history - Switch conversations: different sessionId = different backend
DashAgentinstance
Message Format
// User message
{ role: 'user', content: 'Who won most championships?' }
// Assistant message with events (tools + context + text interleaved)
{
role: 'assistant',
events: [
{ type: 'tool', tool: { name: 'run_sql', args: {...}, result: '...' } },
{ type: 'context', title: 'Data dictionary', content: '...' }, // collapsible plain text box
{ type: 'text', content: 'Based on the data...' }
]
}
Conversations & Permalinks
- Sidebar lists saved conversations via
GET /conversations - Clicking a conversation loads it, restores backend agent history, and updates URL to
?c=<uuid> - Refreshing or sharing the URL reopens the same conversation
- New conversations get a URL permalink after the first message is sent
- "New conversation" generates a fresh session and clears URL back to
/ - Titles are auto-generated by Haiku on the backend after the first user message
Key Features
Chart Rendering
Charts are embedded in tool results using markers:
- Matplotlib/ggplot2:
[CHART_BASE64]<base64>[/CHART_BASE64]→ renders as<img> - D3.js:
[D3_CHART]{"code":"...","data":[...]}}[/D3_CHART]→ renders in sandboxed iframe
Code Panel
Right sidebar shows all executed code (SQL, Python, R) with:
- Individual copy buttons per block
- Export to
.pyor.Rfile with boilerplate (DB setup, imports) - Export to
.ipynbJupyter notebook with user/AI markdown cells, code cells, and captured outputs (text results + base64 chart images) - Language auto-detection based on tools used
Language Toggle
On home screen, user selects Python or R. This:
- Sends
languagefield in API request - Updates CodePanel export format
- Backend prepends
[USER PREFERS R]to guide tool selection
Dataset Browser (Kaggle & TidyTuesday)
Home screen has three tabs: Presets | Kaggle Datasets | TidyTuesday.
- Kaggle tab: Searchable, sortable grid of dataset cards fetched via
GET /kaggle/datasetsbackend proxy. Supports pagination ("Load more"). - TidyTuesday tab: Year-selectable list of weekly datasets from the R4DS GitHub repo via
GET /tidytuesday/datasets. - Instant-load flow: Clicking a dataset card calls
POST /kaggle/loadorPOST /tidytuesday/load. The backend downloads + explores data directly in CodeInterpreter (no Claude API call), fabricates a conversation with tool events, seeds agent history, and returns pre-populated messages. The frontend sets these as the conversation — user sees results instantly. contextevent type: Dataset descriptions/readmes are returned as{type: 'context', title, content}events, rendered byContextBoxas a collapsible plain text box (no markdown rendering).
API Integration
// Streaming chat (SSE) — session_id ties to conversation
fetch('http://localhost:8000/chat/stream', {
method: 'POST',
body: JSON.stringify({ message, session_id: sessionIdRef.current, language })
})
// Restore agent history when loading a conversation
fetch('http://localhost:8000/restore', {
method: 'POST',
body: JSON.stringify({ session_id: convId, messages })
})
SSE Event Types
| Event | Action |
|---|---|
tool_start | Add collapsible ToolCall in "running" state |
tool_complete | Update ToolCall with result, extract/render charts |
delta | Append to streaming text content |
done | Finalize message, save to backend, refresh sidebar |
error | Display error message |
Styling
- Framework: Tailwind CSS v4 with
@tailwindcss/postcss - Theme: Light/dark mode via CSS custom properties (
--ink,--bg,--red, etc.) and@media (prefers-color-scheme: dark) - Fonts: Newsreader (serif display), Outfit (sans body), JetBrains Mono (code)
- Layout: Max-width 3xl centered, responsive code panel, collapsible sidebar
- User message selection: Uses
[data-user-msg]attribute selector inglobals.cssfor visible text selection on dark bubbles (Tailwind v4 purges class-based selectors from CSS files)
File Structure
dash-ui/
├── app/
│ ├── page.js # All UI components and logic (~1750 lines)
│ ├── layout.js # Root layout, metadata, font loading
│ └── globals.css # Design tokens, dark mode, prose styling, animations
├── package.json # Dependencies: next, react 19, tailwindcss v4
├── postcss.config.js # PostCSS with @tailwindcss/postcss
└── tailwind.config.js
What's inside
1 project overview, 4 command examples, 6 architecture sections, 5 API event types, 3 styling notes, 1 file tree
Change this for your project
- Replace
http://localhost:8000with your backend API URL - Replace
../dash-repo/with your backend repository path - Replace
vibedatascience/dash-uiwith your own repository name
Where it goes
Save as CLAUDE.md in your repository root. Claude Code reads it automatically at the start of every session.
Worth borrowing
- Using
[CHART_BASE64]and[D3_CHART]markers to embed charts in tool results without breaking the message stream - Session isolation via
sessionIdReftied to conversation UUID, with a/restoreendpoint to rebuild agent history - Instant-load dataset flow that pre-populates conversation with fabricated tool events, skipping the LLM call
Related Documents
Code indexing for AI agents: summarization strategies and evaluation systems
Synthesises 2024-2025 research on code indexing for AI agents, covering summarisation strategies, hybrid retrieval architectures, and evaluation benchmarks.
write-script
Guides an AI through writing a YouTube video script with strict structural, language, and quiz rules for a survival channel.
Claude AI Git Workflow Integration
Recommends using the git-ai-commit CLI tool for AI-generated commit messages instead of manual ones.
Missing Business Agents Research — FLUXION 2026
Identifies 12 missing business operations agents for an indie software company and ranks them by impact and effort with €0 implementation plans.