Multi-tenant AI chat agent platform. Each tenant gets a configurable agent powered by LLMs, with optional RAG for knowledge-grounded responses.
Built on Memos with OpenRouter for LLM access and LanceDB for vector search.
- Overview
- Quick Start
- Architecture
- Configuration
- Development
- API Reference
- Deployment
- Contributing
- Documentation
bchat is a multi-tenant AI chat agent platform. A single deployment powers unlimited independent AI chat agents — one per business — with no code changes between tenants.
| Principle | Description |
|---|---|
| General-purpose | No tenant-specific logic in code. All customization via config files. |
| Configuration-driven | Agent behavior defined by KB.MD, POLICY.MD, SCRIPT.MD per tenant. |
| Multi-tenant isolation | Each tenant has isolated data, configs, and chat sessions. |
| Layer | Technology |
|---|---|
| Backend | Go 1.25.0, Echo framework |
| Database | SQLite (default), PostgreSQL |
| Frontend | React 18, TypeScript, MobX, Vite |
| UI | Joy UI (@mui/joy) |
| LLM | OpenRouter API |
| Vector DB | LanceDB (optional, for RAG) |
| Embeddings | OpenRouter text-embedding-3-small, local, or mock |
For business owners and operators (KB/POLICY writing, widget deployment, lead capture), see docs/DOCS_HOWTO_BIZ.MD.
- Go 1.25.0+
- Node.js 18+ (for frontend)
- Task (task runner)
- OpenRouter API key (
sk-or-v1-...)
# Clone and install
git clone <repo-url> && cd bchat
task setup
# Set API key
export OPENROUTER_API_KEY=sk-or-v1-your-key-here
# Build and run
task build
./build/memos --mode dev --data build/dataApp starts at http://localhost:8081. Admin UI at /agent-admin.
RAG = agent searches KB.MD for relevant context before answering.
task build:rag
task run:rag
# Or with mock embeddings (no API key needed for testing)
task run:rag:mock# Terminal 1: Backend
task dev:backend
# Terminal 2: Frontend
task dev:frontendFrontend: http://localhost:5173 | Backend API: http://localhost:8081/api/v1/
bchat/
├── bin/memos/ # Application entry point
├── build/ # Build output
│ └── data/ # Runtime data (SQLite DB, LanceDB indexes)
├── docs/ # Documentation
├── server/
│ └── router/api/v1/
│ ├── agent/ # Agent API handlers and services
│ │ ├── handlers.go # HTTP request handlers
│ │ ├── service.go # Business logic, LLM integration
│ │ ├── parser.go # KB/Policy/Script parsing
│ │ ├── vectordb.go # Vector database interface
│ │ ├── vectordb_lance.go # LanceDB implementation
│ │ ├── embedding.go # Embedding providers
│ │ ├── chunker.go # Document chunking
│ │ ├── observer.go # Observational memory
│ │ ├── simulation.go # Agent simulation
│ │ ├── analysis.go # Transcript analysis
│ │ ├── verifier.go # LLM response verification
│ │ ├── sanitizer.go # Output sanitization
│ │ └── prompts/ # Prompt templates
│ ├── auth.go # JWT claims, token generation
│ ├── auth_service.go # Auth endpoints, tenant selection
│ ├── acl.go # gRPC auth interceptor
│ ├── tenant_context.go # Tenant context helpers
│ ├── memo_service.go # Memo CRUD with tenant scoping
│ ├── ticket_service.go # Ticket CRUD with tenant scoping
│ └── v1.go # Route registration
├── store/
│ ├── agent.go # Data types and store interface
│ ├── driver.go # Database driver interface
│ ├── db/sqlite/ # SQLite implementation
│ ├── db/postgres/ # PostgreSQL implementation
│ └── migration/sqlite/ # Database migrations
├── web/
│ ├── src/
│ │ ├── pages/ # React page components
│ │ ├── store/v2/ # MobX stores
│ │ └── locales/ # i18n translations
│ └── dist/ # Built frontend assets
├── widget/ # Embeddable chat widget
├── plugin/ # Cron, webhook, storage plugins
└── Taskfile.yml # Build and run commands
Client Request
│
▼
Echo Router (/api/v1/agent/:slug/...)
│
▼
Agent Handler (handlers.go)
│
├─► Permission Check (RBAC)
│
▼
Agent Service (service.go)
│
├─► Parse KB/Policy/Script
├─► [Optional] RAG Search (vectordb.go)
├─► Build System Prompt
└─► Call OpenRouter LLM
│
▼
SSE Response Stream
Every API request is scoped to a single tenant via JWT claims:
JWT (tenant_id) → Auth Middleware → Context → Handler → DB Query (WHERE tenant_id = ?)
- gRPC handlers: Extract tenant from Go context via
GetTenantIDFromContext(ctx) - Echo handlers: Extract tenant from echo context via
getTenantFromContext(c) - Superusers: Bypass tenant checks for cross-tenant access
OPENROUTER_API_KEY=sk-or-v1-xxx # OpenRouter API key (required)LLM_MODEL=openai/gpt-4o-mini # Default chat model
LLM_MODEL_REASONING=google/gemini-2.5-pro # Content generation modelRAG_PIPELINE_ENABLED=true # Enable RAG pipeline
EMBEDDING_PROVIDER=openrouter # openrouter|local|mock
EMBEDDING_MODEL=text-embedding-3-small
EMBEDDING_BATCH_SIZE=10
EMBEDDING_TIMEOUT=180s
LANCEDB_STORAGE_PROVIDER=local # local|s3
LANCEDB_LOCAL_PATH=build/data/lancedb
HYBRID_SEARCH_ENABLED=true # Vector (70%) + BM25 (30%)OM_ENABLED=true # Long-term memory
OM_OBSERVER_TOKEN_THRESHOLD=30000
OM_TOKEN_THRESHOLD=2000FORCE_REINDEX_ON_STARTUP=true # Re-index all content at boot
LLM_VERIFIER_ENABLED=true # LLM response verification1. Tenant Config (Agent Admin UI) → Highest
↓ (if empty)
2. Environment Variable → Fallback
↓ (if empty)
3. Hardcoded Default → Lowest
See docs/DOCS_ENV_VAR.MD for complete reference.
| Command | Description |
|---|---|
task setup |
Install all dependencies |
task build |
Build frontend + backend |
task build:frontend |
Frontend only |
task build:backend |
Backend only |
task build:rag |
Full build with RAG (LanceDB) |
task run |
Run dev server |
task run:rag |
Run with RAG enabled |
task run:rag:mock |
Run with mock embeddings (no API key) |
task dev:backend |
Backend with hot reload |
task dev:frontend |
Frontend with hot reload |
task validate:schema |
Validate database schema |
Adding a new API endpoint:
- Define types in
store/agent.go - Add interface methods in
store/driver.go - Implement in
store/db/sqlite/agent.go(+ stubs for postgres/mysql) - Add handler in
server/router/api/v1/agent/handlers.go - Register route in
server/router/api/v1/v1.go
Adding a new database table:
- Create migration in
store/migration/sqlite/NN__description.sql - Add Go types in
store/agent.go - Add interface in
store/driver.go - Implement in
store/db/sqlite/agent.go - Migrations auto-apply on startup
Code conventions:
- Use
slogfor logging:slog.Error("message", "error", err) - Return errors with context:
fmt.Errorf("failed to X: %w", err) - Pointer receivers for methods
- JSON tags:
snake_case
Adding a new feature:
- Add types and state to store (e.g.,
web/src/store/v2/agentAdmin.ts) - Add fetch methods with
runInActionfor async updates - Add UI component in
web/src/pages/ - Add translations to
web/src/locales/en.json
Code conventions:
- MobX
makeAutoObservablefor stores runInActionfor all async state updatesobserverHOC for reactive components- Joy UI components from
@mui/joy
Location: store/migration/sqlite/
Naming: NN__snake_case_description.sql
CREATE TABLE IF NOT EXISTS my_table (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tenant_id INTEGER NOT NULL,
FOREIGN KEY (tenant_id) REFERENCES agent_tenant(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_my_table_tenant ON my_table(tenant_id);| Method | Path | Description |
|---|---|---|
POST |
/api/v1/agent/:slug/chat |
Send chat message |
GET |
/api/v1/agent/:slug/chat/stream |
SSE response stream |
GET |
/widget/:slug/embed.js |
JavaScript widget embed |
GET |
/widget/:slug/iframe |
iframe widget embed |
| Method | Path | Description |
|---|---|---|
POST |
/api/v1/auth/tenants |
List tenants for multi-tenant user |
POST |
/api/v1/auth/select-tenant |
Select tenant, return JWT with tenant_id |
| Method | Path | Permission | Description |
|---|---|---|---|
GET/POST |
/api/v1/agent/tenants |
tenant:admin |
List/Create tenants |
GET/PUT/DELETE |
/api/v1/agent/:slug |
tenant:admin |
CRUD tenant |
POST |
/api/v1/agent/:slug/files |
files:upload |
Upload KB/Policy/Script |
POST |
/api/v1/agent/:slug/reindex |
api:config |
Rebuild RAG index |
POST |
/api/v1/agent/:slug/simulate |
chat:test |
Run simulation |
GET |
/api/v1/agent/:slug/simulations |
chat:test |
List simulations |
POST |
/api/v1/agent/:slug/generate-kb |
tenant:admin |
Auto-generate KB.MD |
POST |
/api/v1/agent/:slug/rag/search |
api:config |
Test RAG search |
GET |
/api/v1/agent/:slug/leads |
tenant:admin |
List leads |
GET |
/api/v1/agent/:slug/leads/export |
tenant:admin |
Export leads CSV |
| Permission | Description |
|---|---|
tenant:admin |
Full tenant management |
tenant:read |
View tenant configuration |
api:config |
Configure LLM settings, rebuild index |
chat:test |
Run simulations, view history |
chat:logs |
View real chat session logs |
files:upload |
Upload KB/Policy/Script files |
docker build -t bchat .
docker run -e OPENROUTER_API_KEY=sk-or-v1-xxx -p 8081:8081 bchatexport FLY_API_TOKEN=...
fly launch
fly deployPre-deployment checks:
task fly:check # Validate env chain
task fly:db-check # Validate migrations
task fly:pre-deploy # Run all checksSee docs/DOCS_DEPLOY_FLY.MD for full deployment guide.
Contributions welcome! See AGENTS.md for the development guide, code conventions, and patterns for adding new features.
| Document | Description |
|---|---|
docs/DOCS_README.MD |
Comprehensive project documentation |
docs/DOCS_ENV_VAR.MD |
Environment variables reference |
docs/DOCS_TASKFILE.MD |
Build commands reference |
AGENTS.md |
AI agent development guide |
| Document | Description |
|---|---|
docs/DOCS_AGENT_ARCHITECTURE.MD |
Configuration-driven design |
docs/DOCS_CHAT_DESIGN.MD |
Chat agent design spec |
docs/DOCS_RAG_PIPELINE.MD |
RAG pipeline architecture |
docs/DOCS_HYBRID_SEARCH.MD |
Hybrid search (vector + BM25) |
| Document | Description |
|---|---|
docs/DOCS_SIMULATION.MD |
Agent simulation feature |
docs/DOCS_WIDGET.MD |
Chat widget integration |
docs/DOCS_HOWTO_BIZ.MD |
Business owner guide |
| Document | Description |
|---|---|
docs/DOCS_DEPLOY_FLY.MD |
Fly.io deployment guide |
docs/DOCS_ROLLOUT.MD |
Production rollout guide |
docs/CHANGELOG.MD |
Project changelog |
MIT License
Copyright (c) 2026 Pithom Labs
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.