# Working in this project (for AI coding assistants)

This project was scaffolded from the `multi-agent-chat` template in
[Coral](https://github.com/microsoft/coral-ui) (`npm create @coral-ai`). When
suggesting code or extending the app, follow these conventions.

## Tech stack

- **React 19** + **Vite** + **TypeScript** on the frontend.
- **FastAPI** + **Anthropic Claude** (`anthropic` Python SDK) on the backend.
- UI is built on **Coral** layered on top of **Fluent UI React v9**:
  - `@coral-ai/react`  — shell primitives: `CoralProvider`, `CoralShellColumn`,
    `CoralShellRow`, `Navbar`, `Panel.Left`, `Panel.Top`, `Panel.NavItem`,
    `Panel.ChatHistorySection`, `Panel.ChatHistoryItem`, `Content`,
    `CoralAuthProvider`.
  - `@coral-ai/chat`   — `<Chat>` component (streaming chat surface, NDJSON
    protocol, built-in handler for the `api` prop).
  - `@coral-ai/markdown` — `<CoralMarkdown>` for rendering assistant markdown
    (already styled to match the Coral shell).
  - `@coral-ai/bundleicons` — icon set. Prefer these over `@fluentui/react-icons`
    or inline SVG.
  - `@fluentui/react-components` — every other primitive (Button, Menu,
    MenuItem, Toast, Skeleton, etc.). **Prefer Fluent components over rolling
    your own.**

## Rules to follow

1. **Do not wrap the app in `<FluentProvider>`.** `CoralProvider` already
   provides the theme. Adding a nested `FluentProvider` with styling breaks
   Fluent's portaled menus (it aria-hides sibling subtrees on open, which kills
   click handlers in the shell).

2. **Use Coral shell primitives, not custom flexbox.** A new page is `<Content>`
   inside the existing `<CoralShellRow>`, not a new layout. Nav buttons go in
   `<Panel.NavItem>` / `<Panel.ChatHistoryItem>`, not raw `<Button>`s in a
   `<div>`.

3. **Auth lives in `Panel.Left`'s `userCard` slot**, not the navbar. Sign-in
   and Logout are rendered automatically by `Panel.UserCard` as long as a
   `CoralAuthProvider` is in the tree with `signIn` / `signOut` handlers (see
   `src/auth/AuthProvider.tsx`).

4. **Chat → backend wiring** is `<Chat api="/api/chat" ... />`. The `<Chat>`
   component is wired declaratively — do not write a custom `onSendMessage`
   unless you need to intercept the request.

5. **Streaming protocol is NDJSON, one JSON value per line.** The frontend
   accepts:
   - bare strings — appended as visible text
   - `{type:"todos", todos:[…]}` — renders an inline checklist
   - `{type:"approval", approval:{…}}` — renders a multi-choice prompt
   - `{type:"chart", spec:{kind, title, xKey, series, data}}` — renders a
     `<CoralChart>` inline (bar or line). `kind` is `"bar"` or `"line"`.
   Any other shape is dropped silently — if you want it visible, emit a bare
   string. See `backend/agents/orchestrator.py` `error_chunk()` for the
   canonical "make this visible" helper.

6. **Sessions are created lazily.** The history sidebar should never show an
   empty "New Chat" stub. The "+ New Chat" button calls `chatStore.clearActive()`
   (blank canvas); a session is only registered in `chatStore` once the first
   message lands (`onMessagesChange`).

7. **Errors must always reach the user.** Backend stages wrap their Anthropic
   calls in try/except and yield `error_chunk(...)` before returning.
   `<Chat onError>` raises a toast for HTTP-level failures (missing key, 5xx,
   network) that never reach the stream.

8. **Markdown content files are CRLF on Windows.** If you write a parser that
   splits on `\n`, normalize first.

## Where things live

- `src/main.tsx`         — root: `AuthProvider` → `CoralProvider` → `App`.
- `src/App.tsx`          — shell: `Navbar` + `Panel.Left` (with `userCard`) + `Content`.
- `src/chat/ChatPage.tsx` — `<Chat>` wiring, session lifecycle, error toasting.
- `src/chat/chatStore.ts` — lazy multi-session store, localStorage-backed.
- `src/components/PanelLeftContent.tsx` — left-panel "New Chat" + history list.
- `src/auth/AuthProvider.tsx` — MSAL ↔ `CoralAuthProvider` bridge,
  no-op variant when `VITE_AUTH_REQUIRED !== "true"`.
- `backend/main.py` — FastAPI routes + tool-use loop. `TOOLS` registers the
  three built-in tools (`update_todos`, `request_approval`, `render_chart`);
  `run_agent` is the loop. `SYSTEM_PROMPT` embeds the MCAPS sample data so
  the agent always has data without needing user input.
- `backend/sample_data.py` — the MCAPS dataset.
- `backend/auth.py` — MSAL bearer-token validation.

## Don't

- Don't add a top-right Sign-in button — use the `userCard` slot.
- Don't `npm install --legacy-peer-deps` to paper over a peer warning; fix
  the version pin.
- Don't yield raw exception objects from the backend; wrap with
  `error_chunk()` so the user sees them.
- Don't create an empty "New Chat" session on mount or on button click.
