An AI-assisted client experience and operator workspace for Modo Studio. Ren, the public-facing assistant, answers questions from approved studio knowledge, preserves anonymous conversations, and hands visitors to a human operator without losing context.
The project combines a responsive studio website, a retrieval-augmented chatbot, a persistent FastAPI backend, and a protected real-time operator inbox in one repository.
Ren lives directly inside the Modo Studio website, streams grounded answers, restores previous visitor conversations, and offers an expert handoff when a request needs human attention.
The operator inbox provides conversation search and filtering, visitor presence, complete message history, human takeover, operator replies, return-to-Ren controls, and resolution workflows.
- Grounded studio answers — retrieval-augmented responses use only approved Modo Studio knowledge.
- Live response streaming — server-sent events deliver status, answer chunks, citations, and completion metadata.
- Persistent anonymous conversations — HttpOnly visitor sessions restore multiple threads without exposing credentials to JavaScript.
- Human handoff — visitors can record an expert request while operators receive the conversation and its context.
- Atomic operator takeover — PostgreSQL row locks prevent Ren and a human operator from owning the same turn concurrently.
- Protected operator inbox — admin credentials are exchanged for a signed HttpOnly session rather than stored in browser state.
- Knowledge operations — administrators can ingest, replace, inspect, retry, and delete Markdown, text, and text-based PDF documents.
- Provider isolation — deterministic providers support repeatable tests; live adapters connect Groq, Cloudflare BGE embeddings, Pinecone, and Jina or an optional local reranker.
- Fail-closed production configuration — missing credentials or unsafe defaults fail validation instead of silently producing ungrounded answers.
flowchart LR
Visitor[Visitor] --> Web[React + Vite website]
Operator[Studio operator] --> Desk[Operator inbox]
Web -->|REST + SSE| API[FastAPI application]
Desk -->|Protected admin API| API
API --> Auth[Visitor and admin authorization]
API --> Chat[Chat orchestration]
API --> Ops[Handoff and operator workflows]
API --> Ingest[Knowledge ingestion]
Auth --> DB[(PostgreSQL / Neon)]
Chat --> DB
Ops --> DB
Ingest --> DB
Chat --> Groq[Groq LLM]
Chat --> Embed[Cloudflare Workers AI / BGE]
Embed --> Pinecone[(Pinecone index)]
Pinecone --> Rerank[Jina or local reranker]
Rerank --> Chat
Ingest --> Embed
Ingest --> Pinecone
- The browser creates or restores an anonymous visitor session and conversation.
- FastAPI authenticates the conversation and locks its row to serialize concurrent turns.
- The router classifies the request as knowledge, clarification, handoff, or action.
- Knowledge questions are embedded and queried against the configured Pinecone collection.
- Weak candidates are removed and the remaining evidence is reranked.
- Groq generates an answer constrained to the retrieved evidence and Modo Studio's versioned assistant rules.
- The finalized answer is streamed to the browser and persisted with structured source metadata.
- Reusing the same request ID returns the stored result, preventing duplicate turns after retries.
Provider clients and local models are initialized lazily. Importing the application does not contact external services or download an embedding model.
| Layer | Technology | Responsibility |
|---|---|---|
| Web application | React 19, TypeScript, Vite 8 | Public website, chat experience, and operator dashboard |
| UI system | Tailwind CSS 4, Radix UI, Lucide | Responsive layout, accessible primitives, and icons |
| API | FastAPI, Uvicorn, Pydantic | Typed REST endpoints, SSE streaming, validation, and OpenAPI |
| Persistence | PostgreSQL, SQLAlchemy 2, asyncpg | Conversations, messages, sessions, handoffs, knowledge metadata, and idempotency |
| Schema management | Alembic | Versioned PostgreSQL migrations |
| Language model | Groq | Routing, standalone retrieval queries, summaries, and grounded responses |
| Embeddings | Cloudflare Workers AI / BGE | Hosted, normalized semantic vectors without local model memory |
| Vector search | Pinecone | Namespaced knowledge retrieval |
| Reranking | Jina AI or local CrossEncoder | Final evidence ordering |
| Testing | Pytest, Vitest, Testing Library | Backend integration and frontend component coverage |
| Quality | Ruff, Oxlint, TypeScript | Python linting, frontend linting, and static type checking |
| Automation | GitHub Actions | PostgreSQL-backed backend checks and frontend CI |
modo-studio-intelligence-desk/
├── app/ FastAPI application
│ ├── api/ Routes and request dependencies
│ ├── core/ Settings, security, and shared errors
│ ├── db/ SQLAlchemy engine and models
│ ├── providers/ Deterministic and live AI providers
│ ├── schemas/ Public API contracts
│ └── services/ Chat, retrieval, ingestion, memory, and handoffs
├── config/ Versioned business and assistant behavior
├── frontend/ React website, Ren chat, and operator inbox
├── knowledge/source/ Approved Markdown knowledge documents
├── migrations/ Alembic migrations
├── scripts/ Knowledge and operational utilities
├── tests/ Backend integration tests and fixtures
├── design/ Original supplied design assets
├── docs/ Architecture, handoff, plans, and references
├── compose.yaml Local API and PostgreSQL services
├── compose.test.yaml Disposable PostgreSQL test service
└── Dockerfile Backend container image
See docs/PROJECT_STRUCTURE.md for detailed ownership boundaries.
- Python 3.11 or newer; CI uses Python 3.12
- Node.js 22 and npm
- PostgreSQL 16 locally, or a managed PostgreSQL service such as Neon
- Docker only if you want the included local/test PostgreSQL services
git clone https://github.com/hammadproject/modo-studio-intelligence-desk.git
Set-Location modo-studio-intelligence-desk
Copy-Item .env.example .envFill .env with your own development values. Never commit .env; the repository tracks only .env.example.
For deterministic development and backend tests:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txtFor lightweight live Groq, Cloudflare embeddings, Pinecone, and Jina providers:
.\.venv\Scripts\python.exe -m pip install -r requirements-live.txtTo run the embedding model or reranker locally instead, install the optional ML stack:
.\.venv\Scripts\python.exe -m pip install -r requirements-local-ml.txtStart the included local database:
docker compose up -d db
.\.venv\Scripts\python.exe -m alembic upgrade headIf DATABASE_URL points to Neon or another managed PostgreSQL instance, Docker is unnecessary. Apply migrations only to a database you explicitly intend to modify.
npm.cmd --prefix frontend ciBackend:
.\.venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reloadFrontend, in a second terminal:
npm.cmd --prefix frontend run dev -- --host 127.0.0.1Open:
- Website: http://127.0.0.1:5173
- Operator inbox: http://127.0.0.1:5173/admin
- API documentation: http://127.0.0.1:8000/docs
- Readiness: http://127.0.0.1:8000/health/ready
The frontend derives its default API hostname from the page hostname. Set VITE_API_BASE_URL only when the API is hosted elsewhere; never place server credentials in a VITE_ variable.
For the hosted Vercel frontend, use VITE_API_BASE_URL=/. The frontend's Vercel configuration proxies API and health requests to the Render backend on the same browser origin, preserving secure visitor and operator sessions.
PROVIDER_MODE=deterministic provides network-free, repeatable behavior for development and automated tests. It is explicit—production validation will not permit deterministic mode.
Live mode requires:
PROVIDER_MODE=live- A Groq API key
- A Cloudflare account ID and Workers AI API token when
EMBEDDING_PROVIDER=cloudflare - A Pinecone API key
- An existing Pinecone index matching
EMBEDDING_DIMENSION - A Jina API key when
RERANKER_PROVIDER=jina - Non-default admin and conversation-token secrets
The application does not create or reset external Pinecone indexes automatically.
All supported settings are documented in .env.example. The primary groups are:
| Group | Key settings |
|---|---|
| Runtime | ENVIRONMENT, PROVIDER_MODE, LOG_LEVEL, CORS_ALLOW_ORIGINS |
| Database | DATABASE_URL |
| Security | ADMIN_API_KEY, CONVERSATION_TOKEN_PEPPER, session and cookie settings |
| LLM | LLM_PROVIDER, LLM_MODEL, GROQ_API_KEY |
| Embeddings | EMBEDDING_PROVIDER, Cloudflare credentials and model, EMBEDDING_DIMENSION |
| Retrieval | PINECONE_API_KEY, VECTOR_INDEX_NAME, VECTOR_COLLECTION, candidate and top-k limits |
| Reranking | RERANKER_PROVIDER, local/Jina model settings, JINA_API_KEY |
| Memory | History budget and summary trigger settings |
| Limits | Message, upload, chunking, timeout, retry, and rate-limit settings |
For Neon deployments, use the pooled application connection string when appropriate and retain Neon's required SSL parameters. Keep direct administrative URLs separate from public configuration.
Approved source material lives in knowledge/source/. With the API running and authorized configuration available, ingest the packaged Modo Studio documents with:
.\.venv\Scripts\python.exe -m scripts.ingest_modoIngestion behavior includes:
.txt,.md, and text-based.pdfinput- Heading-aware Markdown chunking
- Deterministic document, chunk, and vector identities
- No-op handling for unchanged documents
- Replacement of stale vectors when content changes
- Partial-failure state with safe retry support
- Collection-scoped retrieval and structured citation metadata
OCR, website scraping, and automatic external-index creation are intentionally outside the current scope.
| Method | Endpoint | Access | Purpose |
|---|---|---|---|
GET |
/health/live |
Public | Process liveness |
GET |
/health/ready |
Public | Database, provider, and knowledge readiness |
POST |
/api/v1/conversations |
Public | Create a visitor conversation |
GET |
/api/v1/visitor/conversations |
Visitor session | Restore the visitor's conversations |
POST |
/api/v1/conversations/{id}/messages |
Conversation | Submit an idempotent chat turn |
POST |
/api/v1/conversations/{id}/messages/stream |
Conversation | Stream status, answer chunks, and completion |
GET |
/api/v1/conversations/{id}/messages |
Conversation | Read ordered history |
POST |
/api/v1/conversations/{id}/handoffs |
Conversation | Record an expert request |
POST |
/api/v1/admin/session |
Admin key | Create an HttpOnly admin session |
GET |
/api/v1/admin/conversations |
Admin session | Search and filter the operator inbox |
POST |
/api/v1/admin/conversations/{id}/takeover |
Admin session | Transfer the thread to an operator |
POST |
/api/v1/admin/conversations/{id}/messages |
Admin session | Send an operator reply |
POST |
/api/v1/admin/conversations/{id}/release |
Admin session | Return the thread to Ren |
POST |
/api/v1/admin/conversations/{id}/resolve |
Admin session | Resolve the thread |
POST |
/api/v1/admin/knowledge/documents |
Admin credential | Ingest or replace knowledge |
POST |
/api/v1/admin/knowledge/documents/{id}/retry |
Admin credential | Retry partial indexing |
DELETE |
/api/v1/admin/knowledge/documents/{id} |
Admin credential | Remove a document and its vectors |
The complete interactive contract is available through FastAPI at /docs.
- Conversation identifiers are not credentials.
- Browser visitors use an opaque HttpOnly session; bearer conversation credentials remain available for non-browser clients.
- Only keyed hashes of conversation and visitor credentials are stored.
- Admin keys are exchanged for signed, time-limited HttpOnly sessions.
- Every history and message operation is scoped to its authorized conversation.
- PostgreSQL row locks serialize concurrent turns and operator state transitions.
- Request IDs enforce idempotency and make failed turns safely retryable.
- Retrieved source metadata is generated only from approved indexed chunks.
- Provider credentials, database credentials, admin keys, and token peppers remain server-side.
- Logs omit conversation bodies by default and include correlation IDs for operations.
- Document and message sizes, CORS origins, provider timeouts, retries, and per-IP request rates are bounded.
The built-in rate limiter is process-local. Production deployments with multiple API instances should enforce distributed limits at an edge gateway or shared store.
The backend suite requires a disposable PostgreSQL database. Never point these tests at production because the fixtures truncate test tables.
docker compose -f compose.test.yaml up -d --wait
$env:DATABASE_URL='postgresql+asyncpg://chirpy_test:chirpy_test@localhost:55432/chirpy_test'
.\.venv\Scripts\python.exe -m alembic upgrade head
.\.venv\Scripts\python.exe -m ruff check app migrations scripts tests
.\.venv\Scripts\python.exe -m pytest -q
docker compose -f compose.test.yaml downnpm.cmd --prefix frontend run typecheck
npm.cmd --prefix frontend run lint
npm.cmd --prefix frontend run test -- --run
npm.cmd --prefix frontend run buildGitHub Actions runs the same backend checks against an isolated PostgreSQL 16 service and performs the complete frontend verification pipeline.
/health/liveconfirms that the process is accepting requests./health/readydistinguishes database, provider configuration, and knowledge-base availability.- An empty knowledge base reports degraded readiness rather than pretending grounded answers are available.
- Provider failures return typed service errors and leave idempotent requests retryable.
- Human handoffs report only what has actually been recorded; the system does not promise response times.
- Conversation deletion cascades through dependent messages, requests, handoffs, and tool executions.
- External vectors are removed before knowledge metadata is deleted.
- There is deliberately no bulk database or vector-index reset endpoint.
- Replace polling with distributed real-time operator events
- Add multi-operator accounts, roles, and audit history
- Add external email, Slack, or push handoff notifications
- Optimize operator-inbox aggregation for high-latency managed databases
- Add production observability and distributed rate limiting
- Expand knowledge-source connectors with explicit review and approval workflows
Released under the MIT License.

