Case study
Cierra
An AI sales agent for WhatsApp sellers
Cierra answers buyer chats on a seller’s own WhatsApp number, negotiates inside a discount limit the seller sets, and saves orders as drafts for the seller to confirm. This page covers how it is built and why.
- My role
- Go API, WhatsApp gateway, AI service, and infrastructure
- Team
- Two engineers. Web dashboard mostly by Dimas Danang Aji
- Status
- MVP built, pilot sign-ups open. Production rollout of the WhatsApp and AI services is pending
- Stack
- Go, Python, gRPC, PostgreSQL + pgvector, Redis Streams, Next.js, Docker, Terraform

The problem
Slow replies cost sellers their buyers
- Sellers lose buyers to slow replies.
- They repeat the same negotiations all day.
- Orders get lost in the middle of a chat.
The agent speaks to real customers in the seller’s name. So the hard part is not generating replies. It is making sure the agent can never promise something the seller did not allow.
Architecture
Small services, one queue between them
- BuyerWhatsApp
- GatewayGo, whatsmeow
- QueueRedis Streams
- API workerGo
- AI servicePython, gRPC
- LLMQwen, OpenAI-compatible API
- PostgreSQL 16 + pgvectorSource of truth and catalog retrieval
- DashboardNext.js over REST and SSE
- ObservabilityOpenTelemetry, Prometheus, Grafana, Loki
Hover the diagram to see data flow left to right.
Three boundary rules
- 01The API is the only service facing the internet. The gateway, AI service, database, and Redis are reachable only inside the private network.
- 02The gateway never talks to the LLM directly. Everything goes through the queue.
- 03Every database query carries a tenant context, and the repository layer rejects queries without it.
One message
What happens when a buyer asks for a discount
A buyer writes: “Is there red? Can I get a discount?”
The gateway receives it, drops duplicates by WhatsApp message id, stores it, and pushes it to the inbound stream.
A worker loads the context: seller, customer, chat history, and the seller’s sales playbook.
The AI service checks escalation keywords, retrieves from the seller’s own catalog, generates a structured reply, runs its guards, and falls back to a second model if needed.
If an order is detected, an order draft is created and the owner is notified. If the chat needs a human, it switches to takeover mode.
The reply streams back, is assembled into one message, and goes to the outbound stream.
The gateway sends it with rate limiting and a short pause between messages.
Decisions
Choices that shaped the system, and why
Go for the WhatsApp gateway
whatsmeow is the only production-grade multi-device WhatsApp library, and it is written in Go. That settled the language at the heart of the system. A third language with no clear need was rejected.
A separate Python service for the AI, over gRPC
The conversation pipeline is a plain Python function: retrieve, generate, guard, fall back. The only contract between the services is a small protobuf, frozen early and changed only in backward-compatible ways.
Business rules live in code, not only in the prompt
The discount limit, false “your order is recorded” claims, and order validation are checked in the AI service. Items and prices are checked again in the API against the seller’s own catalog, so a model mistake cannot create a wrong order.
No agent framework
A graph framework was considered and dropped. One turn is a straight line with one branch, the fallback model, and chat history already lives in the messages table. Plain functions are easier to test.
Redis Streams now, Kafka later
Streams give consumer groups and a dead-letter queue. Kafka stays deferred until traffic holds around a thousand messages a minute.
Tenant isolation in the application layer
A middleware injects the business id and the repository refuses queries without it. This replaced the row-level security of the earlier hosted database setup.
Docker Compose before Kubernetes
One server, described in Terraform. The written triggers for moving to Kubernetes are more than four services, more than one server, or a team larger than three.
Quality and operations
How it is kept honest
- 23 Go test files and 5 Python test files, plus an evaluation suite for the sales agent.
- CI runs lint, tests, and an image build on every change. Deploys are manual from the main branch, run by a self-hosted runner on the production server, with images built locally and no external registry.
- Infrastructure changes go through Terraform pull requests, not the cloud console.
- The LLM provider is isolated in its own module, so swapping models or vendors is a contained change.
- Architecture decisions are written down, and changes arrive as pull requests against the architecture document.
Where it stands
Built, with launch work still ahead
Based on the repository audit of 13 October 2026.
Done
- Foundation, core API with auth, and data migration
- WhatsApp gateway
- AI service, code complete
- Web dashboard connected to the new API
Before launch
- Deploy the gateway and AI services to production
- End-to-end test with two real phones, measuring token cost and time to first reply
- Alerting, runbooks, and a restore drill
- Load test
After the MVP
- Automatic follow-ups
- Voice-note transcription
- Real-time inbox
- TikTok Shop connector, if partner approval comes through
Hiring for a team that ships?
Email works best for roles and project details. For a quick question, WhatsApp is fine too.