Skip to content

Latest commit

 

History

History
195 lines (134 loc) · 11.6 KB

File metadata and controls

195 lines (134 loc) · 11.6 KB

AGENTS.md

This file provides guidance to AI agents when working with code in this repository.

Backward Compatibility (CRITICAL)

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.

MCP-First Approach (CRITICAL)

When available, ALWAYS prefer MCP servers over manual alternatives. Use Context7 for docs/API references, Serena for code navigation/refactoring/memory, and GitHub MCP for issues/PRs/actions/commits/releases/code search. Fall back to CLI tools, direct file reads, or web searches ONLY IF the corresponding MCP is unavailable or cannot fulfill the request.

Overview

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.

Prerequisites

  • Python: 3.13 (3.10+ is the framework's minimum, but development targets 3.13)
  • Node.js: 24+
  • uv — Python package manager
  • pnpm 9 — Node.js package manager (Corepack)

Quick Start

Install

Command Directory
Backend uv sync --all-extras backend/
Frontend pnpm install repo root

Build

Command Directory What it does
All JS packages pnpm build repo root Build all workspace packages (frontend, react-client, copilot) via pnpm run --recursive
Backend (PyPI) uv build backend/ Build Python package — builds JS assets first, then bundles into the Python distribution
Single JS package pnpm --filter @chainlit/react-client build repo root Build one package (useful for publishing)

Dev servers

Command Directory URL
Backend uv run chainlit run chainlit/sample/hello.py -h backend/ http://localhost:8000
Frontend pnpm run dev frontend/ http://localhost:5173 (proxies to :8000)

Tests

Command Directory
Backend (all) uv run pytest --cov=chainlit/ backend/
Backend (single file) uv run pytest tests/test_file.py backend/
Frontend unit pnpm test frontend/
E2E (Cypress) pnpm test repo root

Lint & Format

Command Directory
Lint JS/TS pnpm lint repo root
Lint fix JS/TS pnpm lint:fix repo root
Format check JS/TS pnpm format-check repo root
Format fix JS/TS pnpm format repo root
Lint Python uv run scripts/lint.py repo root
Lint fix Python uv run scripts/lint.py --fix repo root
Format check Python uv run scripts/format.py --check repo root
Format fix Python uv run scripts/format.py repo root

JS/TS lint and format commands accept file/directory arguments: pnpm lint frontend/, pnpm format-check:files frontend/src/App.tsx. Python scripts also accept file arguments: uv run scripts/lint.py backend/chainlit/server.py.

Type checking

Command Directory
Python uv run scripts/type_check.py repo root
TypeScript pnpm type-check repo root

Type checking runs on whole projects (no per-file mode).

Run pnpm lint:fix and pnpm format before committing — CI enforces checks on both.

Commits

This project uses Conventional Commits. Format: <type>(<optional scope>): <description>.

Common types: feat, fix, chore, docs, refactor, test, ci. Scope is optional but encouraged (e.g. fix(data): ..., feat(i18n): ...).

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:

Co-Authored-By: <Agent Name> <agent-email-or-noreply>

Examples:

  • Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • Co-Authored-By: GitHub Copilot <noreply@github.com>
  • Co-Authored-By: Gemini CLI <noreply@google.com>

Tech Stack

Layer Stack
Frontend React 18, TypeScript 5.2, Vite 5, Tailwind CSS 3, Vitest, Zod 3
Frontend (state & routing) Recoil, React Router 6, react-hook-form, socket.io-client, SWR
Frontend (rendering) react-markdown + remark-gfm/math + rehype-katex/raw, highlight.js, lucide-react (icons), Radix UI (primitives), Plotly.js
Backend Python 3.13, FastAPI, Starlette, Uvicorn, python-socketio, Pydantic 2, PyJWT, httpx
LLM integrations MCP, LangChain, LlamaIndex, OpenAI SDK, Semantic Kernel, MistralAI
Infra / persistence SQLAlchemy (PostgreSQL/SQLite), DynamoDB + S3 (boto3), Azure Blob / Data Lake, Google Cloud Storage, LiteralAI
DX pre-commit hooks, linting, formatting, type checking, unit testing, E2E testing

Architecture

Monorepo structure

backend/          # Python package (published to PyPI as "chainlit")
frontend/         # React app (built output served by backend)
libs/
  react-client/   # @chainlit/react-client — published npm package with React hooks
  copilot/        # Copilot widget (embedded chat bubble)
cypress/          # E2E tests

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.

Backend (backend/chainlit/)

Entry point for user apps: __init__.py re-exports all public API decorators and classes.

Key files:

  • server.py — FastAPI app, all REST routes (auth, elements, threads, file upload), serves the built frontend SPA, mounts the SocketIO app
  • socket.py — SocketIO event handlers for real-time WebSocket communication (connect, message, audio, etc.)
  • callbacks.py — Decorator functions registered via @cl.on_message, @cl.on_chat_start, @cl.on_audio_chunk, etc. These store functions on config.code.*
  • 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().
  • session.pyWebsocketSession (per-connection state: user, files, MCP connections, message queue) and HTTPSession
  • context.pyChainlitContext per-coroutine context variable (similar to thread-local), providing access to the current session and emitter
  • emitter.py — Sends events back to the frontend through the SocketIO session
  • data/base.pyBaseDataLayer ABC for persistence (threads, steps, elements, users, feedback). Implementations: sql_alchemy.py, dynamodb.py, literalai.py
  • auth/ — JWT creation/validation (jwt.py), OAuth state cookies (cookie.py)
  • types.py — Shared Pydantic models for API request/response types

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.

Integrations: langchain/, llama_index/, openai/, semantic_kernel/, mistralai/ — each provides callback handlers that bridge those frameworks into Chainlit steps/messages.

Frontend (frontend/src/)

React 18 + TypeScript + Vite, styled with Tailwind CSS and Radix UI primitives.

  • main.tsx — React root, wraps app in RecoilRoot and ChainlitContext.Provider
  • App.tsx — Handles auth readiness, chat profile selection, and WebSocket connection lifecycle
  • router.tsx — Client-side routes: / (Home), /thread/:id, /element/:id, /login, /login/callback, /share/:id, /env
  • state/ — Recoil atoms: chat.ts (messages, elements, tasks), project.ts (config, session), user.ts (env vars)
  • components/chat/ — Core chat UI (message list, input bar, elements, audio)
  • components/header/ — Top navigation bar
  • components/LeftSidebar/ — Thread history sidebar

@chainlit/react-client (libs/react-client/src/)

Publishable npm package — the bridge between the React UI and the backend WebSocket.

  • api.tsChainlitAPI class: HTTP calls to backend REST endpoints
  • useChatSession.ts — Manages socket.io connection lifecycle
  • useChatMessages.ts — Exposes message tree state
  • useChatData.ts — Exposes elements, actions, tasklists, connection status
  • useChatInteract.tssendMessage, replyMessage, callAction, stopTask, clear
  • state.ts — Recoil atoms shared between the lib and consuming apps

State is managed via Recoil; consuming apps must wrap the tree in <RecoilRoot> and provide a ChainlitAPI instance via ChainlitContext.Provider.

Communication flow

  1. User sends a message → useChatInteract.sendMessage → emits client_message over SocketIO
  2. Backend socket.py handler receives it → calls config.code.on_message(message)
  3. User's app calls cl.Message(...).send()emitter.py emits new_message back over SocketIO
  4. Frontend useChatMessages updates Recoil state → component re-renders

App configuration

Apps configure Chainlit via .chainlit/config.toml (created automatically on first run). Key sections: [project] (auth, session timeouts, CORS), [UI] (name, theme, layout).


Documentation Verification Requirements

Before writing/modifying code, verify against official docs.

Lookup order: Context7 MCP (preferred) → WebFetch → WebSearch.

Pre-resolved Context7 library IDs: docs/context7.md

Cross-reference API signatures and patterns during implementation. When uncertain, always check docs rather than relying on training data.