# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

**Multi-Agent Chat Interface** - A Next.js-based AI chat platform that supports multiple agents configured via environment variables. Users select an agent from a menu on first visit, then chat with that agent. The application integrates with n8n workflows via webhooks, features markdown rendering with syntax highlighting, image uploads, and an interactive diff tool for code changes.

## Development Commands

```bash
npm run dev      # Start Next.js development server (http://localhost:3000)
npm run build    # Create production build
npm start        # Run production server
npm run lint     # Run ESLint checks
```

**Note:** No testing framework is currently configured. Tests should be added when needed.

## Technology Stack

- **Frontend:** Next.js 15.5.4 (App Router), React 19, TypeScript 5
- **Styling:** Tailwind CSS 4.1.9 with PostCSS
- **UI Components:** shadcn/ui (Radix UI primitives), Lucide icons
- **Forms & Validation:** React Hook Form + Zod
- **Markdown:** react-markdown with remark-gfm and rehype-highlight for code syntax
- **Diffs:** Custom pipeline using `diff` library with Highlight.js for colored output
- **Deployment:** Cloudflare Workers/Pages via OpenNextJS + Wrangler

## Project Structure

```
src/
├── app/
│   ├── api/
│   │   ├── agents/route.ts        # GET endpoint - returns available agents from env vars
│   │   └── chat/route.ts          # POST endpoint - routes to selected agent's webhook
│   ├── layout.tsx                 # Root layout with theme provider
│   ├── page.tsx                   # Home page - conditionally renders AgentSelector or ChatInterface
│   └── globals.css                # Tailwind global styles
├── components/
│   ├── agent-selector.tsx         # Agent selection menu (card-based UI)
│   ├── chat-interface.tsx         # Main chat UI component (client-side, per-agent)
│   ├── markdown-renderer.tsx      # Parses markdown + extracts diff-tool blocks
│   ├── diff-display.tsx           # Renders diffs with syntax highlighting
│   ├── diff-tool.tsx              # Diff tool wrapper component
│   ├── header.tsx                 # App header with agent name and switch button
│   ├── mode-toggle.tsx            # Dark/light theme toggle
│   ├── theme-provider.tsx         # Theme context setup
│   ├── DIFF_TOOL_USAGE.md         # In-component documentation
│   └── ui/                        # shadcn/ui component library
└── lib/
    ├── types.ts                   # TypeScript types and interfaces (Agent, Message, ChatRequest, etc.)
    └── utils.ts                   # Utility functions (cn() for classname merging)
```

## Architecture & Data Flow

### Agent Selection Flow
```
User visits site
  ↓
page.tsx checks localStorage for selected agent
  ↓
If no agent: Show AgentSelector
  │   - Fetches agents from GET /api/agents
  │   - Displays agent cards with name + description
  │   - On selection: saves agent to localStorage and shows ChatInterface
  ↓
If agent exists: Show ChatInterface with that agent
```

### Multi-Agent API Pattern
**GET /api/agents**
- Reads environment variables `AGENT_1_URL`, `AGENT_1_NAME`, `AGENT_1_DESCRIPTION`, `AGENT_2_URL`, etc.
- Returns array of available agents: `{ agents: Agent[] }`

**POST /api/chat**
- **Request:** `{ message, timestamp, sessionId, agentId, images? }`
- **Processing:**
  1. Validates agentId is provided
  2. Looks up webhook URL using `getAgentWebhookUrl(agentId)`
  3. Proxies request to agent's specific n8n webhook
  4. Forwards images (base64) if provided
- **Response Format:** Newline-delimited JSON with two message types:
  - `"item"` - Text content rendered directly
  - `"tool_call"` - Structured tools like `{ name: "show_diff", input: {...} }`

### Diff Tool Pipeline
```
n8n webhook response (tool_call: show_diff)
  ↓
/api/chat/route.ts (converts to markdown code block format)
  ↓
MarkdownRenderer (regex extracts diff-tool code blocks)
  ↓
DiffDisplay (renders diffs with Highlight.js syntax highlighting)
```

### Client-Side Architecture
- **State Management:** React hooks (useState, useRef) + localStorage for persistence
- **Agent Persistence:** Selected agent stored in `selected-agent` and `selected-agent-id`
- **Session ID:** Per-agent format `chat-session-{agentId}` stored as `chat-session-{agentId}`
- **Message Storage:** Per-agent messages stored as `chat-messages-{agentId}` in localStorage
- **Image Handling:** Images converted to base64 and included in message payload
- **Auto-scroll:** Maintains scroll position at latest message

### Markdown Processing Details
- Custom regex parser in `MarkdownRenderer` extracts ` ```diff-tool ... ``` ` code blocks
- Replaces diff-tool blocks with placeholders during markdown rendering
- After markdown is rendered, dynamically inserts `<DiffDisplay>` components
- Supports remark-gfm (GitHub-flavored markdown) and rehype-highlight for syntax coloring

## Key Files & Responsibilities

| File | Purpose |
|------|---------|
| `src/lib/types.ts` | Centralized TypeScript types: Agent, Message, ChatRequest, ChatResponse, etc. |
| `src/app/api/agents/route.ts` | GET endpoint - parses env vars and returns available agents |
| `src/app/api/chat/route.ts` | POST endpoint - looks up agent webhook URL and proxies requests |
| `src/app/page.tsx` | Home page - manages agent selection state, conditionally renders AgentSelector or ChatInterface |
| `src/components/agent-selector.tsx` | Agent selection UI - fetches agents, displays cards, handles selection |
| `src/components/chat-interface.tsx` | Main chat UI - handles per-agent messages, image uploads, streaming |
| `src/components/header.tsx` | App header - displays agent name and "Switch Agent" button |
| `src/components/markdown-renderer.tsx` | Parses markdown and extracts diff-tool blocks for custom rendering |
| `src/components/diff-display.tsx` | Renders side-by-side diffs with syntax highlighting using Highlight.js |
| `AGENT_DIFF_TOOL_SETUP.md` | Comprehensive guide for configuring n8n agents to output diff tools |
| `src/components/DIFF_TOOL_USAGE.md` | In-component documentation for the diff tool feature |

## Theme & Styling

- **System:** Tailwind CSS 4 with CSS custom properties and OKLch color space
- **Colors:** Warm light mode (cream/beige) and pure black dark mode
- **Implementation:** `next-themes` with "light" and "dark" variants
- **Toggle:** Mode toggle button in header
- **Global Styles:** `src/app/globals.css` contains theme definitions and Tailwind imports

## Configuration Files

- `tsconfig.json` - TypeScript strict mode, bundler module resolution, `@/*` alias to `src/`
- `next.config.ts` - Next.js configuration
- `open-next.config.ts` - Cloudflare-specific Next.js configuration
- `wrangler.jsonc` - Wrangler (Cloudflare CLI) configuration
- `eslint.config.mjs` - ESLint with Next.js core-web-vitals and TypeScript support
- `components.json` - shadcn/ui component library configuration
- `postcss.config.mjs` - Tailwind CSS plugin configuration

## n8n Webhook Integration

The chat endpoint routes to an n8n workflow via webhook. The workflow should:

1. Accept message input and context from the client
2. Return newline-delimited JSON with messages in one of two formats:
   - `{ "type": "item", "content": "text content" }`
   - `{ "type": "tool_call", "name": "show_diff", "input": { "before": "...", "after": "...", "language": "..." } }`

**Note:** See `AGENT_DIFF_TOOL_SETUP.md` for detailed instructions on configuring n8n agents to use the diff tool feature.

## Common Tasks

### Configuring Agents via Environment Variables
**Local Development (.env.local):**
```
AGENT_1_URL=https://n8n.example.com/webhook/agent-1-uuid
AGENT_1_NAME=Creative Writer
AGENT_1_DESCRIPTION=An AI assistant for creative writing and brainstorming

AGENT_2_URL=https://n8n.example.com/webhook/agent-2-uuid
AGENT_2_NAME=Code Reviewer
AGENT_2_DESCRIPTION=An AI assistant for code review and refactoring
```

**Cloudflare Deployment:**
- Go to Cloudflare dashboard → Workers & Pages → your-project → Settings → Environment variables
- Add the same AGENT_* variables above
- Deploy to apply changes

### Adding a New Agent
1. Add three environment variables:
   - `AGENT_N_URL` - webhook URL for the agent
   - `AGENT_N_NAME` - display name
   - `AGENT_N_DESCRIPTION` - short description
2. On next page reload, new agent appears in AgentSelector
3. No code changes needed

### Modifying Chat Messages or Display
- **Chat UI:** `src/components/chat-interface.tsx`
- **Rendering:** `src/components/markdown-renderer.tsx`
- **State:** Message list stored in component state, persisted to localStorage per agent
- **Per-agent persistence:** Messages saved as `chat-messages-{agentId}`

### Changing Theme Colors
- Edit CSS custom properties in `src/app/globals.css`
- Uses OKLch color space (perceptually uniform)
- Dark mode variant defined with `@custom-variant dark`

### Adding New Tool Types (beyond show_diff)
- **Step 1:** Handle in `/api/chat/route.ts` - convert tool_call to markdown format
- **Step 2:** Add detection logic in `markdown-renderer.tsx` to extract new code block type
- **Step 3:** Create new component similar to `DiffDisplay` and render dynamically

### Switching Between Agents
- Users click "Switch Agent" button in header
- Returns to AgentSelector menu
- Previously selected agents/messages are preserved in localStorage per agent
- No data loss when switching

## Notes for Future Development

### Multi-Agent Features
- **Agent Switching:** Currently requires page reload to agent selector. Could add inline dropdown in header.
- **Agent Management:** UI for adding/editing agents without env vars could improve UX
- **Agent Verification:** Add health checks to verify agents' webhook URLs are reachable
- **Agent Categories:** Could group agents by category/type for better organization

### Image Upload Enhancements
- **Image Storage:** Currently base64 in memory; consider Cloudflare R2 for large images
- **Image Preview:** Add full-screen image viewer for uploaded images
- **Multi-file Upload:** Support multiple file types beyond images

### Performance & Scaling
- **Message Virtualization:** Chat interface uses `useRef` for scroll - consider virtualizing long message lists
- **Storage Size:** localStorage has 5-10MB limit; consider IndexedDB for longer conversations
- **Streaming:** Current implementation reads entire response before parsing; consider streaming HTML as it arrives

### Testing & Quality
- **Testing:** Consider adding Jest or Vitest for component and API testing
- **Error Handling:** Enhance with retry logic for failed webhook calls and better error messages
- **Logging:** Add structured logging for debugging multi-agent interactions

### Accessibility & UX
- **Keyboard Navigation:** Verify keyboard navigation on agent selector cards and custom diff tool
- **ARIA Labels:** Add aria-labels for screen readers on interactive elements
- **Mobile Responsive:** Test agent selector and chat interface on mobile devices
