The flagship of my AI & Automation work, and my startup. A production platform where an AI agent runs a real-estate agency's WhatsApp line: replying in seconds at any hour, transcribing voice notes in Twi, Pidgin and English, matching leads to real listings without ever inventing one, booking viewings, chasing quiet leads on Day 3/7/14/30, and logging every word into the CRM automatically. Agents control everything from a Telegram bot, mostly by voice. Live in production: 15 n8n workflows, Claude API reasoning, Twenty CRM, and an ~86,000-character engineered persona prompt.
My Role
Co-founder · AI & Automation Engineer
Duration
3 months · 2026 · ongoing
Context
Agentic Realty, my PropTech startup
Outcome
Live in production · 15 n8n workflows · replies in seconds, 24/7 · voice notes in 3 languages
Stack
Context
Mid-tier real-estate agencies in Accra run their entire business on WhatsApp. Around 30 to 80 inquiries a week land on agents' personal phones while they're out on viewings. There is no CRM, or an empty one. Every conversation lives and dies in a chat thread.
The Pain
A lead messages four or five agencies at once, and the fastest reply wins the deal. Messages sit unanswered overnight and on weekends. Follow-ups are forgotten. Voice notes in Twi or Pidgin get skipped. When an agent leaves, their chats, and the pipeline inside them, leave with them.
Why It Mattered
Every ignored message is lost commission. The pitch to agency owners is not 'AI'. It's revenue recovery: the deals dying in their inbox every night, recovered by being the agency that always answers first.
Technical Goals
Constraints
WhatsApp Cloud API webhooks feed an n8n orchestration layer of 15 production workflows. Claude API provides the reasoning behind 'Ama', a warm, persona-engineered agent with an ~86,000-character system prompt, while Groq Whisper transcribes Twi/Pidgin/English voice notes. Twenty CRM is the system of record, accessed exclusively through its GraphQL API; a separate n8n-owned PostgreSQL database holds operational data (leads, conversations, follow-ups, viewings, deals). Redis provides Lua-scripted conversation locks. A Telegram bot is the agents' control plane. The whole stack runs on Docker Compose behind Nginx on an AWS VPS.
Scroll horizontally on smaller screens to view full diagram
n8n
Orchestrates all 15 workflows: comms routing, lead intake, nurture, matching, reviews, escalation SLA, CRM sync, and the Telegram agent
Claude API ('Ama')
The conversational brain: qualifies leads, answers from real inventory only, and hands negotiations to a human. All of it driven by an ~86K-character engineered persona prompt
Groq Whisper
Transcribes WhatsApp voice notes. Leads speak Twi, Pidgin, or English while driving, and Ama answers the right property
WhatsApp Cloud API + wa-send subworkflow
The lead interface. Every outbound message flows through one shared wa-send subworkflow, the single place the 24-hour window and template rules are enforced
Twenty CRM
System of record for properties, leads, viewings, and deals. Written to exclusively via its GraphQL API, never its database
PostgreSQL × 2
Twenty's own DB plus a separate n8n-owned operational DB (leads, conversations, follow-up sequences, workflow_errors). The two never cross-write
Redis
Conversation locks: a 60-second TTL with a Lua heartbeat every 15s and compare-and-set release, so burst messages never produce racing replies
Telegram bot
The agents' control plane: dictate a reply to any lead by voice note, create listings by voice, ask the pipeline questions in natural language
→AI answers, humans negotiate
Full autonomy is a trust liability in a relationship business. When a lead starts negotiating price, Ama reassures them, pings the boss instantly, and the boss replies with one Telegram voice note that lands on the lead in the agency's own voice. The AI makes the agency fast; the human closes the deal.
→Anti-fabrication as a product feature
One invented listing burns a brokerage's name permanently. Ama answers only from live inventory. Ask her for a beachfront 5-bed at an impossible price and she declines and pivots to what's real. In demos this refusal is a selling point, not a limitation.
→Two databases that never cross-write
Twenty CRM is touched only through its GraphQL API; operational data lives in a separate n8n-owned PostgreSQL database. This survives Twenty upgrades, keeps a clean audit boundary, and means a bug in one system can't corrupt the other.
→One shared wa-send subworkflow for every outbound message
WhatsApp's 24-hour window rule is the kind of policy that rots when copy-pasted across workflows. It lives in exactly one subworkflow that decides free-text vs pre-approved template. No other workflow may call Meta's API directly.
→An AI-native engineering process
The repo itself is a Claude Code harness: a project constitution with non-negotiable invariants, seven specialized subagents (architect, workflow-builder, schema-designer, tester, code-reviewer, doc-gardener, researcher), ADRs, and a rule that nothing is DONE until the tester agent returns green and the code-reviewer signs off. It's how a two-founder team ships at this scope.
Ama's system prompt is ~86,000 characters, refined over 100+ iterations: persona rules, Ghana-market knowledge, honesty rules, escalation triggers, and dozens of worked example conversations. Making her sound genuinely human was an engineering problem, not a writing problem.
Every stage of the lead lifecycle is a version-controlled n8n workflow with an explicit contract doc, and every workflow has an error branch writing to a workflow_errors table. Silent failures are treated as bugs.
// Every workflow sends through wa-send. Nobody calls Meta directly.
const hoursSinceInbound =
(Date.now() - new Date(lead.last_inbound_at)) / 36e5;
if (hoursSinceInbound < 24) {
// Inside the window: Ama replies free-form, in persona
return sendFreeText(lead.wa_id, message);
}
// Outside the window: only Meta-approved templates are legal
return sendTemplate(lead.wa_id, "property_followup", {
name: lead.first_name,
property: match.title,
});-- Burst-proofing: one reply pipeline per conversation.
-- Acquire: SET lock:conv:{lead_id} <token> NX EX 60
-- Heartbeat (every 15s): only the owner may extend
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("EXPIRE", KEYS[1], 60)
end
return 0
-- Release (on every exit path): compare-and-delete
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
end
return 0Agency owners don't open laptops. The entire back office is drivable from a Telegram bot, mostly by voice.
An AI agent talking to real customers is a production system first and an AI project second. The unglamorous engineering is what makes it trustworthy.
The Problem
Real leads don't send one tidy message. They send five short ones in ten seconds. Each webhook fired a parallel workflow execution, and with real Claude API latency, a naive flat-TTL lock expired mid-reply: the lead got multiple overlapping, contradictory answers.
The Fix
A Redis lock per conversation with a 60-second TTL, a Lua heartbeat every 15 seconds that only the lock owner can extend, and a compare-and-set release on every exit path, combined with a debounce that batches the burst into one coherent context before Ama replies once. Typing indicators keep the lead engaged while it thinks.
The Problem
Live chats kept surfacing robotic tells: 'I don't have that tagged on my end', identical greetings for every lead, database jargon like 'what's actually live'. Rules explicitly banned these phrases, yet they kept appearing, and every prompt edit risked breaking 100+ prior refinements with no token budget for regression testing.
The Fix
Built a zero-cost static audit: scripts that cross-check every example dialogue in the prompt against its own ban lists. The finding: seven 'model' example replies were teaching the exact phrases the rules banned, and exemplars beat instructions every time. Rewrote the offending exemplars into compliant phrasing, varied the duplicate greetings, and added a banned-phrase lint that runs before any new exemplar ships.
The Problem
WhatsApp forbids free-form business messages more than 24 hours after the lead's last message, which is exactly when Day-3/7/14/30 follow-ups and viewing reminders need to fire. A workflow that ignores this silently fails in production.
The Fix
All sends route through one shared wa-send subworkflow that checks the last-inbound timestamp and switches between free-form persona replies and Meta-pre-approved templates (property_followup, new_listing_alert, viewing reminders, review_request). Template approval became a tracked prerequisite in every feature plan rather than a launch-day surprise.
The platform is live in production, deployed on AWS with Twenty CRM and n8n running behind SSL, tested end-to-end over live WhatsApp and Telegram, and now being hardened for its first pilot agency.
Before → After
Lead response time
Voice notes (Twi/Pidgin)
Follow-ups
CRM data entry
New-listing marketing
Missed escalations
Business Outcome
Sold to agencies as a managed monthly service with a free 30-day pilot, positioned as revenue recovery rather than software. The live demo is the pitch: a real lead message answered in seconds on a real number, a Twi voice note understood, a negotiation escalated to the boss's pocket and closed with one voice note. Everything in the demo is real, and that honesty is the selling point.
Would Do Differently
Key Takeaways
Next Project
AI & Creative Tooling
