Loading...
Loading...
Loading...
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# 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
```bash
# 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
```javascript
// 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.current` is set to `conversationId` when a conversation is created or loaded
- **New conversation**: generates a fresh `sessionIdRef`, creates a new conversation via `POST /conversations`
- **Load old conversation**: sets `sessionIdRef.current = convId`, calls `/restore` to rebuild agent history
- **Switch conversations**: different sessionId = different backend `DashAgent` instance
### Message Format
```javascript
// 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 `.py` or `.R` file with boilerplate (DB setup, imports)
- Export to `.ipynb` Jupyter 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:
1. Sends `language` field in API request
2. Updates CodePanel export format
3. 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/datasets` backend 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/load` or `POST /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.
- **`context` event type**: Dataset descriptions/readmes are returned as `{type: 'context', title, content}` events, rendered by `ContextBox` as a collapsible plain text box (no markdown rendering).
## API Integration
```javascript
// 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 in `globals.css` for 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
```
1. Application Archtect: myself, the human person guiding and suervising the development of the project.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A 24/7 emergency chat assistant for **first-time pet parents**. Users can ask questions about their pets' health, nutrition, behavior, and get immediate guidance during stressful situations. The AI has a friendly, supportive persona - like a knowledgeable friend who happens to know a lot about pets.