Architecture Overview
Current CloudCLI UI architecture for contributors: React feature slices, Express modules, provider abstractions, SQLite session indexing, WebSockets, plugins, Browser Use, and deployment modes.
Architecture Overview
Want to contribute? Start with the CONTRIBUTING.md in the repository for commit conventions, branch naming, and the pull request process. Then use this page to understand how the current app is put together. For local setup, see Local Development Setup.
Last reviewed against the app source: June 24, 2026.
CloudCLI is now a multi-provider developer workspace rather than a Claude-only web UI. It includes chat, shell access, project/session indexing, MCP management, plugins, skills, Browser Use, and optional desktop/cloud packaging. For lower-level request and transport details, see the Network Architecture Guide.
Stack
| Layer | Current implementation |
|---|---|
| Frontend | React 18, Vite, Tailwind CSS, CodeMirror, xterm.js |
| Backend | Node.js, Express, TypeScript/JavaScript hybrid under server/ |
| Persistence | better-sqlite3 for users, API keys, projects, sessions, settings, notifications, and scan state |
| Real-time transport | One ws WebSocket server with routed chat, shell, plugin proxy, and Browser Use viewer connections |
| Agent providers | Claude, Codex, Cursor, Gemini, and OpenCode provider runtimes |
| Shell runtime | node-pty for interactive terminal sessions |
| Packaging | Web app, npm CLI package, optional Electron desktop build, Docker/cloud deployment support |
Repository Layout
claudecodeui/
src/ # React frontend
components/ # Feature slices: chat, sidebar, file tree, git, MCP, plugins, settings, Browser Use, etc.
contexts/ # Cross-cutting React contexts
hooks/ # Shared frontend hooks
stores/ # Client state stores
types/ # Frontend/shared type definitions
utils/ # API, clipboard, dates, notifications, browser helpers
server/ # Express backend and provider runtimes
index.js # HTTP app, route registration, WebSocket dependency wiring, static serving
routes/ # Legacy REST route modules still in use
modules/ # Newer domain modules with services, routes, repositories, and tests
database/ # SQLite connection, schema, migrations, repositories
projects/ # Project CRUD, clone/delete/star, project/session listing
providers/ # Provider registry and provider facets for auth, MCP, skills, models, sessions
websocket/ # Unified WebSocket gateway and protocol services
browser-use/ # Browser Use sessions, settings, MCP bridge, viewer proxy
middleware/ # JWT/API-key/auth middleware
services/ # Shared backend services such as web push/VAPID orchestration
shared/ # Shared backend interfaces, types, and utility functions
utils/ # Runtime paths, plugin process manager, URL detection, command parsing, etc.
public/ # Public static files, icons, API docs HTML
dist/ # Built frontend output
dist-server/ # Compiled backend output
docker/ # Provider/container support files
plugins/ # Example/starter plugin assetsThe backend is intentionally hybrid. Older endpoints still live in server/routes, while newer areas live in server/modules/*. New backend work should usually follow the module shape unless it is extending an existing legacy route.
Request Flow
The Express app in server/index.js is the composition root.
- It loads environment configuration and initializes the HTTP server.
- It initializes the SQLite-backed database module.
- It creates a single WebSocket server via
server/modules/websocketand injects provider spawn/abort functions, auth callbacks, shell helpers, plugin port lookup, and Browser Use viewer hooks. - It registers public routes such as
/healthand/api/auth. - It protects most
/api/*routes with API-key validation and JWT authentication. - It serves
public/and the built React app fromdist/.
Most frontend API calls go through src/utils/api.js. Realtime chat and terminal flows use WebSocket contexts/hooks rather than polling. The user-facing chat behavior is covered in Chat Interface, while network boundaries are covered in the Network Architecture Guide.
Frontend Organization
Frontend code is organized by product feature under src/components/* rather than by generic component type.
| Area | Responsibility |
|---|---|
chat | Provider chat UI, live event handling, permissions, tools, message rendering. See Chat Interface. |
sidebar and main-content | Project/session navigation and primary workspace layout. See Session Management. |
file-tree and code-editor | Workspace browsing and editing. See File Explorer & Editor. |
git-panel | Git status, diffs, staging, commits, and related workflows. See Git Explorer. |
mcp | Provider-aware MCP server management. See MCP Servers. |
provider-auth | Provider install/auth/setup state surfaces. See Prerequisites. |
plugins | Plugin UI and plugin lifecycle controls. See Plugin System Overview. |
skills | Provider skill discovery and creation UI. See Skills. |
settings | User, app, provider, device, notification, and Browser Use settings. See Environment Variables for runtime configuration. |
browser-use | Browser Use session panel and viewer controls. See Browser Use. |
Shared state lives in React contexts, hooks, and stores. Provider names are mirrored in frontend and backend shared types, so adding a provider is a cross-cutting change.
Backend Modules
The newer backend architecture uses module directories that own their routes, services, tests, and storage adapters.
| Module | Responsibility |
|---|---|
database | Opens SQLite, owns schema/migrations, exposes repositories for users, API keys, credentials, projects, sessions, app config, notification preferences, VAPID keys, push subscriptions, and scan state |
projects | Project discovery, clone/delete/star/archive behavior, TaskMaster detection, and project/session aggregation |
providers | Provider registry plus provider auth, MCP config, model, skill, session history, and session synchronization services |
websocket | Shared WebSocket gateway for chat streaming, shell PTYs, plugin proxying, auth, run registry, replay buffers, and writer adapters |
browser-use | Browser Use settings, session lifecycle, viewer token validation, viewer/WebSocket proxying, and MCP bridge routes |
Legacy route files under server/routes still handle areas such as Git, commands, settings, auth, plugins, TaskMaster, Gemini compatibility routes, user operations, and agent API routes.
Provider System
CloudCLI supports provider-specific behavior through server/modules/providers.
Current provider ids are claude, codex, cursor, gemini, and opencode.
Each provider exposes facets for auth, MCP config, skills, sessions, session synchronization, and models. The registry exports the available providers, while shared services consume the common provider contract.
Provider-specific MCP storage is not a single Claude config file anymore. It is normalized through provider implementations, for example Claude .mcp.json, Codex TOML config, Cursor/Gemini JSON config, and OpenCode JSON/JSONC config. The user-facing setup surface is documented in MCP Servers.
Sessions and Persistence
The app-facing session id is stored separately from the provider-native session id.
server/modules/database/schema.ts defines the sessions table with:
session_id: stable id used by the CloudCLI frontend and APIprovider: provider id such asclaudeorcodexprovider_session_id: provider-native id used by the CLI/SDK or on-disk historyproject_path: workspace associationjsonl_path: file-backed session source when applicable- archive and timestamp fields
This separation lets the UI keep a stable session identity even when the provider announces or changes its own id during a run.
Session synchronization scans provider artifacts and writes normalized rows into SQLite. The scan_state table tracks incremental scan progress. Providers differ in where they store history: Claude, Codex, Cursor, and Gemini scan JSONL-like artifacts; OpenCode reads from its shared SQLite database. For the user-facing model, see Session Management.
WebSocket Gateway
CloudCLI uses a single WebSocket server created by server/modules/websocket/index.ts. It routes connections by pathname:
| Path | Handler |
|---|---|
/ws | Chat streaming and run subscription protocol |
/shell | Interactive PTY terminal sessions |
/plugin-ws/:pluginName | Proxy to a running plugin WebSocket server |
/api/browser-use/sessions/:sessionId/viewer/websockify | Browser Use viewer WebSocket proxy |
The chat protocol uses normalized server-to-client frames with a kind field. Live provider runs are tracked by chat-run-registry.service.ts, which assigns sequence numbers, keeps a replay buffer, tracks processing state, maps provider ids back to app session ids, and suppresses duplicate completion events.
The shell protocol is separate from chat. Shell sessions use node-pty, can reconnect, replay buffered output, resize the terminal, and detect authentication URLs in provider login flows. For how these routes sit on the network, see the Network Architecture Guide.
Authentication and Security Boundaries
CloudCLI has several auth layers:
- Optional API-key validation for
/api/*when configured - JWT-based user authentication for protected app routes
- WebSocket authentication for chat, shell, and plugin proxy paths
- Local-token protection for Browser Use MCP bridge routes
- Viewer-token validation for Browser Use viewer access
Filesystem operations are scoped through workspace validation helpers. Project file reads and writes resolve paths under the project root instead of trusting client-provided paths. Related setup and operational guidance lives in Environment Variables, Tools & Permissions, and Common Issues.
Plugins
Plugin support is managed by backend utilities such as plugin-loader and plugin-process-manager, the /api/plugins routes, frontend plugin context/UI, and the WebSocket proxy path.
At runtime, enabled plugin servers can be started, assigned local ports, and reached by the frontend through the CloudCLI server instead of directly exposing each plugin process. Start with Plugin System Overview, then see Getting Started, Manifest Reference, Frontend API Reference, Backend Servers, and the Plugin Security Model.
Browser Use
The Browser Use integration is its own backend module and frontend panel. It includes settings storage, session lifecycle routes, a Browser Use MCP bridge, viewer token validation, static/viewer proxying, and a WebSocket viewer path handled by the shared WebSocket server.
Because the viewer has its own token model, Browser Use routes have a custom auth wrapper rather than using only the normal app JWT middleware. See Browser Use for the product-level guide.
Deployment Modes
| Mode | Notes |
|---|---|
| Local development | npm run dev starts the backend with tsx and the Vite frontend dev server. See Local Development Setup. |
| Built server | npm run build creates dist/ and dist-server/, then npm run server runs the compiled server. |
| npm package | The cloudcli bin points at dist-server/server/cli.js. See Install via npm. |
| Remote/self-hosted | Run on a VPS, LAN host, or tunnel. See Self-hosting on a Remote Server. |
| Cloud/container | Docker support keeps the server, provider runtimes, and workspace filesystem isolated per environment. See What is CloudCLI Cloud? and Running and Previewing Your App. |
From the React app's perspective, these modes still talk to the same Express API and WebSocket gateway. The main differences are process supervision, filesystem location, and isolation boundary.