AI-powered WhatsApp order management for Ghanaian SMEs.
Customers text a WhatsApp number in natural language — "I want 2 wings and a Coke, deliver to East Legon, paying with Momo" — and Chatalog's agentic loop (Claude calling tools against Postgres) takes the order, confirms the total, and replies. Store owners watch orders flow across a Kanban in real time and manage the menu with natural language too.
┌────────────────────┐
WhatsApp user ─▶ │ Twilio WhatsApp │
│ Sandbox │
└─────────┬──────────┘
│ webhook (form-encoded POST)
▼
┌────────────────────┐
│ FastAPI :8000 │
│ /webhook/whatsapp │
│ /api/orders │──┐
│ /api/menu │ │
│ /api/admin/* │ │
└─────────┬──────────┘ │
│ │ HTTP (axios + TanStack Query)
┌─────────▼──────────┐ │
│ agents/loop.py │ │
│ Claude tool-use │ │ ┌──────────────────┐
│ loop (max 5) │◀─┼──│ Next.js :3001 │
└─────────┬──────────┘ │ │ Kanban + Menu │
│ │ │ + NL command │
│ asyncpg │ └──────────────────┘
▼
┌────────────────────┐
│ Postgres 16 │
│ businesses │
│ menu_items │
│ orders (JSONB) │
│ conversations │
└────────────────────┘
The agentic loop is the heart of the product. It loads the last 20 conversation messages + the business + the menu, builds a system prompt (customer or admin mode), and calls Claude with 11 tools. Claude may call any number of tools (up to 5 iterations) — each call runs against Postgres via asyncpg — before composing a final text reply that Chatalog sends back through Twilio.
- Docker Desktop (for Postgres)
- Python 3.12+ (Python 3.14 also works)
- Node.js 20+
- An Anthropic API key (
sk-ant-api03-...) - A Twilio account with the WhatsApp sandbox enabled — only needed for live WhatsApp testing; the HTTP APIs and admin NL command work without it
git clone <repo-url> chatalog
cd chatalog
cp .env.example apps/api/.envEdit apps/api/.env and fill in at least:
ANTHROPIC_API_KEY— your real Anthropic keyTWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN,TWILIO_WHATSAPP_NUMBER— only if testing WhatsApp live
docker-compose up -dPostgres runs on localhost:5432, pgAdmin on http://localhost:5050.
cd apps/api
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn main:app --reload --port 8000The API auto-creates the schema on startup and seeds a blank business row. Health check: curl http://localhost:8000/health.
In a new terminal:
cd apps/dashboard
npm install
npm run dev -- --port 3001Visit http://localhost:3001 — you'll see an empty Kanban.
Open http://localhost:3001/settings and click Load demo data. The Kanban populates with 8 orders spanning every column, and the Menu page shows 10 items. Idempotent — clicking again is a no-op.
- Sign up at twilio.com and enable the WhatsApp sandbox (Messaging → Try it → Send a WhatsApp message).
- Join the sandbox from your phone — text the join code to Twilio's sandbox number.
- Expose your local API to the public internet:
ngrok http 8000
- In the Twilio console, set the sandbox inbound webhook to
https://<your-ngrok-host>/webhook/whatsapp(HTTP POST). - Text the sandbox number from your phone — "hi" or "what's on the menu?" — and Chatalog replies.
| Variable | Purpose |
|---|---|
DATABASE_URL |
Postgres connection string |
ANTHROPIC_API_KEY |
Anthropic API key |
TWILIO_ACCOUNT_SID |
Twilio account SID |
TWILIO_AUTH_TOKEN |
Twilio auth token |
TWILIO_WHATSAPP_NUMBER |
whatsapp:+14155238886 (sandbox) |
MOMO_NUMBER |
Momo number shown to customers for payment |
BUSINESS_NAME |
Business display name (seeded into businesses on first run) |
NEXT_PUBLIC_API_URL |
FastAPI base URL for the dashboard (http://localhost:8000) |
- Open the dashboard at
http://localhost:3001. Click Settings in the sidebar → Load demo data. - Show the Kanban — 8 orders spread across New, Confirmed, Preparing, Delivered + the collapsed Cancelled drawer. Stats bar shows today's count, pending payments, revenue. The "Live" pulse shows the WhatsApp bot active.
- Advance an order — click the next-status button on a card; it hops to the next column. Toast confirms.
- Open a detail sheet — click any card. Show status/payment dropdowns + notes. Save, watch the Kanban update.
- Menu page — show the table grouped by category.
- NL command bar — type "Add grilled chicken breast for GHS 85 in mains". Within a few seconds, the table updates with the new item. Claude's reply appears in the history.
- Try more NL commands — "Change the price of Malt to GHS 14" · "Mark Water 500ml as unavailable" — all reflect immediately.
- Back to Orders — seed data + new mutations all visible.
- WhatsApp side (if Twilio is wired) — text the sandbox "I want 2 wings, deliver to Osu, paying on delivery". Watch the agent extract the order, confirm the total, insert into the DB. A new card appears in the New column within 10 seconds.
cd apps/api
source .venv/bin/activate
pytest -vExpected: 68 tests pass. Dashboard has no unit tests by design — run cd apps/dashboard && npx tsc --noEmit to type-check.
chatalog/
├── apps/
│ ├── api/ FastAPI backend (Python)
│ │ ├── agents/ tools.py, prompts.py, loop.py — the Claude agentic loop
│ │ ├── db/ schema.sql, connection.py, seed.py
│ │ ├── routers/ webhook.py, orders.py, menu.py, admin.py
│ │ └── services/ claude.py, twilio.py
│ └── dashboard/ Next.js 16 + Tailwind + shadcn/ui
│ ├── app/ /, /menu, /settings
│ ├── components/ KanbanBoard, OrderCard, MenuManager, NLCommandBar, …
│ ├── lib/ api.ts, format.ts
│ └── types/ order.ts (Zod schemas)
└── docker-compose.yml