Elly is an Electron desktop app. It is an AI chat app. It streams replies in real time. It can also run local tools (read/write files, run shell commands) with your approval.
- Chat threads and message history (SQLite)
- Streaming assistant output (WebSocket)
- Multiple AI providers (OpenAI, Anthropic, Google) via Vercel AI SDK
- Tool calling with a permission popup:
read_file/write_file/edit_filebashglob/grep
- Workspace sandbox for tools:
- Tools can only access files inside the active workspace
- Sensitive files are blocked (like
.envand.ssh)
- Electron + electron-vite
- React 19 + TypeScript
- Tailwind CSS v4 + shadcn/ui
- Express (local HTTP API) + ws (WebSocket)
- SQLite (better-sqlite3) + Drizzle ORM
- Vitest
- HTTP API:
http://localhost:23001 - WebSocket:
ws://localhost:8765
- Node.js 20+
- pnpm 9+
If you do not have pnpm:
corepack enable
corepack prepare pnpm@9 --activatepnpm installStart the Electron app. This also starts AI SDK DevTools.
pnpm devStart only the app (no DevTools):
pnpm dev:appStart only the API server:
pnpm dev:apipnpm test
pnpm lint
pnpm formatTypeScript typecheck:
pnpm typecheck
# or
pnpm typecheck:node
pnpm typecheck:webThe app reads providers from the local database table providers.
The UI currently uses the model string google/gemini-2.5-flash.
So you need a provider row with id google.
- Start the app (or at least the API server).
- Create a provider by calling the API:
curl -X POST http://localhost:23001/api/providers \
-H "Content-Type: application/json" \
-d '{
"id": "google",
"name": "Google",
"type": "google",
"apiKey": "YOUR_API_KEY",
"baseUrl": "",
"enabled": true
}'Notes:
- Your API key is stored in SQLite.
- Set
baseUrlto an empty string ("") to use the default API URL. - Do not commit or share your
elly.dbfile.
- Dev database file:
./elly.db - Prod database file: Electron
userData/elly.db(fallback:~/.elly/elly.db)
Migrations:
pnpm db:generate
pnpm db:migrateSeed demo data (fake keys, for UI testing):
pnpm db:seedOpen Drizzle Studio:
pnpm db:studioSome tools need your approval before they run. The renderer shows a popup.
See docs/tool-call.md for the flow.
Sensitive files are blocked by default:
.envand.env.*.git/configid_rsa.ssh/
src/main/: Electron main process (DB, API server, tools, IPC)src/preload/: Preload bridge (window.api)src/renderer/: React UIsrc/shared/: Shared types (IPC and WebSocket messages)docs/: Developer docs
Electron Builder config is in electron-builder.yml.
pnpm build:mac
pnpm build:win
pnpm build:linux- API not reachable: check port
23001 - No streaming output: check WebSocket
8765 - DB errors:
- Close the running Electron app.
- Run
pnpm db:migrate.