ChatForge

Self-hosted multi-provider LLM chat with per-user history, local/server sync controls, tools and memory, native-client APIs, streaming responses, and server-proxied or browser-direct provider access.

UI tour: Jump to screenshots.

Features

Chat and content

  • Multi-provider chat with Anthropic, OpenAI, Gemini, and VertexAI backends, with streaming and non-streaming generation and a Stop action for in-flight responses.
  • Per-user conversation storage with URL-addressable chats, folders, pin/collapse state, desktop/mobile drag-and-drop move/reorder, title regeneration, and persistent ordering.
  • Local-only chats and folders with global, per-chat, and per-folder sync/unsync controls. Local records are saved in browser storage for that account until explicitly synced or deleted.
  • Chat search across titles, IDs, context metadata, folder names, and SQLite FTS5-indexed message content, with folder/unfiled scoping and matching snippets.
  • Message editing/regeneration, retry, copy, individual deletion, sent-prompt history navigation, and token-usage/provider/timestamp footers.
  • Markdown rendering with sanitized links, syntax highlighting, KaTeX math, source links, collapsible reasoning summaries/steps, and code-block themes, wrapping, line numbers, copy, and fullscreen view.
  • Up to six text/audio/video attachments per message, bounded attachment sizes, native media playback, and a playback-disable preference.
  • Artifact CRUD with file/folder upload, path filtering, autocomplete for @path mentions, and lightweight message references that hydrate current artifact content when displayed or sent to a model.
  • Slash commands for context control and generation flow (/compact, /clear, /retry, /restore), plus persistent summaries and configurable rolling context windows.
  • Sound effects, background-completion browser notifications, configurable stream-completion auto-scroll, Enter-to-send behavior, resizable/left-or-right chat sidebar, light/dark mode, high contrast, preset accents, and arbitrary hex themes.

Providers and generation

  • Server-side LLM proxy with provider-specific request shaping and endpoint validation, plus a per-account switch and browser-direct provider fallback when proxying is disabled by the user or server.
  • OpenAI Chat Completions and Responses API support, including built-in Responses web search with returned source links and store: false requests.
  • Provider reasoning controls: OpenAI effort/summary/web-search context, Anthropic thinking budget, and Gemini/VertexAI thinking level/budget/include-thoughts.
  • Per-user provider/model catalogs with editable labels and per-model capability overrides, server-synced defaults, and a separately selectable provider/model/token budget for automatic chat titles.
  • Custom system prompts with runtime {model}, {date}, and {today} interpolation.
  • Provider-bound conversation turns include their original send timestamps so the model retains temporal context across older messages.
  • Client-side encrypted sync for provider endpoints/API keys and local-agent URL/token (PBKDF2-SHA256 + AES-GCM with a password-derived key), including selective fields and login-time unlock.

Tools and memory

  • Tool calling with a per-tool allowlist, explicit execution traces, per-call approve/deny decisions, bounded parallel read-only execution, and a configurable consecutive-call limit.
  • Workspace-scoped file read/write/list, shell command, SearXNG web search, URL fetch, memory read/write, chat/folder read/manage, appearance/settings control, and current/connected-session inspection tools.
  • Local agent process support for filesystem/shell/web tools with workspace confinement, bearer auth, CORS controls, endpoint health, and command timeouts. An agent URL is required to execute these machine-local tools.
  • Direct-provider tool definitions and results are withheld until the user grants browser-session consent to disclose them to the external provider.
  • Memory CRUD/edit/search with SQLite FTS5 indexing, origin labels (manual, tool, background), approval context for destructive writes, and admin memory search.
  • Optional incremental automatic memory consolidation: each user selects a provider/model/endpoint and encrypted API key, then a background worker creates, updates, merges, or retires durable background memories while excluding common credential, payment, and identity data.

Accounts, sync, and portability

  • Per-user authentication and RBAC (user/admin), JWT cookie sessions, bcrypt password hashing, TOTP/recovery-code 2FA, passkey (WebAuthn) sign-in, and hardened self-service password rotation.
  • Optional verified account e-mail addresses with per-address notifications for new logins, session deletion, blocked refresh-token replay, password changes, and export start/completion.
  • E-mail password recovery by username or verified address, with recovery-link proof, required TOTP/recovery-code verification for 2FA accounts, rate limiting, and revocation of existing sessions after reset.
  • Connected-device management for web and native sessions: view metadata/IP/activity, rename, revoke, permanently delete, clean stale entries, or revoke every other session.
  • Native access/refresh/session tokens with rotating refresh tokens, replay detection, password and passkey login, logout, and browser-approved device-code linking.
  • Real-time WebSocket sync with sequence-based delta catch-up, reconnect/reconciliation, backpressure limits, and granular policies/presets for folders, chats, messages, memories, artifacts, UI, settings, catalogs, encrypted secrets, and security state.
  • Full user data export as a compressed archive with status/history, expiring downloads, and secrets excluded; server deployments use async jobs while embedded deployments retain a direct-download fallback.
  • Resumable, restart-safe paged migration APIs for folders, conversations, messages, memories, artifacts, preferences, client preferences, encrypted provider config, and model catalogs, including conflict remapping and commit/rollback.
  • Server mode uses better-sqlite3 with WAL; the embedded Flutter/Android runtime uses an FTS5-enabled sql.js WASM adapter, a persistent generated secret, and database lock/resume bridge controls.

Administration and hardening

  • Admin user management (create/update/delete/reset password), detailed per-user inspection, session revocation/deletion, user and memory search, and last-admin protection.
  • Admin background-queue dashboard with stats/history, filters, auto-refresh, requeue/dead-letter handling, filtered cleanup, and managed worker spawn/stop/restart/log controls.
  • Admin system operations (optional self-update/build pipeline, dependency-change detection, service restart/status, and manual cleanup of expired auth/export records).
  • Admin database operations (state inspector, table previews, VACUUM, message/memory FTS rebuild, and parameterized SQL query runner).
  • Hardened API surface with CSRF origin enforcement, CSP/security headers, login/recovery/device-code rate limits, content/count limits, outbound DNS pinning, blocked redirects/embedded credentials, and private/custom endpoint controls.
  • Per-user isolation for chats, messages, folders, preferences, client preferences, models, memories, artifacts, sessions, passkeys, exports, migration state, sync events, background jobs, and encrypted payloads.

Quick Start

npm install
cp .env.example .env        # edit CHATFORGE_SECRET
npm run user:create -- mattia hunter2 admin
npm run dev                  # starts both Vite (5173) + Express (3069)

Open http://localhost:5173

User Management

npm run user:create -- <username> <password> [user|admin]
npm run user:list
npm run user:delete -- <username>

Admin users can open the in-app admin panel to:

  • inspect full user profiles (preferences, model catalog, memories, conversations, messages)
  • create/update/delete users and reset passwords
  • inspect and revoke user device sessions
  • search users and memories
  • operate the background queue and managed workers
  • run maintenance, service, update, and database actions

Production

npm run build                # builds React into dist/
NODE_ENV=production CHATFORGE_SECRET=replace-with-at-least-32-random-characters node server/server.js

# Run in a second service/process when using async exports, e-mail, or automatic memory
NODE_ENV=production CHATFORGE_SECRET=replace-with-at-least-32-random-characters npm run worker

The Express server serves the built frontend from dist/ and the API on the same port (3069). Set NODE_ENV in systemd/OpenRC (or inline as above), not in .env files consumed by Vite.

The background worker leases persistent jobs for e-mail delivery, archive generation, and automatic memory scans. You can run npm run worker as a long-lived process, run one claim/maintenance pass with npm run worker -- --once, or let an admin spawn and manage worker processes from the Background Queue panel. Jobs remain queued across restarts when no worker is running.

Optional: Admin Self-Update Button

You can expose an admin-only update action in the UI that runs:

  1. fetch and classify local/upstream history
  2. stash local changes
  3. fast-forward, or perform guarded rewritten-history recovery
  4. install/update dependencies
  5. rebuild
  6. unstash
  7. restart service

Enable it with env vars in your runtime service:

CHATFORGE_ENABLE_SELF_UPDATE=true
CHATFORGE_UPDATE_REPO_DIR=/path/to/chatforge
CHATFORGE_UPDATE_BUILD_CMD="npm run build"
CHATFORGE_UPDATE_INSTALL_DEPS=true
CHATFORGE_UPDATE_INSTALL_CMD="npm ci --include=dev"
CHATFORGE_UPDATE_INSTALL_FALLBACK_CMD="npm install --include=dev"
CHATFORGE_UPDATE_INSTALL_POLICY="if-needed"
CHATFORGE_UPDATE_INSTALL_TRIGGER_FILES="package.json,package-lock.json,npm-shrinkwrap.json,yarn.lock,pnpm-lock.yaml,bun.lock,bun.lockb"
CHATFORGE_UPDATE_RECOVER_REWRITTEN_HISTORY=true
CHATFORGE_UPDATE_RESTART_CMD="rc-service chatforge restart"
CHATFORGE_SYSTEM_STATUS_CMD="sudo /usr/bin/systemctl status chatforge.service"

If local and upstream history diverge after a rewrite, the updater only recovers when local HEAD exactly matches one upstream commit by tree, author identity/date, subject, and full message. It creates a refs/chatforge/update-backups/... ref before resetting to upstream, refuses ordinary local commits or ambiguous matches, and rolls back the Git history if dependency installation or the build fails. Set CHATFORGE_UPDATE_RECOVER_REWRITTEN_HISTORY=false to retain strict fast-forward-only behavior.

If any step fails, the process stops and restart is not executed.

Backend via Docker Compose

Use the hardened backend-only compose stack:

# set a strong secret first (or place it in .env)
export CHATFORGE_SECRET='replace-with-a-long-random-secret'

docker compose -f docker-compose.backend.yml up -d --build
docker compose -f docker-compose.backend.yml logs -f --tail=100

Create the first user inside the containerized backend:

docker compose -f docker-compose.backend.yml exec chatforge-backend \
  node server/cli.js create-user <username> <password> [user|admin]

Notes:

  • Backend binds to 127.0.0.1:3069 by default.
  • SQLite data and tool sandbox are persisted in Docker volumes (chatforge_data, chatforge_sandbox).
  • The compose file runs the web/backend service. Start workers from Admin → Background Queue, or add a separately supervised npm run worker process with the same database, secret, export directory, and e-mail/memory environment.

Architecture

  • Frontend: React SPA (Vite)
  • Backend: Express server runtime plus an optional persistent background-job worker
  • Auth: bcrypt passwords + optional TOTP/recovery codes + passkeys (WebAuthn), JWT in an httpOnly cookie for web clients, and rotating access/refresh tokens for native clients
  • LLM transport: Validated server-side proxy by default; browser-direct provider requests are available when proxying is disabled. Provider credentials originate in browser-local configuration and may optionally be synced as a client-encrypted blob
  • Storage: Adapter-based SQLite: better-sqlite3 + WAL in server mode, or the bundled FTS5-enabled sql.js WASM build in embedded mode
  • Live sync: WebSocket event stream with ordered delta catch-up and REST state reconciliation
  • Background work: Lease-based SQLite queue for e-mail, exports, automatic memory, and maintenance

Native Authentication and Device Linking

Native clients can sign in with a password or passkey, rotate refresh tokens, log out, or use a browser-approved device-code flow:

  • POST /api/auth/native/login
  • POST /api/auth/native/refresh
  • POST /api/auth/native/logout
  • POST /api/auth/device/authorize — returns a device code, user code, verification URL, poll interval, and expiry
  • POST /api/auth/device/token — polls until the signed-in web user approves or denies the user code
  • POST /api/auth/device/approve — authenticated browser approval used by the /device-link screen

Passkey login for Flutter/native clients uses:

  • POST /api/auth/native/passkeys/authenticate/options
    • Input: optional username
    • Output: WebAuthn authentication options + challenge_id
  • POST /api/auth/native/passkeys/authenticate/verify
    • Input: challenge_id, WebAuthn response, and native device metadata (platform, device_name, etc.)
    • Output: native auth token bundle (access_token, refresh_token, session) matching /api/auth/native/login

Existing authenticated passkey management endpoints (/api/auth/passkeys list/register/delete) also work with Bearer access tokens from native clients.

Authenticated web and native clients can list and manage their session inventory through /api/auth/devices, including rename, revoke, permanent delete, stale cleanup, and revoke-others operations. Refresh tokens rotate on use; detected replay revokes the affected native session.

Live Sync Policy API (Native + Web)

Authenticated clients can control granular live WebSocket synchronization categories:

  • GET /api/sync/live-policy
    • Output: { policy }
  • PUT /api/sync/live-policy
    • Input: partial or full policy object (can also send the object directly as request body)
    • Output: { ok: true, policy, updated_at }

Policy shape:

  • enabled: global on/off for live WebSocket updates
  • folders.state: synchronize folder open/closed state
  • folders.order: synchronize folder ordering and pin state
  • folders.names: synchronize folder rename changes
  • folders.lifecycle: synchronize folder create/delete
  • chats.order: synchronize chat ordering and pin state
  • chats.names: synchronize chat rename changes
  • chats.lifecycle: synchronize chat create/delete
  • chats.context: synchronize chat context metadata changes (context_summary, context_cutoff_count)
  • chats.messages: synchronize chat message create/update/delete events
  • data.memories: synchronize memory create/update/delete
  • data.artifacts: synchronize artifact create/update/delete
  • app.ui: synchronize UI preference changes
  • app.settings: synchronize non-UI settings changes
  • app.modelCatalog: synchronize model catalog changes
  • app.encryptedSecrets: synchronize encrypted provider/agent sync metadata changes
  • app.security: synchronize account security state changes (auth devices, passkeys, TOTP)

The web client consumes /api/sync/ws, resumes from its last sequence number through /api/sync/changes, ignores its own actor-session events, and periodically reconciles state. The Settings presets can enable everything, disable everything, sync only UI/settings, or omit chat content. Separately, sidebar arrows can move individual chats/folders between server sync and browser-local storage, while Unsync all chats switches new chat creation to local-only mode.

Per-User Model Catalogs

  • Each account has its own provider/model catalog (Anthropic, OpenAI, Gemini, VertexAI).
  • Default model lists are preloaded with current model families and can be customized in Settings.
  • Add, edit, or remove model IDs and labels in the UI; changes are persisted server-side for that user.
  • Per-model capability toggles gate sampling, reasoning, thought, and OpenAI web-search controls; suggested values are inferred from provider/model families and can be overridden.
  • Each account can also save a default provider and default model, applied automatically at login.
  • Automatic title generation can use its own provider/model and output-token limit instead of the active chat model.

Provider Reasoning Controls

  • OpenAI: configurable reasoning effort (used for Chat Completions / Responses where supported).
  • OpenAI Responses API: configurable reasoning summary mode (auto, concise, detailed) and request-level store: false to avoid provider-side response storage.
  • OpenAI Responses API: optional built-in web search, configurable search context size, and rendered source links.
  • Anthropic: configurable thinking token budget (thinking.budget_tokens).
  • Gemini / VertexAI: configurable thinking level and thinking budget (generationConfig.thinkingConfig).
  • Conversation UI: optional reasoning-step visibility for providers that return reasoning/thought traces.

When server proxying is disabled globally or for an account, the browser uses the same provider converters to call the configured endpoint directly; the endpoint must permit browser CORS. Direct-provider tools require explicit consent once per browser session before tool definitions or approved results are disclosed to that provider.

Encrypted Provider Config Sync

  • API keys, provider endpoints, the local-agent URL, and the agent bearer token can be selectively synced to the server as a client-side encrypted blob.
  • Encryption/decryption uses PBKDF2 (password-derived key) + AES-GCM in the browser.
  • On interactive login, ChatForge attempts to load and decrypt synced provider values with the entered password and hydrate local storage.
  • In Settings, use Sync Values To Server and Load Values From Server to push/pull while already logged in.
  • Passwordless passkey login prompts for the account password only if the user chooses to unlock encrypted values; a password change prompts the user to re-encrypt them.

Account E-mail and Password Recovery

Set CHATFORGE_EMAIL_ENABLED=true, configure a transport, and run a background worker to enable account e-mail features. Users can add multiple addresses, verify them through the SPA verification route, and independently subscribe each verified address to new-login, deleted-session, blocked-token-replay, password-change, and export notifications.

The sign-in screen accepts password-recovery requests by username or verified e-mail address. Recovery links are single-account proofs; accounts with 2FA must additionally supply a live TOTP or recovery code. Completing recovery rotates the password and revokes existing sessions. Add/update/delete e-mail operations also require current-password proof and, when enabled, a second factor.

For real links, set CHATFORGE_PUBLIC_BASE_URL to the externally reachable ChatForge origin. The log transport is useful for development; production can use SMTP or a sendmail-compatible command.

Data Export and Migration

Settings → Data Export creates a .tar.gz archive containing account metadata, security summaries, chats, folders, messages, memories, artifacts, preferences, per-client preferences, encrypted provider configuration, and the model catalog. Password hashes, refresh tokens, raw TOTP secrets, recovery codes, automatic-memory credentials, and memory-processing cursors are excluded.

Server-mode exports are persistent async jobs with paged history, status polling, expiring authenticated downloads, optional start/completion e-mails, and scanner-safe public download confirmation pages. They require a background worker. Embedded mode exposes the direct archive fallback instead.

The authenticated /api/migration API provides resumable paged export/import sessions that survive server restarts:

  • GET /api/migration/capabilities
  • POST /api/migration/export/start, then status/manifest/paged-resource reads
  • POST /api/migration/import/start, then chunked resource uploads and status reads
  • POST /api/migration/import/:id/commit or /rollback

Imports validate record sizes/counts and ownership, reject gaps/out-of-bounds chunks, remap conflicting IDs, preserve artifact path identity, and emit sync events after commit.

Automatic Memory Consolidation

In Settings → Memories, server-mode users can enable background analysis, choose a provider/model/endpoint, save a dedicated API key encrypted at rest, inspect last/next run and errors, and queue an immediate run. The scheduler incrementally scans completed conversations from per-conversation cursors and can backfill a bounded number of existing chats.

The model may create, update, merge, or retire only background-origin memories; manual and tool-created memories are protected. Candidate output is bounded and screened for common credentials, bearer/API tokens, private keys, payment-card numbers, and government identity data. Automatic memory is disabled in embedded mode and requires a running background worker.

Embedded Backend and Migration

server/embedded-entry.js runs the backend inside a Flutter Android bridge. It selects the bundled FTS5-enabled sql.js WASM storage adapter, persists a generated secret beside the database, creates a local sandbox, and handles prepare_lock / resume_after_unlock control messages so the host can safely close and reopen local storage around its lock lifecycle.

POST /api/auth/embedded-bootstrap creates the single local-owner admin on first use and returns the same native token/session bundle used by remote clients. Embedded mode disables e-mail, async workers, automatic memory, self-update, and system-status commands; it keeps the core chat/storage APIs, resumable migration import/export, local sync endpoints, and direct archive export. See Flutter embedded integration for packaging and bridge details.

nginx Reverse Proxy

server {
    listen 443 ssl;
    server_name chat.n9x.co;

    location / {
        proxy_pass http://127.0.0.1:3069;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_buffering off;            # important for SSE streaming
        proxy_cache off;
    }
}

OpenRC Service (Alpine/Gentoo)

Service files are provided under deploy/openrc/.

# install chatforge service + config
sudo cp deploy/openrc/chatforge /etc/init.d/chatforge
sudo chmod +x /etc/init.d/chatforge
sudo cp deploy/openrc/chatforge.confd.example /etc/conf.d/chatforge

# edit /etc/conf.d/chatforge and set CHATFORGE_SECRET
sudo rc-service chatforge start
sudo rc-update add chatforge default

Agent service (optional, if you use local tool execution):

sudo cp deploy/openrc/chatforge-agent /etc/init.d/chatforge-agent
sudo chmod +x /etc/init.d/chatforge-agent
sudo cp deploy/openrc/chatforge-agent.confd.example /etc/conf.d/chatforge-agent

# edit /etc/conf.d/chatforge-agent (set CHATFORGE_AGENT_TOKEN and allowed CHATFORGE_AGENT_CORS origins;
# include your hosted ChatForge origin, for example https://chat.example.com, if the UI is not served from localhost)
# optional: set CHATFORGE_AGENT_EXTRA_ARGS="--allow-private-fetch true" only if you explicitly need local/private URL fetching
sudo rc-service chatforge-agent start
sudo rc-update add chatforge-agent default

SearXNG via Docker Compose

Compose files are under deploy/searxng/.

cd deploy/searxng
# set a strong server.secret_key in settings.yml first
docker compose up -d
docker compose logs -f --tail=100

By default it binds to 127.0.0.1:8888 and matches CHATFORGE_SEARXNG=http://127.0.0.1:8888.

Environment Variables

Runtime, authentication, and sync

Variable Default Description
CHATFORGE_PORT 3069 Server port
CHATFORGE_DB ./data/chatforge.db SQLite path
CHATFORGE_BACKEND_MODE server Runtime mode; embedded selects the WASM adapter and disables server-only operations
CHATFORGE_EMBEDDED_DATA_DIR database directory Embedded secret and default sandbox directory
CHATFORGE_SECRET unset Token/signing and default memory-credential key; production requires at least 32 characters, while development generates an ephemeral secret if unset
CHATFORGE_JWT_EXPIRY 7d JWT lifetime
CHATFORGE_ACCESS_TOKEN_EXPIRY 15m Native Bearer access-token lifetime
CHATFORGE_REFRESH_TOKEN_EXPIRY_DAYS 90 Native rotating refresh-token lifetime in days (1365)
CHATFORGE_DEVICE_CODE_EXPIRY_MIN 10 Native device-link code lifetime in minutes
CHATFORGE_DEVICE_CODE_POLL_INTERVAL_SEC 5 Minimum device-token polling interval
CHATFORGE_DEVICE_VERIFICATION_URI inferred /device-link URL Public device-link approval URL returned to native clients
CHATFORGE_TOTP_ISSUER ChatForge Display name used in authenticator apps during TOTP setup
CHATFORGE_PASSKEY_RP_NAME ChatForge Relying Party display name shown in passkey prompts
CHATFORGE_PASSKEY_RP_ID empty Optional RP ID override for passkey ceremonies (defaults to request host without port)
CHATFORGE_PASSKEY_ALLOWED_ORIGINS empty Optional comma-separated allowed origins for passkey ceremonies (defaults to inferred same-origin values; can include native origins like android:apk-key-hash:...)
CHATFORGE_PASSKEY_ANDROID_PACKAGE_NAME empty Optional Android package name used to publish /.well-known/assetlinks.json for native passkey providers
CHATFORGE_PASSKEY_ANDROID_SHA256_CERT_FINGERPRINTS empty Optional comma-separated Android cert SHA-256 fingerprints (AA:BB:...). When set with package name, ChatForge publishes Digital Asset Links and auto-adds matching android:apk-key-hash:... passkey origins
CHATFORGE_PASSKEY_CHALLENGE_TTL_SEC 300 Passkey challenge lifetime in seconds
CHATFORGE_PASSKEY_CHALLENGE_PURGE_AGE_SEC 86400 Age after which used/expired passkey challenges are purged
CHATFORGE_TRUST_PROXY false Express trust proxy setting (1, true, or trusted proxy keyword)
CHATFORGE_ALLOWED_ORIGINS empty Optional comma-separated origins allowed for mutating /api requests. Empty means same-origin only.
CHATFORGE_ALLOW_WS_QUERY_TOKEN_AUTH false Allow Bearer auth via WebSocket query params (access_token/token) on /api/sync/ws. Keep disabled to avoid token leakage in URL logs/history.
NODE_ENV unset Set to production in the runtime service env (not in .env) for secure cookies

E-mail, exports, and background work

Variable Default Description
CHATFORGE_EMAIL_ENABLED false Enable account e-mail, verification, recovery, and notification routes; always off in embedded mode
CHATFORGE_PUBLIC_BASE_URL empty External origin used in e-mail verification, recovery, and export links
CHATFORGE_EMAIL_FROM ChatForge <no-reply@localhost> Outbound From header
CHATFORGE_EMAIL_TRANSPORT log Worker delivery transport: log, sendmail, or smtp
CHATFORGE_EMAIL_SENDMAIL_CMD sendmail -t -i Command used by the sendmail transport
CHATFORGE_EMAIL_SMTP_HOST empty SMTP hostname; required for the smtp transport
CHATFORGE_EMAIL_SMTP_PORT 587 SMTP port
CHATFORGE_EMAIL_SMTP_SECURE false Use implicit TLS for SMTP
CHATFORGE_EMAIL_SMTP_USER empty Optional SMTP username
CHATFORGE_EMAIL_SMTP_PASS empty Optional SMTP password
CHATFORGE_EMAIL_SMTP_REQUIRE_TLS false Require STARTTLS for SMTP
CHATFORGE_EMAIL_SMTP_IGNORE_TLS false Disable STARTTLS negotiation for SMTP
CHATFORGE_EMAIL_VERIFY_TTL_SEC 86400 E-mail verification-token lifetime
CHATFORGE_PASSWORD_RECOVERY_TTL_SEC 3600 Password-recovery request lifetime
CHATFORGE_BACKGROUND_JOB_LEASE_SEC 60 Queue lease duration; active workers renew leases during long jobs
CHATFORGE_BACKGROUND_JOB_POLL_INTERVAL_MS 1000 Worker idle polling interval
CHATFORGE_DAILY_MAINTENANCE_INTERVAL_SEC 86400 Full expired-token/export cleanup interval
CHATFORGE_EXPORT_STORAGE_DIR ./data/exports Async archive output directory; must be shared by server and workers
CHATFORGE_EXPORT_TTL_HOURS 24 Completed archive and download-token lifetime
CHATFORGE_AUTO_MEMORY_ENABLED true in server mode Globally enable automatic-memory scheduling
CHATFORGE_AUTO_MEMORY_INTERVAL_SEC 86400 Per-user automatic-memory scan interval
CHATFORGE_AUTO_MEMORY_BACKFILL_CONVERSATIONS 100 Maximum existing conversations considered when initializing cursors; 0 disables backfill
CHATFORGE_AUTO_MEMORY_MAX_MESSAGES_PER_CONVERSATION 50 Maximum messages read from each conversation per scan
CHATFORGE_AUTO_MEMORY_MAX_INPUT_CHARS_PER_RUN 120000 Aggregate conversation-input character budget per scan
CHATFORGE_MEMORY_CREDENTIAL_KEY CHATFORGE_SECRET Optional independent key material for AES-256-GCM automatic-memory API-key encryption

Providers and tools

Variable Default Description
CHATFORGE_ENABLE_LLM_PROXY true Enable /api/stream; when false, the web client falls back to direct provider requests instead of using the server proxy
CHATFORGE_ALLOW_PRIVATE_ENDPOINTS true outside production, false in production Allow proxying LLM traffic to localhost/private IPs
CHATFORGE_ALLOWED_CUSTOM_LLM_HOSTS empty Optional comma-separated public hostnames allowed for custom LLM endpoints while keeping arbitrary endpoints blocked
CHATFORGE_ALLOW_CUSTOM_LLM_ENDPOINTS false Allow arbitrary public LLM endpoint hosts in /api/stream. Prefer CHATFORGE_ALLOWED_CUSTOM_LLM_HOSTS when possible
CHATFORGE_SANDBOX ./sandbox Default workspace reported by server tool configuration and used by legacy server-side tool executors
CHATFORGE_SEARXNG http://localhost:8888 SearXNG base URL for web_search
CHATFORGE_ALLOW_PRIVATE_FETCH_URLS false Allow fetch_url tool requests to localhost/private IPs
CHATFORGE_CMD_TIMEOUT 30000 Default run_command timeout in ms (can be overridden per-user at runtime in Tools settings)

Admin operations

Variable Default Description
CHATFORGE_ENABLE_SELF_UPDATE false Allow admin UI to run self-update pipeline
CHATFORGE_UPDATE_REPO_DIR current working dir Repository directory for update commands
CHATFORGE_UPDATE_BUILD_CMD npm run build Build command run during admin update
CHATFORGE_UPDATE_INSTALL_DEPS true Install dependencies before build during admin update
CHATFORGE_UPDATE_INSTALL_CMD npm ci --include=dev Primary dependency-install command run during admin update
CHATFORGE_UPDATE_INSTALL_FALLBACK_CMD npm install --include=dev Fallback install command if primary install fails
CHATFORGE_UPDATE_INSTALL_POLICY if-needed if-needed skips install unless dependency trigger files changed in pulled commits; always installs every update
CHATFORGE_UPDATE_INSTALL_TRIGGER_FILES package.json,package-lock.json,npm-shrinkwrap.json,yarn.lock,pnpm-lock.yaml,bun.lock,bun.lockb Comma-separated files that trigger dependency install in if-needed mode
CHATFORGE_UPDATE_RECOVER_REWRITTEN_HISTORY true Allow guarded divergence recovery when local HEAD exactly matches one rewritten upstream commit; a backup ref is created before reset
CHATFORGE_UPDATE_RESTART_CMD empty Service restart command (required if self-update enabled)
CHATFORGE_SYSTEM_STATUS_CMD empty Command for admin service-status display

UI Tour (Screenshots)

Authentication

Login

Login screen

Username/password sign-in before loading synced user preferences and chats.

Core Chat

Main Chat (Light Theme)

Main chat UI light theme

Primary conversation surface with model/provider controls, streaming responses, and message actions.

Conversation Example

Conversation example

Longer back-and-forth conversation showing grouped turns in one thread.

Markdown Rendering (1)

Markdown chat example 1

Markdown Rendering (2)

Markdown chat example 2

Markdown Rendering (3)

Markdown chat example 3

Formatted markdown output across lists, blocks, and rich response content.

Inline LaTeX

Inline latex chat

Math rendering in chat responses.

High-Contrast Chat

High contrast chat view

High-contrast chat mode for improved visual accessibility.

Search With Content Match

Search content match

Search inside chats to quickly jump to conversations/messages containing the query.

Search With No Content Match

Search no content match

Empty/no-match state behavior when no messages match the query.

Productivity Features

Commands

Chat commands

Built-in command palette/view for quick in-chat actions and workflow shortcuts.

Sidebar and Organization

Sidebar Folders (Drag and Drop)

Sidebar folders

Conversation sidebar for organizing chats and folders. Supports collapsing folders, drag-and-drop reordering for folders and threads, and server-side persistence of folder state and order.

Settings and Configuration

Settings (Collapsed)

Settings collapsed

Main settings entry point for providers, defaults, preferences, and account-level options.

General Settings

General settings

Provider Settings

Provider settings

Model Catalog Settings

Model catalog settings

Per-user provider/model catalogs can be customized directly in Settings.

Default Model Selector

Default model selector

Reasoning Settings

Reasoning settings

Sampling Settings

Sampling settings

System Prompt Settings

System prompt settings

Tools Settings

Tools settings

Memories Settings

Memories settings

Encrypted Provider Sync

Encrypted provider sync

Artifacts Settings

Artifacts settings

Self Password Change

Self password change

Admin and Operations

Admin Panel Overview

General admin panel

Top-level admin panel with user, database, and service controls.

Admin Controls

Admin controls

Operational actions for service status, update, and restart workflows.

Admin User Management

Admin user management

User list with role management, password reset, and account lifecycle actions.

Admin User Detail

Admin user detail

Full per-user snapshot including preferences, memories, conversations, and messages.

Admin SQL Query Runner

Admin SQL query runner

In-app SQL runner for read/admin queries with typed parameter input.

Admin Query Runner Example

Admin query runner example

Example query execution and result rendering in the admin database panel.

Default Themes

Blue Theme

Blue theme

Green Theme

Green theme

Purple Theme

Purple theme

Yellow Theme

Yellow theme

Theme customization note:

  • You are not limited to presets. Any valid hex color is supported (for example #1f6feb, #22c55e, #f59e0b).
Description
A vibe coded web UI for various LLM providers
Readme 15 MiB
Languages
JavaScript 99.3%
CSS 0.6%
Shell 0.1%