claudeers.

🔓 unclaimed — this page was auto-generated from GitHub. Are you the creator?

Claim this page →
// Integrations & Connectors

lucy

Lucy — open-core, self-hosted AI chat platform. Multi-provider (Claude/OpenAI/Gemini/local), memory, connectors, workflows. Local-first standalone mode or fu…

// Integrations & Connectors[ cli ][ api ][ desktop ][ web ][ mobile ][ claude ]#claude#integrationsAGPL-3.0$open-sourceupdated 5 days ago
// install
git clone https://github.com/JustLucyHQ/lucy

Lucy AI

Introducing Lucy AI — Your AI, every provider, one platform

Your AI. Every provider. One memory.

Lucy runs OpenAI, Claude, Gemini, and local models like Ollama in one interface that remembers your work, connects to your tools, and keeps your keys on your machine.

Lucy is a closed environment, with a brain. Most AI platforms are someone else's cloud — Lucy is a sealed room inside your company. She remembers your decisions and context (the brain), keeps every byte on your deployment under your keys (the walls), and embeds into any app you own with one line of code (the doors). Your company, your data, and nobody else's business.

Switch AI models mid-conversation | Memory that compounds | MCP connector marketplace | Visual workflow builder | Run local LLMs for full privacy | Voice in, voice out | Embed with one line of code | Open source. Self-hostable. Free.

Built for teams that want to test, compare, and ship AI — self-hosted, on infrastructure you control.

📚 Documentation: in-app at /docs when Lucy is running, or browse the markdown in docs/kb/ — guides for users (chat, memory, personas, connectors, workflows, voice, themes) and developers (architecture, self-hosting, embedding, HTTP API, MCP server, contributing).


Overview

Lucy is a self-hosted AI platform for teams that want to roll out AI tooling without handing their data to someone else's cloud. It connects to OpenAI, Anthropic Claude, Google Gemini, and local models via Ollama and LM Studio through a unified provider interface, streams responses in real time, and lets you switch models mid-conversation. All chat history and settings are stored either locally in the browser (zero-infrastructure standalone mode) or persisted to a Supabase PostgreSQL database when you need multi-user, cross-device access.

Beyond chat, Lucy ships a visual workflow builder — a drag-and-drop canvas powered by React Flow — where you can compose multi-step AI pipelines from a rich node library (AI Agent, Knowledge Base, Condition, Filter, Transform, Code, HTTP, Send Email, Integration, …). In connected mode workflows run server-side and durably (a run survives closing the tab, with saved history and per-node logs), fire automatically on triggers (schedule, webhook, or record-change events), retry failed runs with backoff, support run cancellation, and keep published versions you can restore. On the desktop app they run locally in the browser.

The integration layer lets other applications register themselves with Lucy's project registry. Once registered, Lucy can read live data from the app's Supabase tables, inject it into the AI system prompt as context, and trigger actions on the app's behalf. An embeddable widget ships via a single <script> tag for easy integration into any web page.


Screenshots

Replace the placeholders below with actual screenshots once the application is running.

ScreenDescription
docs/screenshots/chat.pngMain chat interface — conversation sidebar, model selector, streaming message output
docs/screenshots/workflow-builder.pngVisual workflow canvas with node panel, configuration sidebar, and run panel
docs/screenshots/personas.pngPersonas management page — built-in and custom AI personas
docs/screenshots/onboarding.png4-step company onboarding wizard
docs/screenshots/settings.pngSettings page — API key management, local models detection, theme toggle
docs/screenshots/integrations.pngIntegrations page listing registered connected projects
docs/screenshots/embed-widget.pngEmbeddable chat widget mounted in an external application

Features

Multi-Provider AI Chat

  • Connect to OpenAI (GPT-4o, GPT-4o Mini, GPT-3.5 Turbo), Anthropic (Claude Sonnet 4, Claude Haiku 4), Google (Gemini 2.0 Flash, Gemini 1.5 Pro), DeepSeek (V3 Chat, R1 Reasoner), Groq (Llama 3.3 70B, Llama 3.1 8B, Gemma 2), Mistral (Large, Small), xAI (Grok 2, Grok Beta), OpenRouter (gateway), and local models (via Ollama or LM Studio) from a single interface
  • Real-time streaming responses via Server-Sent Events — tokens render as they arrive
  • Per-conversation model switching — change provider and model without starting a new session
  • Conversation history with auto-generated titles, searchable sidebar
  • Message editing — edit any user message inline; saving re-sends the conversation from that point
  • Response regeneration — regenerate any assistant reply with a single click
  • Conversation export — download any chat as Markdown or JSON from the chat header menu
  • Rate limiting — chat API enforces 30 requests per minute per IP to protect server-level API keys

Memory (connected mode)

  • Lucy remembers across conversations — facts, preferences, working style, and what happened when (semantic / pragmatic / episodic)
  • Always-on profile + searchable collection — a compact identity block is always present; relevant memories are retrieved per message via hybrid search (pgvector + full-text, fused with Reciprocal Rank Fusion)
  • Entity salience — recurring terms (clients, products, jargon) auto-promote in importance the more they appear
  • Reconciliation-aware capture — one end-of-conversation pass extracts, de-duplicates, and reconciles (ADD / UPDATE / MERGE / SKIP); a privacy guard never stores secrets or PII
  • /remember pins a fact instantly; /global contributes it to shared knowledge; incognito skips capture for a session
  • Admin-gated with storage-usage visibility, configurable contradiction policy (supersede / keep-history), and a staged archive → grace-window → delete flow
  • Dual-mode by design — full semantic memory in connected (Supabase) mode; a lexical fallback engine for standalone mode
  • Pluggable embedder — pick OpenAI text-embedding-3-small or a fully-local Ollama model (e.g. embeddinggemma) in Settings → Memory; the pgvector column reshapes to match the chosen dimension automatically

Terminal CLI

  • lucy chat — streaming chat in any shell, with the same memory and encrypted provider keys as the web app
  • Rich REPL — welcome banner, Markdown-rendered replies (code blocks, lists, bold), a thinking spinner, /-command Tab autocomplete, and boxed output; defaults to a model whose provider you actually have a key for
  • Pipe-friendly one-shotscat error.log | lucy chat "explain this" (plain text when piped)
  • lucy models / memories / screenings / admin / whoami — manage your deployment without leaving the terminal
  • Thin client over Lucy's HTTP API, authenticated with a Lucy API key; configure once with lucy login (~/.lucy/config.json, or LUCY_URL/LUCY_API_KEY env vars)
  • Run via npm run lucy -- <cmd> in the repo, or npm link for a global lucy command

MCP Connector Marketplace

  • Browse, install, configure — a curated catalog of MCP connectors (GitHub, Slack, Notion, Postgres, Linear, Stripe, Brave Search, Filesystem, Fetch) installable per user with one click
  • Tool use in chat — Lucy calls connector tools mid-conversation (OpenAI-compatible + Anthropic providers); tool calls render as live status chips above the streaming reply
  • Encrypted secrets — connector credentials are AES-256-GCM encrypted at rest and never returned to the browser
  • Approval gating — flag any installation so write-like actions (create/update/delete/send) require your approval instead of executing silently

Voice (STT + TTS)

  • Mic input — browser Web Speech (live interim text) or cloud Whisper/Deepgram press-to-record
  • Read-aloud — per-message speaker button plus auto-read; browser voices, OpenAI TTS, or any OpenAI-compatible local server
  • Configured in Settings → Voice; keys travel via request headers only

Desktop App (local-first)

  • Ships as a downloadable Electron app for Windows (.exe), macOS (.dmg), and Linux (.AppImage) — runs the full Lucy server locally
  • Local-first — no account required; chats, memory, and provider keys stay on your machine in standalone mode
  • First-run wizard — pick a cloud API key or a local Ollama / LM Studio model and start
  • Connect to Cloud — optionally push local chats and settings to a justlucy.ai account (one-way, idempotent sync)
  • OS-detecting download page at /download

Channels — Telegram

  • Run Lucy as a Telegram bot from Admin → Channels — paste a BotFather token, register the webhook, and chat with the same memory and encrypted keys
  • Shared mode (one bot on your keys, optional Telegram user-ID allowlist) or Linked mode (each user binds their own account with a /link code)

Five Themes

  • Luminous (default — glassy purple glow), Industrial (sharp, structured), Editorial (bold typography, stark contrast), Minimal dark, and Light
  • CSS-variable design tokens restyle the entire app instantly; picker in Settings → General; set in Manrope via next/font

Chat Commands

Type / in the chat box for an autocomplete menu of slash-commands:

CommandEffect
/remember <text>Save a fact to memory
/forget <text>Forget memories matching the text
/global <text>Save shared knowledge for everyone
/memoriesShow what Lucy remembers (count + recent)
/incognitoToggle: don't capture memories this session
/newStart a new conversation
/helpList all commands

Arrow keys + Enter/Tab to apply, Esc to dismiss. Arg-commands prime the input; no-arg commands fire immediately. The registry lives in lib/chat/slash-commands.ts.

AI Personas

  • 5 built-in personas with purpose-built system prompts:
    • General Assistant — helpful and balanced for everyday tasks
    • Code Expert — senior developer persona for TypeScript, React, and Node.js
    • Creative Writer — storytelling, copywriting, and creative content
    • Data Analyst — SQL, pandas, statistics, and data visualisation
    • Onboarding Guide — patient guide for helping new employees
  • Create custom personas — define your own name, icon, description, and system prompt on the /personas page
  • Persona selector chip in the chat input — pick a persona without leaving the conversation
  • Built-in personas cannot be deleted; custom ones can be edited or removed
  • Active persona system prompt is injected at the start of each new conversation
  • Personas are persisted to localStorage under the lucy-personas key

Token Tracking

  • Per-message token estimates — shown on hover for each message (heuristic: ~4 chars/token)
  • Conversation total displayed in the chat header as ~N tokens this conversation
  • Implemented in lib/utils/tokens.ts via estimateTokens() and estimateConversationTokens()

Local LLM Support

  • Run AI models entirely on your own machine via Ollama or LM Studio
  • Both expose an OpenAI-compatible API — Lucy connects without any API key
  • Auto-detection — the model selector probes localhost at startup and lists available models automatically
  • Detect Models button in Settings discovers what is currently loaded
  • Configurable server URLs (defaults: http://localhost:11434 for Ollama, http://localhost:1234 for LM Studio)
  • Gracefully skipped when local servers are not running — cloud providers continue to work

Authentication

  • Login, signup, and forgot-password pages built with Supabase Auth
  • Google OAuth — one-click sign-in via Google
  • Auth middleware — protects /chat, /workflows, and /settings routes when Supabase is configured; redirects unauthenticated users to /auth/login with a redirectTo param
  • In standalone mode (no Supabase configured), auth is fully bypassed and all routes are public
  • User avatar and sign-out in the header when signed in
  • Two-factor authentication — email-OTP and TOTP authenticator-app 2FA, with a login challenge gate
  • Account security — password reset via emailed code, active-device tracking, and a profile / account page
  • Transactional email — reset and 2FA codes sent over SMTP (configure the SMTP_* env vars)
  • /personas route is always public (not protected by auth middleware)

Progressive Web App (PWA)

  • Full Web App Manifest with name, short name, display mode, theme colour, and icons
  • Favicon and app icons render the Lucy brand markapp/icon.svg (favicon), 192×192 and 512×512 PWA icons, and an Apple touch icon
  • Can be installed as a standalone app on desktop and mobile

Visual Workflow Builder

  • Drag-and-drop canvas built on React Flow (@xyflow/react)
  • Rich node library — AI Agent (pick provider + model), Knowledge Base, Condition, Filter, Transform, Code (JS), HTTP, Send Email, Integration, Output
  • Durable server-side execution (connected mode) via an in-process worker + a Postgres run queue — runs survive closing the tab, with saved history, per-node logs, and cancellation; the desktop app runs workflows in-browser
  • Triggers — run automatically on a schedule (cron), from a webhook (secret URL), or on record events (row created/updated/deleted)
  • Retry/backoff + idempotency for trigger-fired runs; DRAFT/PUBLISHED versions with restore
  • Execution log panel with per-node input/output inspection

Code Blocks

  • Syntax-highlighted code blocks rendered via rehype-highlight
  • Language label shown in the block header
  • Copy button on every code block
  • Line numbers shown automatically when a block has more than 5 lines
  • Horizontally scrollable to handle wide code without breaking layout

Accessibility (ARIA)

  • Semantic HTML throughout: <header role="banner">, <nav role="navigation">, <main>, <form role="form">, message list as <div role="log" aria-live="polite">
  • All interactive elements have aria-label attributes
  • Persona selector uses role="listbox" / role="option" / aria-selected
  • Conversation list items have aria-current for the active conversation
  • Export button has aria-expanded and aria-haspopup
  • Header user menu has aria-expanded and aria-haspopup
  • Mobile hamburger button has aria-expanded and aria-label

Mobile Responsive

  • Hamburger menu in the header on small screens — tap to open a full-width dropdown nav
  • Sidebar overlay — on mobile, the conversation sidebar slides in as a fixed overlay with a backdrop
  • Swipe-to-close — swipe left on the mobile sidebar to dismiss it (60 px threshold)
  • Sidebar close button visible in mobile overlay mode
  • Selecting a conversation auto-closes the mobile sidebar
  • Chat input bottom bar wraps gracefully on narrow screens

Keyboard Shortcuts

  • Cmd/Ctrl+K — focus the conversation search input
  • Cmd/Ctrl+Shift+N — start a new chat
  • Escape — close the sidebar on mobile
  • Enter — send message (in chat input)
  • Shift+Enter — insert newline in chat input
  • Cmd/Ctrl+Enter — save an inline message edit
  • Escape — cancel an inline message edit

Dual Storage — Standalone and Connected Modes

  • Standalone mode (default): zero configuration, all data in browser localStorage under the lucy- namespace. No backend required.
  • Connected mode: point NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY at a Supabase project and Lucy switches automatically to PostgreSQL-backed persistence with Supabase Auth
  • The entire application is written against a StorageAdapter interface — swapping backends requires no component changes

Theming and UX Polish

  • Light and dark themes — toggle from the header or Settings page
  • No flash on load — an inline <script> in the root layout reads the stored theme before React hydrates, so there is never a white flash on a dark-mode page
  • ThemeProvider keeps the <html> class in sync with the Zustand store in real time
  • Loading skeletons for the chat and workflows pages — shown while JavaScript bundles load
  • Global loading page — animated bouncing dots with the Lucy logo
  • Error boundary (app/error.tsx) catches React render errors and shows a friendly "Try again" screen
  • 404 page (app/not-found.tsx) with a link back to chat

Project Integration Layer

  • Registry — external apps call registerProject() to describe their tables, columns, and available actions
  • Context builder — at chat time, Lucy queries the registered app's live Supabase data and injects a concise summary into the LLM system prompt (token-budget aware)
  • Action executor — four handler types: supabase-insert, supabase-update, api-call, and workflow
  • Embeddable widget — serve Lucy as an iframe chat panel in any web app via a single <script> tag

Company Onboarding

  • 4-step guided wizard: Welcome (company name) → API KeysTest ChatInvite
  • API keys are stored locally or encrypted in Supabase; they never leave the user's own infrastructure

AI Screening Engine

  • Profile Verification — automatic one-shot review of a contractor's profile with AI-generated grade (1–5), strengths, and concerns
  • Project Screening — client-initiated multi-step screening: Lucy generates 5–8 tailored questions, the contractor answers, then Lucy grades the fit
  • Grading scale: Excellent Match (5) → Not Recommended (1)
  • Results visible only to the screening creator (RLS-enforced)
  • API endpoints: POST /api/screening/start, GET/POST /api/screening/:id, GET /api/screening

API Key System

  • External applications authenticate to Lucy using per-user API keys
  • Key format: lucy_k_<24-random-base64url-chars> — only the SHA-256 hash is stored in the database
  • Full key shown once on creation, never again
  • Manage keys from the Settings page (Supabase mode only)
  • API routes: POST /api/keys (create), GET /api/keys (list), DELETE /api/keys (revoke/delete)

MCP Server

  • Lucy exposes screening tools via the Model Context Protocol for use with Claude Code, Cursor, and other MCP-compatible editors
  • 5 tools: start_screening, get_screening, list_screenings, submit_screening_answers, verify_contractor_profile
  • Run with npm run mcp — uses stdio transport

Quick Start

Prerequisites

  • Node.js 18 or later
  • npm 9 or later
  • At least one AI provider API key (OpenAI, Anthropic, or Google) — or a running Ollama instance for local-only use

Steps

# 1. Clone the repository
git clone https://github.com/JustLucyHQ/lucy.git
cd LucyAI

# 2. Install dependencies
npm install

# 3. Create your local environment file
cp .env.example .env.local

# 4. Open .env.local and add your API keys (see Configuration below)

# 5. Start the development server
npm run dev

# 6. Open the application
# http://localhost:3001

On first launch you will be redirected to the onboarding wizard to set your company name and configure API keys.


Docker

Lucy ships with a multi-stage Dockerfile and a docker-compose.yml for running the production build in a container.

# Build and start the container
# API keys are picked up from your shell environment or a .env file
OPENAI_API_KEY=sk-... docker-compose up --build

# Or export variables first, then run
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
docker-compose up --build

The app is available at http://localhost:3000.

Building the Docker image manually

# Build
docker build -t lucy-ai .

# Run
docker run -p 3000:3000 \
  -e OPENAI_API_KEY=sk-... \
  -e ANTHROPIC_API_KEY=sk-ant-... \
  lucy-ai

Dockerfile details

The build uses a three-stage approach:

  1. deps — installs production dependencies only (npm ci --omit=dev)
  2. builder — copies source and runs next build (telemetry disabled)
  3. runner — minimal node:20-alpine image running server.js as a non-root user

The docker-compose.yml maps OLLAMA_URL and LM_STUDIO_URL to host.docker.internal so the containerised app can reach Ollama or LM Studio running on the host machine.


Testing

Lucy has 282 tests across 49 test suites written with Jest and React Testing Library. A representative sample:

Running tests

# Run all tests once
npm test

# Run in watch mode (re-runs on file change)
npm run test:watch

# Type-check without running tests
npx tsc --noEmit

Test suites

SuiteFileWhat is covered
Provider registry__tests__/lib/providers/index.test.tsgetProvider, getProviderForModel, getAllModels, getModelsByProvider
Local storage adapter__tests__/lib/storage/local.test.tsLocalStorageAdapter CRUD, conversation/message/preference/provider config
Workflow engine__tests__/lib/workflow/engine.test.tsStart→Output execution, edge following, condition branching, transform operations
Integration registry__tests__/lib/integrations/registry.test.tsregisterProject, getProject, getAllProjects, getProjectTables, getProjectActions
Markdown utilities__tests__/lib/utils/markdown.test.tshasMarkdown, generateConversationTitle, truncate
ModelSelector component__tests__/components/chat/ModelSelector.test.tsxRenders provider groups, onChange callback fires with correct model id
Button component__tests__/components/ui/Button.test.tsxRenders children, variant classes, loading spinner, disabled state, click behaviour

Test configuration

  • Framework: Jest 29 with ts-jest for TypeScript transpilation
  • Environment: jsdom (browser-like, suitable for React component tests)
  • Setup file: jest.setup.ts loads @testing-library/jest-dom matchers
  • Module alias: @/ maps to the project root (matches tsconfig.json paths)
  • Test location: all test files live under __tests__/ mirroring the source tree

Configuration

All configuration is done through environment variables. Copy .env.example to .env.local and fill in the values relevant to your setup.

VariableRequiredDescription
OPENAI_API_KEYOptional*OpenAI API key. Required to use GPT-4o, GPT-4o Mini, or GPT-3.5 Turbo. Format: sk-...
ANTHROPIC_API_KEYOptional*Anthropic API key. Required to use Claude Sonnet 4 or Claude Haiku 4. Format: sk-ant-...
GOOGLE_API_KEYOptional*Google AI API key. Required to use Gemini 2.0 Flash or Gemini 1.5 Pro. Format: AIza...
DEEPSEEK_API_KEYOptional*DeepSeek API key. Required to use DeepSeek V3 (Chat) or DeepSeek R1 (Reasoner). Format: sk-...
GROQ_API_KEYOptional*Groq API key (very fast inference). Format: gsk_...
MISTRAL_API_KEYOptional*Mistral API key (Mistral Large / Small).
XAI_API_KEYOptional*xAI API key for Grok models. Format: xai-...
OPENROUTER_API_KEYOptional*OpenRouter API key — one key, many models. Format: sk-or-...
NEXT_PUBLIC_SITE_URLOptionalCanonical public URL of the deployment (e.g. https://justlucy.ai). Drives OG / canonical / manifest URLs; inlined at build time.
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROMOptionalSMTP credentials for password-reset and 2FA emails (connected mode).
NEXT_PUBLIC_SUPABASE_URLOptionalYour Supabase project URL (e.g. https://xyz.supabase.co). When omitted, Lucy runs in standalone localStorage mode.
NEXT_PUBLIC_SUPABASE_ANON_KEYOptionalYour Supabase project's anon public key. Required when NEXT_PUBLIC_SUPABASE_URL is set.
SUPABASE_SERVICE_ROLE_KEYOptionalService-role key for screening + memory APIs (bypasses RLS). Required when using the screening or connected-memory endpoints.
LUCY_ADMIN_EMAILOptionalWhen set, only these signed-in users may change global memory settings (Settings → Memory). Accepts a single email or a comma-separated list. Unset means any authenticated user may toggle.
LUCY_URLOptionalLucy's own URL for MCP callbacks. Default: http://localhost:3001.
LUCY_API_KEYOptionalAPI key for MCP server and external integrations (e.g., Contractors Room).
OLLAMA_URLOptionalBase URL for the Ollama server. Default: http://localhost:11434.
LM_STUDIO_URLOptionalBase URL for the LM Studio local server. Default: http://localhost:1234.

*At least one AI provider key is required to send messages to cloud models. Local models via Ollama or LM Studio require no API key. Keys can also be entered per-user through the Settings page; server-level keys act as a shared fallback.


Auth

Authentication is built on Supabase Auth and is completely optional. When NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY are set, auth is automatically enabled. When they are not set, Lucy runs in anonymous standalone mode and all routes are public.

Auth routes

RouteDescription
/auth/loginEmail + password sign-in and Google OAuth
/auth/signupNew account creation with email confirmation
/auth/forgot-passwordSend a password-reset email
/auth/callbackSupabase OAuth redirect handler (server route)

Middleware

middleware.ts runs on every request. When auth is enabled it:

  1. Lets all requests to /auth/*, /api/*, /onboarding, /embed, /personas, and static assets through unconditionally.
  2. Checks the Supabase session cookie for requests to /chat, /workflows, and /settings.
  3. Redirects unauthenticated requests to /auth/login?redirectTo=<original-path>.

If anything goes wrong during session verification the middleware fails open (allows the request) to avoid blocking the app.

Google OAuth setup

In your Supabase project → Authentication → Providers → Google, enable Google and add your OAuth client ID and secret. Add https://your-lucy-instance.com/auth/callback to the authorised redirect URIs in your Google Cloud Console project.


Personas

Personas configure the AI's personality and expertise by injecting a system prompt at the start of each conversation.

Built-in personas

PersonaIconDescription
General Assistant🤖Helpful and balanced for everyday tasks
Code Expert💻Senior developer — TypeScript, React, Node.js
Creative Writer✍️Storytelling, copywriting, and creative content
Data Analyst📊SQL, data analysis, charts, and statistics
Onboarding Guide🎓Helps new employees learn company tools and processes

Creating a custom persona

  1. Click Personas in the header navigation, or click Create Custom in the persona selector dropdown in the chat input
  2. On the /personas page, click Create Custom
  3. Fill in: icon (emoji), name, short description, and system prompt
  4. Click Save Persona — the persona appears immediately in the selector

Custom personas can be edited or deleted at any time. Built-in personas are read-only. The active persona is highlighted with a purple border and "Active" badge.

Using personas

The persona selector chip sits in the chat input bar next to the model selector. Click it to open a dropdown listing all personas. The selected persona's system prompt is used for new conversations. Switching personas mid-conversation does not affect already-sent messages.


Architecture

lucy-ai/
├── app/                          # Next.js 16 App Router
│   ├── layout.tsx                # Root layout — inline theme script, AuthProvider > StorageProvider > StoreSync > ThemeProvider
│   ├── page.tsx                  # Landing / redirect
│   ├── icon.tsx                  # Dynamic favicon 32×32 (purple "L", edge runtime)
│   ├── icon-192.tsx              # PWA icon 192×192 (edge runtime)
│   ├── icon-512.tsx              # PWA icon 512×512 (edge runtime)
│   ├── manifest.ts               # Web App Manifest (PWA)
│   ├── error.tsx                 # React error boundary page — "Something went wrong" + Try again
│   ├── not-found.tsx             # 404 page with link back to chat
│   ├── loading.tsx               # Global loading fallback (animated dots)
│   ├── globals.css               # Global styles + Tailwind imports
│   ├── chat/
│   │   ├── page.tsx              # Main chat page (sidebar + window + input + keyboard shortcuts)
│   │   └── loading.tsx           # Chat page skeleton (header + sidebar + message area)
│   ├── workflows/
│   │   ├── page.tsx              # Workflow list (grid of cards)
│   │   ├── loading.tsx           # Workflows page skeleton
│   │   └── [id]/page.tsx         # Workflow editor (canvas + toolbar + panels)
│   ├── personas/
│   │   └── page.tsx              # AI persona manager (create, edit, delete, set active)
│   ├── settings/
│   │   ├── page.tsx              # API keys, local models, theme, data
│   │   └── integrations/         # Integration management page
│   ├── onboarding/               # 4-step onboarding wizard
│   ├── embed/                    # Embeddable widget page (loaded in iframe)
│   ├── auth/
│   │   ├── login/page.tsx        # Sign-in page (email + Google OAuth)
│   │   ├── signup/page.tsx       # Account creation page
│   │   ├── forgot-password/page.tsx  # Password reset request page
│   │   └── callback/route.ts     # Supabase OAuth callback handler
│   └── api/
│       ├── chat/route.ts         # POST — streaming AI chat via SSE (rate-limited: 30 req/min/IP)
│       ├── models/route.ts       # GET  — list models; ?includeLocal=true probes Ollama/LM Studio
│       ├── embed/route.ts        # GET  — serve embeddable widget loader script
│       ├── keys/route.ts         # GET/POST/DELETE — API key management
│       └── screening/            # AI screening endpoints (start, get, submit, list)
│
├── components/
│   ├── ThemeProvider.tsx         # Keeps <html> class in sync with Zustand theme state
│   ├── chat/
│   │   ├── ChatWindow.tsx        # Message list, token counter, export menu
│   │   ├── ChatInput.tsx         # Textarea + persona selector + model selector + send/stop
│   │   ├── ChatMessage.tsx       # Single message — markdown, code blocks, edit, regenerate, token count
│   │   ├── ChatSidebar.tsx       # Conversation list, search, mobile overlay, swipe-to-close
│   │   ├── ModelSelector.tsx     # Provider/model dropdown with local model detection
│   │   └── PersonaSelector.tsx   # Persona chip + dropdown in the chat input bar
│   ├── workflow/                 # WorkflowCanvas, NodePanel, NodeConfigPanel, RunPanel, WorkflowToolbar
│   │   └── nodes/                # Individual node components (one per node type)
│   ├── onboarding/               # OnboardingWizard
│   ├── embed/                    # LucyWidget (iframe chat widget)
│   ├── layout/
│   │   ├── Header.tsx            # Top nav — theme toggle, user avatar, sign-out, mobile hamburger
│   │   └── Sidebar.tsx           # Generic sidebar shell
│   └── ui/                       # Primitive UI components — Button, Input, Card, Select, Badge, Avatar, Spinner
│
├── lib/
│   ├── providers/                # AI provider implementations
│   │   ├── types.ts              # AIProvider, AIModel, ChatMessage, ProviderName (openai|anthropic|google|local)
│   │   ├── openai.ts             # OpenAI streaming adapter
│   │   ├── anthropic.ts          # Anthropic streaming adapter
│   │   ├── gemini.ts             # Google Gemini streaming adapter
│   │   ├── local.ts              # LocalProvider — Ollama + LM Studio via OpenAI-compatible API
│   │   └── index.ts              # Provider registry — getProvider(), getAllModels(), getModelsByProvider()
│   │
│   ├── storage/                  # Storage abstraction layer
│   │   ├── index.ts              # StorageAdapter interface + data types
│   │   ├── local.ts              # LocalStorageAdapter (standalone mode)
│   │   ├── supabase.ts           # SupabaseStorageAdapter (connected mode)
│   │   └── provider.tsx          # React context — detects mode and supplies the active adapter
│   │
│   ├── store/                    # Zustand client stores
│   │   ├── conversations.ts      # Conversation list state
│   │   ├── chat.ts               # Active chat state
│   │   ├── settings.ts           # User preferences + provider config + ollamaUrl + lmStudioUrl
│   │   ├── personas.ts           # AI personas state — 5 built-ins + custom, persisted to localStorage
│   │   └── StoreSync.tsx         # Bootstrap component: loads stores from adapter on mount
│   │
│   ├── workflow/                 # Workflow engine and storage
│   │   ├── types.ts              # All workflow types — NodeType, WorkflowNode, ExecutionResult, etc.
│   │   ├── engine.ts             # Execution engine — walks the graph, runs nodes in order
│   │   ├── registry.ts           # Node type registry — maps NodeType to React component + config defaults
│   │   ├── storage.ts            # Workflow CRUD over the active StorageAdapter
│   │   └── store.ts              # Zustand store for workflow editor state
│   │
│   ├── integrations/             # External app integration layer
│   │   ├── registry.ts           # registerProject(), getProject(), getAllProjects()
│   │   ├── context.ts            # buildProjectContext() — injects live data into system prompt
│   │   ├── actions.ts            # executeAction() — runs integration actions
│   │   └── contractors-room.ts   # Built-in Contractors Room integration definition
│   │
│   ├── auth/                     # API key authentication
│   │   └── api-keys.ts           # generateKey, hashKey, validateApiKey, createApiKey, revokeApiKey
│   │
│   ├── screening/                # AI screening engine
│   │   ├── index.ts              # startScreening, submitAnswers, getScreening, listScreenings
│   │   ├── types.ts              # Screening, ScreeningGrade, ContractorProfile, GRADE_LABELS
│   │   └── grading.ts            # LLM prompt builders + response parsers
│   │
│   ├── mcp/                      # Model Context Protocol server
│   │   └── server.ts             # Standalone MCP server (5 screening tools, stdio transport)
│   │
│   ├── supabase/                 # Supabase client setup
│   │   ├── client.ts             # Browser-side Supabase client (db: { schema: 'lucy' })
│   │   ├── server.ts             # Server-side Supabase client (db: { schema: 'lucy' })
│   │   ├── auth.tsx              # AuthProvider context — signIn, signUp, signOut, signInWithGoogle
│   │   ├── schema.sql            # Database migration — lucy schema tables + RLS policies
│   │   ├── api_keys.sql          # API key table migration
│   │   └── screening_rls_fix.sql # Multi-tenancy RLS fix
│   │
│   ├── scripts/                  # CLI utilities
│   │   └── seed-admin-key.ts     # Generates API key for [email protected]
│   │
│   └── utils/
│       ├── markdown.ts           # Markdown rendering helpers + generateConversationTitle
│       ├── stream.ts             # SSE encoder utilities for streaming API responses
│       └── tokens.ts             # Token estimation — estimateTokens(), estimateConversationTokens()
│
├── __tests__/                    # Jest test suites (282 tests, 49 suites)
│   ├── components/
│   │   ├── chat/ModelSelector.test.tsx
│   │   └── ui/Button.test.tsx
│   └── lib/
│       ├── integrations/registry.test.ts
│       ├── providers/index.test.ts
│       ├── storage/local.test.ts
│       ├── utils/markdown.test.ts
│       └── workflow/engine.test.ts
│
├── middleware.ts                 # Route protection — redirects unauthenticated users when Supabase is enabled
├── jest.config.ts                # Jest configuration (ts-jest, jsdom, @/ alias)
├── jest.setup.ts                 # Jest setup — loads @testing-library/jest-dom matchers
├── Dockerfile                    # Multi-stage production Docker build
├── docker-compose.yml            # docker-compose for running Lucy with env var passthrough
├── .dockerignore                 # Excludes node_modules, .next, tests from Docker build
├── .env.example                  # Environment variable template
├── tailwind.config.ts            # Tailwind configuration
├── next.config.js                # Next.js configuration
└── tsconfig.json                 # TypeScript configuration

Supabase Setup

Supabase is optional. Without it, Lucy runs fully in standalone mode using browser localStorage. When you want persistent, cross-device, multi-user storage with authentication, follow these steps.

1. Create a Supabase project

Go to supabase.com, create a new project, and note your Project URL and anon public key from Project Settings → API.

2. Set environment variables

NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...

3. Run the migration

Open the SQL Editor in your Supabase dashboard and execute the full contents of lib/supabase/schema.sql. This creates all required tables and indexes.

To enable the memory system (connected mode), also run lib/supabase/memory.sql followed by lib/supabase/memory_search.sql. These add the pgvector extension, the memory/entity/profile tables (HNSW + FTS indexes), RLS policies, the single-row memory_settings config, and the hybrid-search RPCs. Memory stays off until an admin enables it in Settings → Memory.

Database tables

All Lucy tables live in the lucy schema (not public). The schema provides namespacing so tables have clean names without prefixes. Supabase clients must be configured with db: { schema: 'lucy' }.

TableDescription
conversationsOne row per conversation. References auth.users.
messagesChat messages. Cascades on conversation delete. Includes model, provider, tokens_used.
provider_configsPer-user API key storage (encrypted at rest). Unique per (user_id, provider).
user_preferencesPer-user settings — theme, default model/provider, company name.
memory_profilesAlways-on per-user (and per-project) profile, merge-updated JSONB.
memoriesDurable semantic/pragmatic/episodic memories with halfvec(1536) embeddings + FTS, visibility, source, and bi-temporal valid_at/invalid_at.
entitiesSalient terms (clients, products, jargon) with occurrence/recency-driven importance.
memory_entitiesJoin table wiring memories ↔ entities.
memory_settingsSingle-row deployment config — memory gate, embedder, contradiction policy, deletion grace window.
workflowsWorkflow definitions. Stores nodes and edges as JSONB.
workflow_runsExecution history — inputs, outputs, logs, status, and timing.
screeningsAI screening records (grade, questions, transcript).
screening_answersIndividual Q&A answers per screening.
api_keysPer-user API keys (SHA-256 hashed, prefix for display).

Row Level Security

RLS is enabled on all tables. The policies ensure:

  • Users can only read and write their own conversations, messages, API configs, preferences, and workflows.
  • Messages are indirectly scoped through their parent conversation's user_id.
  • Screenings use created_by = auth.uid() — only the creator sees their screenings.

No service-role key is required for normal operation — the anon key with the user's JWT is sufficient. The screening API uses the service-role key to bypass RLS.


Local LLM Setup

Lucy supports running AI models locally with zero API cost. Both Ollama and LM Studio expose an OpenAI-compatible REST API that Lucy connects to automatically.

Ollama

# 1. Install Ollama from https://ollama.com
# 2. Pull a model
ollama pull llama3.1
ollama pull mistral

# 3. Start the server (runs on http://localhost:11434 by default)
ollama serve

LM Studio

  1. Download from lmstudio.ai
  2. Download a model from the Discover tab
  3. Go to Local ServerStart Server (runs on http://localhost:1234 by default)

Using local models in Lucy

Once a local server is running:

  1. Open Lucy → Settings → scroll to Local Models
  2. Click Detect Models to discover what is available
  3. The model selector in the chat input will now show a Local group with your running models
  4. Select any local model and chat normally — no API key required

Integrations

The integration layer lets any external application make its data and actions available to Lucy's AI. The pattern is intentionally simple: register a descriptor object once at startup and Lucy handles the rest.

Registry pattern

import { registerProject } from '@/lib/integrations/registry';

registerProject({
  id: 'my-app',
  name: 'My Application',
  description: 'Short description for the AI system prompt',
  supabaseSchema: 'my_app',   // Supabase schema where your tables live
  tables: [
    {
      name: 'projects',
      description: 'Active client projects with budgets and status',
      columns: [
        { name: 'name',   type: 'text',    description: 'Project name' },
        { name: 'budget', type: 'numeric', description: 'Approved budget' },
        { name: 'status', type: 'text',    description: 'Current status' },
      ],
      accessPolicy: 'user',   // 'user' | 'public' | 'admin'
    },
  ],
  actions: [
    {
      id: 'create-project',
      name: 'Create Project',
      description: 'Insert a new project row',
      parameters: [
        { name: 'name',      type: 'string', required: true,  description: 'Project name' },
        { name: 'budget',    type: 'number', required: false, description: 'Budget amount' },
        { name: 'company_id',type: 'number', required: true,  description: 'Client company ID' },
      ],
      handler: 'supabase-insert',
      config: { table: 'projects', schema: 'my_app' },
    },
  ],
});

Call registerProject() once during server startup (e.g., inside an API route module or a Next.js instrumentation file). On the client side you can call it inside a useEffect or a provider component.

Action handler types

HandlerDescription
supabase-insertINSERT a row into a Supabase table. config needs table and optional schema. sender_id / user_id are injected automatically.
supabase-updateUPDATE a row matching matchColumn. config needs table, schema, and matchColumn.
api-callPOST params as JSON to an external HTTP endpoint.
workflowTrigger a Lucy workflow by workflowId via /api/workflows/[id]/run.

Contractors Room — built-in example

lib/integrations/contractors-room.ts ships as the first reference integration. It registers 6 tables (user_profiles, companies, projects, project_tasks, messages, member_cvs) and 3 actions (create-project, send-message, update-contract-status) against the contractors_room Supabase schema.

It is automatically registered in app/api/chat/route.ts:

import { registerContractorsRoom } from '@/lib/integrations/contractors-room';
registerContractorsRoom();

Embeddable widget

Add Lucy as a floating chat panel to any web page with a single script tag:

<script
  src="https://your-lucy-instance.com/api/embed?project=contractors-room&model=gpt-4o&theme=dark&position=bottom-right"
  async
></script>

Query parameters:

ParameterDefaultOptions
project(none)Any registered integration id
modelgpt-4oAny model id (e.g. claude-sonnet-4-6)
themedarkdark, light, auto
positionbottom-rightbottom-right, bottom-left, inline

The script creates a fixed-position iframe (340 × 520 px) pointing at Lucy's /embed page. Using an iframe avoids React version conflicts with the host application.


Workflow Builder

The workflow builder gives you a visual canvas to compose multi-step AI pipelines. Each node in the graph represents a single processing step. Edges connect nodes to define execution order.

Node types

NodeDescription
StartEntry point for every workflow. Defines named input variables (e.g. user_query) that are passed through the pipeline and can be referenced by downstream nodes.
LLMCalls an AI model from any registered provider. Configure system prompt, temperature, max tokens, and which workflow variable to use as input.
ConditionBranches the graph based on a field evaluation. Supports operators: contains, not_contains, equals, not_equals, greater_than, less_than, regex, starts_with, ends_with.
Knowledge BaseQueries a named knowledge collection for semantically similar content. Returns the top-K results into the workflow context.
TransformMutates a value without calling an AI. Operations: template, uppercase, lowercase, trim, extract_json, combine, replace.
HTTP RequestMakes an outbound HTTP request (GET, POST, PUT, PATCH, DELETE) with configurable headers, body, and timeout. Response is injected into the workflow context.
IntegrationRuns an action on a registered Lucy integration (see Integrations). Maps workflow variables to action parameters.
OutputTerminal node. Marks the final value to surface as the workflow result. Supports text, markdown, and json display formats.

Execution model

When you click Run, the execution engine:

  1. Finds the start node and resolves initial variable values from the run panel inputs
  2. Traverses the graph in topological order, executing one node at a time
  3. Each node receives the current variable context, produces an output, and the engine merges it back into the context
  4. Condition nodes evaluate their expression and activate only the matching outgoing edge
  5. Execution state (idle, running, success, error) is broadcast back to the canvas in real time so each node shows its live status
  6. A full ExecutionResult with per-node logs (input, output, duration, error) is available in the Run panel after completion

Tech Stack

TechnologyVersionRole
Next.js16Full-stack React framework, App Router, API routes
React19UI library
TypeScript5Static typing across the entire codebase
Tailwind CSS3.4Utility-first styling
React Flow (@xyflow/react)12Workflow canvas — nodes, edges, drag-and-drop
Zustand5Lightweight client-side state management
Supabase JS2PostgreSQL persistence + Auth (optional)
OpenAI Node SDK6OpenAI client (also drives Ollama / LM Studio + other OpenAI-compatible providers)
Anthropic SDK0.10xAnthropic Claude client
Google Generative AI0.24Google Gemini client
@modelcontextprotocol/sdk1MCP — connector client + screening-tools server
grammY1Telegram bot framework
cron-parser4Workflow schedule (cron) parsing
Nodemailer8SMTP email (password reset, 2FA codes)
Electron42Desktop app shell
electron-builder26Desktop installers (.exe / .dmg / .AppImage)
react-markdown10Markdown rendering for AI responses
rehype-highlight7Syntax highlighting in code blocks
remark-gfm4GitHub Flavored Markdown support
lucide-react1Core icon set
@lobehub/icons5AI-provider brand icons
simple-icons16Company / connector brand icons
zod3Schema validation
Jest30Test runner
React Testing Library16Component testing utilities

API Routes

MethodPathDescription

view the full README on GitHub.

// compatibility

Platformscli, api, desktop, web, mobile
Operating systems
AI compatibilityclaude
LicenseAGPL-3.0
Pricingopen-source
LanguageTypeScript

// faq

What is lucy?

Lucy — open-core, self-hosted AI chat platform. Multi-provider (Claude/OpenAI/Gemini/local), memory, connectors, workflows. Local-first standalone mode or full connected deployment.. It is open-source on GitHub.

Is lucy free to use?

lucy is open-source under the AGPL-3.0 license, so it is free to use.

What category does lucy belong to?

lucy is listed under integrations in the Claudeers registry of Claude-compatible tools.

0 views
22 stars
unclaimed
updated 5 days ago

// embed badge

lucy on Claudeers
[![Claudeers](https://claudeers.com/api/badge/lucy.svg)](https://claudeers.com/lucy)

// retro hit counter

lucy hit counter
[![Hits](https://claudeers.com/api/counter/lucy.svg)](https://claudeers.com/lucy)

// reviews

// guestbook

0/500

// related in Integrations & Connectors

🔓

Use claude code and codex for free in the terminal, VSCode extension, and discord like OpenClaw (voice supported)

// integrationsAlishahryar1/Python39,205MIT[ claude ]
🔓

Bridge local AI coding agents (Claude Code, Cursor, Gemini CLI, Codex) to messaging platforms (Feishu/Lark, DingTalk, Slack, Telegram, Discord, LINE, WeChat…

// integrationschenhg5/Go13,605[ claude ]
🔓

All parts of Claude Code's system prompt, 27 builtin tool descriptions, sub agent prompts (Plan/Explore/Task), utility prompts (CLAUDE.md, compact, statusli…

// integrationsPiebald-AI/JavaScript11,624MIT[ claude ]
🔓

Fastest, smallest, and fully autonomous AI assistant infrastructure written in Zig

// integrationsnullclaw/Zig7,737MIT[ claude ]
→ see how lucy connects across the ecosystem