This page introduces Open Chat Studio (OCS), its high-level purpose, the major subsystems it comprises, and how they relate to each other. It is intended as a starting point for navigating the codebase. Detailed treatment of each subsystem is in the child pages of this wiki.
Open Chat Studio (OCS) is a Django-based web application for building and deploying AI-powered chatbots. Teams can define chatbots (called Experiments), configure their conversational behavior using visual pipelines, connect them to external messaging platforms (Telegram, WhatsApp, Slack, Facebook Messenger, Web, API), and analyze conversation data through a comprehensive review and evaluation system.
Core concepts:
Experiment (in apps.experiments.models.Experiment) defines a chatbot's configuration, including its pipeline, LLM provider, consent form, and other settingsExperimentSession (in apps.experiments.models.ExperimentSession) represents one conversation between a Participant and an ExperimentPipeline (in apps.pipelines.models.Pipeline) is a directed graph of processing nodes compiled into a LangGraph state machine at runtimeChatMessage records linked to a Chat, enabling full session review, annotation, and exportSources: pyproject.toml1-7 apps/experiments/models.py518-632 apps/pipelines/models.py104-175
The codebase is a standard Django project. Major Django apps map directly to subsystems:
| Django App | Subsystem |
|---|---|
apps.experiments | Core domain models: Experiment, ExperimentSession, Participant, consent forms, surveys, source materials |
apps.pipelines | Pipeline builder, visual editor, and LangGraph-based executor |
apps.chat | Chat infrastructure: ChannelBase, PipelineBot, Chat, ChatMessage |
apps.channels | Platform-specific channel integrations: ExperimentChannel, webhook handlers, async message tasks |
apps.service_providers | LLM service abstraction (LlmService), voice providers, trace providers |
apps.assistants | OpenAI Assistant synchronization and file resource management |
apps.documents | Collection management, local/remote indexing (IndexManager), file processing |
apps.events | Event system: StaticTrigger, TimeoutTrigger, ScheduledMessage, event actions |
apps.annotations | Tagging system: Tag, CustomTaggedItem for messages and sessions |
apps.api | REST API: chat endpoints, OpenAI-compatible API, participant data management |
apps.evaluations | Evaluation framework: datasets, evaluators, evaluation runs |
apps.trace | Trace storage: Trace model, tracing UI, span management |
apps.teams | Multi-tenancy: Team, BaseTeamModel, team-scoped permissions |
apps.files | File upload handling: File model, S3/local storage backends |
apps.participants | Participant management views and tables |
apps.chatbots | Chatbot-focused views (experiment management under "chatbots" branding) |
apps.dashboard | Team dashboard with chatbot statistics and trends |
apps.human_annotations | Human annotation queues for session review |
apps.ocs_notifications | Notification system: in-app and email delivery |
apps.oauth | OAuth2 provider implementation for third-party integrations |
apps.mcp_integrations | MCP (Model Context Protocol) tool integrations |
apps.filters | Dynamic filtering infrastructure for tables |
assets/javascript | React/TypeScript frontend: pipeline editor (ReactFlow), chat widget (Stencil web component) |
Sources: config/settings.py89-125 pyproject.toml1-88
Top-level component diagram: how OCS subsystems relate
Sources: apps/chat/bots.py51-149 apps/chat/channels.py102-338 apps/pipelines/graph.py1-50 apps/channels/tasks.py1-50
The central models live in apps/experiments/models.py. They form the backbone that all other subsystems reference.
Experiment model relationships
Key model classes:
Experiment — the chatbot definition; supports versioning via VersionsMixin (apps/experiments/models.py515-630)ExperimentSession — one conversation between a participant and an experiment (apps/experiments/models.py1-50)Participant — a person interacting across sessions; keyed by identifier and platformPipeline — a directed graph of processing nodes attached to an Experiment (apps/pipelines/models.py104-175)For full detail, see Core Domain Models.
Sources: apps/experiments/models.py515-650 apps/pipelines/models.py104-175
When a user sends a message, it travels through several layers before a response is returned.
Message flow from platform to LLM and back
Sources: apps/chat/channels.py358-427 apps/chat/bots.py60-149 apps/pipelines/graph.py1-50 apps/channels/tasks.py1-50
Pipelines define the processing logic of a chatbot. A Pipeline is stored as a directed graph (data JSON field) composed of Node records. At runtime, PipelineGraph.build_runnable_from_pipeline() compiles this into a LangGraph StateGraph.
Key node types defined in apps.pipelines.nodes.nodes:
| Node Class | Purpose |
|---|---|
LLMResponseWithPrompt | Invokes an LLM with a configurable prompt; supports tools, RAG context injection, conversation history |
RouterNode | Uses an LLM to classify input and select a downstream edge |
StaticRouterNode | Routes based on participant data, session state, or custom conditions (no LLM call) |
RenderTemplate | Renders a Jinja2 template with pipeline state variables |
SendEmail | Sends an email via Celery task (async) |
CodeNode | Executes sandboxed Python code using RestrictedPython |
AssistantNode | Delegates message handling to an OpenAI Assistant with tool invocation |
ExtractStructuredData | Extracts JSON-structured data from LLM output using a schema |
ExtractParticipantData | Extracts and persists data to ParticipantData for long-term participant state |
PassthroughNode | Base for nodes that don't process state (StartNode, EndNode) |
StartNode | Entry point of the pipeline graph |
EndNode | Terminal node; marks conversation end |
All nodes carry typed Pydantic fields and a _process(state, context) method. The PipelineState dict flows between nodes, accumulating outputs.
The frontend pipeline editor is a React application (assets/javascript/apps/pipeline/) using ReactFlow. It renders node parameters using widget components (assets/javascript/apps/pipeline/nodes/widgets.tsx).
For full detail, see Pipeline System.
Sources: apps/pipelines/nodes/nodes.py95-670 apps/pipelines/models.py104-353 apps/chat/bots.py133-149 assets/javascript/apps/pipeline/nodes/widgets.tsx16-56
LLM access is abstracted through LlmService (in apps/service_providers/). Supported providers include OpenAI, Anthropic, Google (Gemini), Azure OpenAI, and DeepSeek. Provider credentials are stored in LlmProvider Django models; available models are stored in LlmProviderModel.
The PipelineBot in apps/chat/bots.py uses TracingService from apps/service_providers/tracing/ to wrap all LLM calls in observable spans. Traces are forwarded to LangFuse or stored locally in apps/trace/.
For full detail, see LLM Integration.
Sources: apps/chat/bots.py72-80 apps/pipelines/nodes/nodes.py411-412
ChannelBase (apps/chat/channels.py) is the abstract base class for all messaging platform integrations. Platform-specific subclasses include:
| Class | Platform |
|---|---|
TelegramChannel | Telegram |
WhatsappChannel | WhatsApp via Turn.io |
SlackChannel | Slack |
FacebookMessengerChannel | Facebook Messenger |
ApiChannel | REST API / embedded widget |
SureAdhereChannel | SureAdhere |
CommCareConnectChannel | CommCare Connect |
WebChannel | Web-based chat UI |
EvaluationChannel | Internal evaluations runner |
Each platform has a corresponding webhook view in apps/channels/views.py that enqueues a Celery task. The task instantiates the correct ChannelBase subclass and calls new_user_message().
ExperimentChannel (model in apps/channels/models.py) links an Experiment to a specific platform configuration.
For full detail, see Multi-Channel Communication.
Sources: apps/chat/channels.py313-347 apps/channels/views.py52-100 apps/channels/tasks.py1-50
OCS exposes a Django REST Framework API under apps/api/. It supports:
/api/chat/)Authentication supports API keys (ApiKey), bearer tokens, embedded widget tokens, and session cookies.
For full detail, see REST API.
Sources: apps/experiments/views/experiment.py105-180
Collection models in apps/documents/ store document sets. Collections can be indexed locally (pgvector) or remotely (e.g., OpenAI file search). When an LLMResponseWithPrompt node has collection_index_ids configured, retrieval results are injected into the LLM prompt context.
For full detail, see Document Collections and RAG.
Sources: apps/pipelines/nodes/nodes.py213-230
The event system allows automated actions to fire based on session events:
StaticTrigger — fires on named events (e.g., NEW_HUMAN_MESSAGE, CONVERSATION_ENDED_BY_USER)TimeoutTrigger — fires if no message is received within a configured durationScheduledMessage — sends a message to the bot at a scheduled future timeActions include logging, ending conversations, sending messages to the bot, starting pipelines, and scheduling future triggers. These are defined under apps/events/.
For full detail, see Event System and Automation.
Sources: apps/chat/channels.py421-423 apps/experiments/models.py679-681
All messages are stored as ChatMessage records linked to a Chat. Sessions can be tagged, annotated, reviewed by humans in annotation queues, and exported to CSV. The tag system (Tag, CustomTaggedItem) supports categorization of both sessions and individual messages.
For full detail, see Chat System.
Sources: apps/chat/bots.py221-235
Evaluation datasets (EvaluationDataset) contain test messages. EvaluationConfig links a dataset to evaluator settings. Evaluation runs execute the chatbot against the dataset asynchronously and store scored results.
For full detail, see Evaluation System.
OCS has three UI surfaces:
apps/pipelines/views.py. Uses ReactFlow for the graph canvas and Pydantic-derived JSON Schema for node configuration widgets.OcsChat) that can be dropped into external websites.Frontend assets are built with webpack and npm. Entry points are under assets/javascript/.
For full detail, see User Interfaces.
Sources: apps/pipelines/views.py90-98 assets/javascript/apps/pipeline/nodes/widgets.tsx16-56
| Concern | Technology |
|---|---|
| Web framework | Django 5.x |
| Python version | >=3.13 |
| Database | PostgreSQL (psycopg3 with connection pooling) |
| Task queue | Celery 5.x with Redis broker |
| Cache | Redis (django-redis) |
| File storage | AWS S3 (django-storages) or local filesystem |
| LLM orchestration | LangChain 1.1+ and LangGraph 0.2+ |
| Auth | django-allauth (with MFA support), djangorestframework-api-key, OAuth2 provider (django-oauth-toolkit) |
| Multi-tenancy | Team-scoped models via BaseTeamModel, team-based permissions via TeamBackend |
| Error tracking | Sentry SDK |
| Observability | LangFuse integration + internal Trace model storage |
| Frontend build | webpack, npm, React 18, TypeScript, Tailwind CSS (daisyUI components) |
| Web components | Stencil (for embeddable chat widget) |
| API docs | drf-spectacular (OpenAPI 3) |
| HTMX | django-htmx for dynamic partial updates |
| Vector store | pgvector (local) or OpenAI Vector Store (remote) |
| Deployment | Docker, environment-based settings (django-environ) |
Sources: pyproject.toml1-88 config/settings.py1-330 .env.example1-104 .pre-commit-config.yaml25
The diagram below maps the major runtime code entities to their subsystems.
Sources: apps/chat/bots.py51-149 apps/chat/channels.py102-350 apps/pipelines/graph.py1-50 apps/experiments/models.py515-680 apps/channels/tasks.py1-50
Refresh this wiki