WAIR is a privacy-first, local-first AI assistant for WhatsApp that enables natural language search across your complete chat history. All data remains on your machine—nothing is sent to external servers.
WAIR indexes your WhatsApp conversations into an encrypted local database and uses retrieval-augmented generation (RAG) to answer questions about your chat history. You interact with it through WhatsApp itself or a web dashboard.
How it works:
- Connect to WhatsApp via QR code authentication (Baileys library)
- Messages are indexed, embedded, and stored in an encrypted SQLite database
- When you ask a question, the system performs hybrid search (vector similarity + full-text search)
- Retrieved context is passed to a local LLM (via Ollama) to generate an answer
- Results are returned with source citations
- Natural Language Search — Ask questions like "What did Alice say about the project last week?" or "Find the document Mr. Huang sent me"
- Hybrid RAG Retrieval — Combines vector embeddings (semantic search) with FTS5 full-text search, with configurable weighting
- Intent Classification — Queries are classified into types (person, temporal, document, image, summary) with tuned search strategies per intent
- Multi-modal Indexing — Processes text, images (with OCR via Tesseract), documents (PDF, Word), and voice messages
- End-to-End Encryption — SQLCipher encrypts the database (AES-256), media files use AES-256-GCM with scrypt-derived keys
- WhatsApp Commands — Control the system from WhatsApp:
/search,/status,/help,/exclude,/delete,/export - Auto-Reply — Message yourself on WhatsApp to query your history (configurable)
- Web Dashboard — EJS-based admin panel with query testing, chat history, indexing status, system health, and backup/restore
- Real-time Monitoring — SSE endpoint for live dashboard updates
- Node.js 20.11.0 or later
- Ollama (for local LLM and embeddings)
- 8 GB RAM minimum, 16 GB recommended
- 50 GB+ storage (SSD recommended)
ollama pull qwen3.5:4b # LLM for generating answers
ollama pull nomic-embed-text # Embedding model for vector searchnpm install- Copy
.env.exampleto.env:
cp .env.example .env- Set the required variables:
| Variable | Required | Description |
|---|---|---|
DATABASE_PASSWORD |
Yes | Encryption password for SQLCipher (min 8 chars). Lost password = lost data. |
DASHBOARD_ADMIN_PASSWORD |
Yes | Password for web dashboard access |
- Review optional settings in
.envas needed (see.env.examplefor all options):
| Variable | Default | Description |
|---|---|---|
PORT |
3000 | Dashboard port |
OLLAMA_HOST |
http://localhost:11434 | Ollama API endpoint |
LLM_MODEL |
qwen3.5:4b | LLM model |
LLM_TEMPERATURE |
0.7 | LLM temperature |
RAG_VECTOR_WEIGHT |
0.7 | Vector search weight in hybrid search (remainder is FTS weight) |
RAG_TOP_K |
10 | Number of results to retrieve |
EMBEDDING_MODEL |
nomic-embed-text | Embedding model |
WHATSAPP_AUTO_RECONNECT |
true | Auto-reconnect on disconnect |
DASHBOARD_SESSION_TIMEOUT |
30 | Session timeout (minutes) |
RETENTION_POLICY |
forever | Message retention (30d, 1y, 2y, forever) |
npm run devnpm run build
npm startnpm run setupOn first launch, a QR code appears in the terminal. Scan it with WhatsApp (Settings → Linked Devices → Link a Device). The client auto-reconnects on disconnect (configurable max attempts).
Open http://localhost:3000 and log in with your DASHBOARD_ADMIN_PASSWORD.
Send commands to yourself (auto-reply must be enabled):
/search What did I discuss with mom about the trip?
/status
/help
/exclude Group Chat Name
/delete chat-id
/export
The web interface provides:
- Query Test — Submit natural language queries with detailed result breakdown
- Chat History — View and manage indexed conversations
- Messages — Monitor real-time message ingestion
- Indexing Status — Track indexing progress and statistics
- System Health — Resource usage and system metrics
- Settings — Configure RAG, LLM, retention, and application settings
- Backup & Restore — Create and restore database backups
Examples:
- "What did Alice say about the project deadline?"
- "Find a photo from the beach trip with Jessica"
- "Retrieve the document Mr. Huang sent last week"
- "What are Anna and James planning for next month?"
┌─────────────────────────────────────────────────┐
│ Application Layer │
│ WhatsApp Module │ API │ Dashboard │ Commands │
└───────────────────────┬─────────────────────────┘
│
┌───────────────────────▼─────────────────────────┐
│ Core Services │
│ Query Processor │ RAG Engine │ LLM Provider │
│ Intent Classifier │ Embedding Service │ Queue │
└───────────────────────┬─────────────────────────┘
│
┌───────────────────────▼─────────────────────────┐
│ Data Layer │
│ SQLCipher-encrypted SQLite (wss.db) │
│ Metadata │ sqlite-vec │ FTS5 │ Media (AES-GCM) │
└─────────────────────────────────────────────────┘
- Database: SQLCipher encrypts the entire SQLite file with AES-256
- Media Files: Individual files encrypted with AES-256-GCM
- Keys: Derived from
DATABASE_PASSWORDvia scrypt (N=16384, r=8, p=1), never persisted to disk - Sessions: Express sessions with configurable timeout, stored in SQLite
- Rate Limiting: Configurable request rate limiting on API endpoints
Important: There is no password recovery. If you lose DATABASE_PASSWORD, the database cannot be decrypted.
src/
├── index.ts # Entry point, bootstrap, graceful shutdown
├── app.ts # Express app configuration
├── config/ # Environment config, validation, defaults
├── whatsapp/ # Baileys client, session management, media download
├── database/
│ ├── connection.ts # SQLCipher SQLite connection
│ ├── schema.ts # Table definitions (contacts, chats, messages, FTS5, settings)
│ ├── vector.ts # Vector operations and hybrid search
│ └── repositories/ # Data access layer (chats, contacts, messages, indexing)
├── rag/
│ ├── engine.ts # RAG orchestration and context building
│ ├── embedding.ts # Embedding generation via Ollama
│ ├── hybrid.ts # Hybrid search (vector + FTS combination)
│ ├── reranker.ts # Result re-ranking (recency, exact match boost)
│ └── chunking.ts # Text chunking for processing
├── llm/
│ ├── provider.ts # Ollama LLM provider with streaming
│ ├── context.ts # Conversation context management
│ └── prompts.ts # System prompt definitions
├── query/
│ ├── processor.ts # Query orchestration (parse → RAG → LLM → result)
│ ├── parser.ts # Query parsing and entity extraction
│ └── intent.ts # Intent classification with confidence scoring
├── media/ # Media processing (PDF, images, documents, OCR)
├── security/
│ ├── encryption.ts # AES-256-GCM media encryption
│ └── keys.ts # scrypt key derivation
├── commands/
│ ├── registry.ts # Command registry
│ └── handlers/ # /help, /status, /search, /exclude, /delete, /export
├── jobs/
│ ├── queue.ts # Job queue (p-queue)
│ └── workers/ # Message ingestion, embedding, image processing
├── api/
│ ├── routes/ # REST endpoints (health, query, chats, settings, etc.)
│ └── middleware/ # Rate limiting, logging, error handling
├── dashboard/
│ ├── routes.ts # Web dashboard routes with auth + SSE
│ └── views/ # EJS templates
└── utils/ # Logger (Winston), error classes, constants
| Endpoint | Method | Description |
|---|---|---|
/api/v1/health |
GET | Health check |
/api/v1/status |
GET | System status |
/api/v1/query |
POST | Execute natural language query |
/api/v1/chats |
GET | List indexed chats |
/api/v1/chats/:id |
DELETE | Delete a chat and its data |
/api/v1/messages |
GET | List indexed messages |
/api/v1/indexing/rebuild |
POST | Rebuild search index |
/api/v1/settings |
GET, POST | View/update settings |
/api/v1/whatsapp/qr |
GET | Get current QR code |
/api/v1/whatsapp/status |
GET | WhatsApp connection status |
/api/v1/backup/create |
POST | Create database backup |
/api/v1/backup/restore |
POST | Restore from backup |
/events |
GET | Server-Sent Events for real-time updates |
| Command | Description |
|---|---|
npm run dev |
Start with hot reload (tsx watch) |
npm run build |
Compile TypeScript to JavaScript |
npm start |
Run production build |
npm run setup |
Run initial setup wizard |
npm run backup |
Create database backup |
npm run restore |
Restore from backup |
npm run migrate |
Run database migrations |
npm run reset:whatsapp |
Reset WhatsApp session |
npm test |
Run test suite |
npm run test:watch |
Run tests in watch mode |
npm run test:coverage |
Run tests with coverage report |
npm run lint |
Run ESLint |
npm run lint:fix |
Auto-fix ESLint issues |
npm run format |
Format code with Prettier |
npm run format:check |
Check code formatting |
A Dockerfile and docker-compose.yml are provided for containerized deployment. Build and run with:
docker-compose up -dOllama connection fails
- Verify Ollama is running:
ollama serve - Confirm models are downloaded:
ollama list - Check
OLLAMA_HOSTin.envmatches your Ollama endpoint
Database encryption error
- Ensure
DATABASE_PASSWORDis set and at least 8 characters - Changing the password after data exists requires reinitializing the database
WhatsApp won't connect
- The client auto-reconnects (max attempts set by
WHATSAPP_MAX_RECONNECT_ATTEMPTS) - If reconnection fails, restart the app and scan a new QR code
Slow indexing
- Initial indexing of existing chat history takes time depending on volume
- Adjust
QUEUE_CONCURRENCYin.envto process messages in parallel - Monitor progress via the dashboard Indexing Status page
MIT