|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to AI agents when working with code in this repository. |
| 4 | + |
| 5 | +## Backward Compatibility (CRITICAL) |
| 6 | + |
| 7 | +All changes MUST be backward-compatible. If a refactor or breaking change is unavoidable, notify the user and stop — do not proceed without explicit approval. When approved, prefer adding a compatibility layer over keeping legacy code in place. |
| 8 | + |
| 9 | +## Overview |
| 10 | + |
| 11 | +Chainlit is a Python framework for building production-ready conversational AI applications. It consists of a Python/FastAPI backend and a React frontend, with a pnpm monorepo for the JS packages. |
| 12 | + |
| 13 | +## Prerequisites |
| 14 | + |
| 15 | +- Python: **3.13** (3.10+ is the framework's minimum, but development targets 3.13) |
| 16 | +- Node.js: **24+** |
| 17 | +- [uv](https://docs.astral.sh/uv/) — Python package manager |
| 18 | +- [pnpm 9](https://pnpm.io/) — Node.js package manager (Corepack) |
| 19 | + |
| 20 | +## Quick Start |
| 21 | + |
| 22 | +### Install |
| 23 | + |
| 24 | +| | Command | Directory | |
| 25 | +|---|---|---| |
| 26 | +| Backend | `uv sync --all-extras` | `backend/` | |
| 27 | +| Frontend | `pnpm install` | repo root | |
| 28 | + |
| 29 | +### Build |
| 30 | + |
| 31 | +| | Command | Directory | What it does | |
| 32 | +|---|---|---|---| |
| 33 | +| Backend | `uv build` | `backend/` | Build Python package — runs `pnpm buildUi`, then copies assets into `backend/chainlit/frontend/dist/` and `backend/chainlit/copilot/dist/` | |
| 34 | +| Frontend | `pnpm run buildUi` | repo root | Build libs + frontend JS assets | |
| 35 | +| Frontend (libs only) | `pnpm run build:libs` | repo root | Build only `react-client` and `copilot` libs | |
| 36 | + |
| 37 | +### Dev servers |
| 38 | + |
| 39 | +| | Command | Directory | URL | |
| 40 | +|---|---|---|---| |
| 41 | +| Backend | `uv run chainlit run chainlit/sample/hello.py -h` | `backend/` | http://localhost:8000 | |
| 42 | +| Frontend | `pnpm run dev` | `frontend/` | http://localhost:5173 (proxies to :8000) | |
| 43 | + |
| 44 | +### Tests |
| 45 | + |
| 46 | +| | Command | Directory | |
| 47 | +|---|---|---| |
| 48 | +| Backend (all) | `uv run pytest --cov=chainlit/` | `backend/` | |
| 49 | +| Backend (single file) | `uv run pytest tests/test_file.py` | `backend/` | |
| 50 | +| Frontend unit | `pnpm test` | `frontend/` | |
| 51 | +| E2E (Cypress) | `pnpm test` | repo root | |
| 52 | + |
| 53 | +### Lint & Format |
| 54 | + |
| 55 | +| | Command | Directory | |
| 56 | +|---|---|---| |
| 57 | +| Lint all | `pnpm run lint` | repo root | |
| 58 | +| Lint frontend only | `pnpm run lintUi` | repo root | |
| 59 | +| Format Python | `uv run ruff format chainlit/ tests/` | `backend/` | |
| 60 | +| Format JS/TS | `pnpm run formatUi` | repo root | |
| 61 | + |
| 62 | +### Type checking |
| 63 | + |
| 64 | +| | Command | Directory | |
| 65 | +|---|---|---| |
| 66 | +| Python (mypy) | `uv run dmypy run -- chainlit/ tests/` | `backend/` | |
| 67 | +| TypeScript | `tsc --noemit` | `frontend/` | |
| 68 | + |
| 69 | +Run `pnpm run lint` before committing — CI enforces this. |
| 70 | + |
| 71 | +### Commits |
| 72 | + |
| 73 | +This project uses [Conventional Commits](https://www.conventionalcommits.org/). Format: `<type>(<optional scope>): <description>`. |
| 74 | + |
| 75 | +Common types: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `ci`. Scope is optional but encouraged (e.g. `fix(data): ...`, `feat(i18n): ...`). |
| 76 | + |
| 77 | +All commits made with AI assistance **must** include a `Co-Authored-By` trailer identifying the AI agent. Add it as the last line of the commit message body: |
| 78 | + |
| 79 | +``` |
| 80 | +Co-Authored-By: <Agent Name> <agent-email-or-noreply> |
| 81 | +``` |
| 82 | + |
| 83 | +Examples: |
| 84 | +- `Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>` |
| 85 | +- `Co-Authored-By: GitHub Copilot <noreply@github.com>` |
| 86 | +- `Co-Authored-By: Gemini CLI <noreply@google.com>` |
| 87 | + |
| 88 | +## Tech Stack |
| 89 | + |
| 90 | +| Layer | Stack | |
| 91 | +|---|---| |
| 92 | +| **Frontend** | React 18, TypeScript 5.2, Vite 5, Tailwind CSS 3, Vitest, Zod 3 | |
| 93 | +| **Frontend (state & routing)** | Recoil, React Router 6, react-hook-form, socket.io-client, SWR | |
| 94 | +| **Frontend (rendering)** | react-markdown + remark-gfm/math + rehype-katex/raw, highlight.js, lucide-react (icons), Radix UI (primitives), Plotly.js | |
| 95 | +| **Backend** | Python 3.13, FastAPI, Starlette, Uvicorn, python-socketio, Pydantic 2, PyJWT, httpx | |
| 96 | +| **LLM integrations** | MCP, LangChain, LlamaIndex, OpenAI SDK, Semantic Kernel, MistralAI | |
| 97 | +| **Infra / persistence** | SQLAlchemy (PostgreSQL/SQLite), DynamoDB + S3 (boto3), Azure Blob / Data Lake, Google Cloud Storage, LiteralAI | |
| 98 | +| **DX** | Husky (pre-commit), ESLint, Prettier, ruff, mypy (dmypy), pytest, Cypress | |
| 99 | + |
| 100 | +## Architecture |
| 101 | + |
| 102 | +### Monorepo structure |
| 103 | + |
| 104 | +``` |
| 105 | +backend/ # Python package (published to PyPI as "chainlit") |
| 106 | +frontend/ # React app (built output served by backend) |
| 107 | +libs/ |
| 108 | + react-client/ # @chainlit/react-client — published npm package with React hooks |
| 109 | + copilot/ # Copilot widget (embedded chat bubble) |
| 110 | +cypress/ # E2E tests |
| 111 | +``` |
| 112 | + |
| 113 | +The pnpm workspace includes `frontend/`, `libs/react-client/`, and `libs/copilot/`. The built frontend assets are copied into `backend/chainlit/frontend/dist/` and served as static files. |
| 114 | + |
| 115 | +### Backend (`backend/chainlit/`) |
| 116 | + |
| 117 | +**Entry point for user apps**: `__init__.py` re-exports all public API decorators and classes. |
| 118 | + |
| 119 | +**Key files:** |
| 120 | +- `server.py` — FastAPI app, all REST routes (auth, elements, threads, file upload), serves the built frontend SPA, mounts the SocketIO app |
| 121 | +- `socket.py` — SocketIO event handlers for real-time WebSocket communication (connect, message, audio, etc.) |
| 122 | +- `callbacks.py` — Decorator functions registered via `@cl.on_message`, `@cl.on_chat_start`, `@cl.on_audio_chunk`, etc. These store functions on `config.code.*` |
| 123 | +- `config.py` — Reads `.chainlit/config.toml` from `APP_ROOT`. `ChainlitConfig` holds both static TOML config and runtime user-registered callbacks. `APP_ROOT` defaults to `os.getcwd()`. |
| 124 | +- `session.py` — `WebsocketSession` (per-connection state: user, files, MCP connections, message queue) and `HTTPSession` |
| 125 | +- `context.py` — `ChainlitContext` per-coroutine context variable (similar to thread-local), providing access to the current session and emitter |
| 126 | +- `emitter.py` — Sends events back to the frontend through the SocketIO session |
| 127 | +- `data/base.py` — `BaseDataLayer` ABC for persistence (threads, steps, elements, users, feedback). Implementations: `sql_alchemy.py`, `dynamodb.py`, `literalai.py` |
| 128 | +- `auth/` — JWT creation/validation (`jwt.py`), OAuth state cookies (`cookie.py`) |
| 129 | +- `types.py` — Shared Pydantic models for API request/response types |
| 130 | + |
| 131 | +**Data layer pattern**: The data layer is optional (no persistence by default). Register a custom implementation with `@cl.data_layer` decorator or use the built-in SQLAlchemy/DynamoDB/LiteralAI implementations. The `@queue_until_user_message()` decorator on `BaseDataLayer` methods queues write operations until the first user message arrives. |
| 132 | + |
| 133 | +**Integrations**: `langchain/`, `llama_index/`, `openai/`, `semantic_kernel/`, `mistralai/` — each provides callback handlers that bridge those frameworks into Chainlit steps/messages. |
| 134 | + |
| 135 | +### Frontend (`frontend/src/`) |
| 136 | + |
| 137 | +React 18 + TypeScript + Vite, styled with Tailwind CSS and Radix UI primitives. |
| 138 | + |
| 139 | +- `main.tsx` — React root, wraps app in `RecoilRoot` and `ChainlitContext.Provider` |
| 140 | +- `App.tsx` — Handles auth readiness, chat profile selection, and WebSocket connection lifecycle |
| 141 | +- `router.tsx` — Client-side routes: `/` (Home), `/thread/:id`, `/element/:id`, `/login`, `/login/callback`, `/share/:id`, `/env` |
| 142 | +- `state/` — Recoil atoms: `chat.ts` (messages, elements, tasks), `project.ts` (config, session), `user.ts` (env vars) |
| 143 | +- `components/chat/` — Core chat UI (message list, input bar, elements, audio) |
| 144 | +- `components/header/` — Top navigation bar |
| 145 | +- `components/LeftSidebar/` — Thread history sidebar |
| 146 | + |
| 147 | +### `@chainlit/react-client` (`libs/react-client/src/`) |
| 148 | + |
| 149 | +Publishable npm package — the bridge between the React UI and the backend WebSocket. |
| 150 | + |
| 151 | +- `api.ts` — `ChainlitAPI` class: HTTP calls to backend REST endpoints |
| 152 | +- `useChatSession.ts` — Manages socket.io connection lifecycle |
| 153 | +- `useChatMessages.ts` — Exposes message tree state |
| 154 | +- `useChatData.ts` — Exposes elements, actions, tasklists, connection status |
| 155 | +- `useChatInteract.ts` — `sendMessage`, `replyMessage`, `callAction`, `stopTask`, `clear` |
| 156 | +- `state.ts` — Recoil atoms shared between the lib and consuming apps |
| 157 | + |
| 158 | +State is managed via Recoil; consuming apps must wrap the tree in `<RecoilRoot>` and provide a `ChainlitAPI` instance via `ChainlitContext.Provider`. |
| 159 | + |
| 160 | +### Communication flow |
| 161 | + |
| 162 | +1. User sends a message → `useChatInteract.sendMessage` → emits `client_message` over SocketIO |
| 163 | +2. Backend `socket.py` handler receives it → calls `config.code.on_message(message)` |
| 164 | +3. User's app calls `cl.Message(...).send()` → `emitter.py` emits `new_message` back over SocketIO |
| 165 | +4. Frontend `useChatMessages` updates Recoil state → component re-renders |
| 166 | + |
| 167 | +### App configuration |
| 168 | + |
| 169 | +Apps configure Chainlit via `.chainlit/config.toml` (created automatically on first run). Key sections: `[project]` (auth, session timeouts, CORS), `[UI]` (name, theme, layout). |
| 170 | + |
| 171 | +--- |
| 172 | + |
| 173 | +## Documentation Verification Requirements |
| 174 | + |
| 175 | +Before writing/modifying code, verify against official docs. |
| 176 | + |
| 177 | +**Lookup order**: Context7 MCP (preferred) → WebFetch → WebSearch. |
| 178 | + |
| 179 | +Pre-resolved Context7 library IDs: [docs/context7.md](docs/context7.md) |
| 180 | + |
| 181 | +Cross-reference API signatures and patterns during implementation. When uncertain, always check docs rather than relying on training data. |
0 commit comments