11 KiB
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
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
difflibrary 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:
- Validates agentId is provided
- Looks up webhook URL using
getAgentWebhookUrl(agentId) - Proxies request to agent's specific n8n webhook
- 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-agentandselected-agent-id - Session ID: Per-agent format
chat-session-{agentId}stored aschat-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
MarkdownRendererextracts```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-themeswith "light" and "dark" variants - Toggle: Mode toggle button in header
- Global Styles:
src/app/globals.csscontains theme definitions and Tailwind imports
Configuration Files
tsconfig.json- TypeScript strict mode, bundler module resolution,@/*alias tosrc/next.config.ts- Next.js configurationopen-next.config.ts- Cloudflare-specific Next.js configurationwrangler.jsonc- Wrangler (Cloudflare CLI) configurationeslint.config.mjs- ESLint with Next.js core-web-vitals and TypeScript supportcomponents.json- shadcn/ui component library configurationpostcss.config.mjs- Tailwind CSS plugin configuration
n8n Webhook Integration
The chat endpoint routes to an n8n workflow via webhook. The workflow should:
- Accept message input and context from the client
- 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
- Add three environment variables:
AGENT_N_URL- webhook URL for the agentAGENT_N_NAME- display nameAGENT_N_DESCRIPTION- short description
- On next page reload, new agent appears in AgentSelector
- 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.tsxto extract new code block type - Step 3: Create new component similar to
DiffDisplayand 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
useReffor 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