Back to the work

TenantDesk

A help desk for rental agencies. An AI bot takes tenants' repair requests on Telegram and WhatsApp, sorts them by urgency, and hands them to agents in 12 languages.

A repair request moving through TenantDeskA tenant reports a leak in Spanish. The bot asks the model to classify it, gets back plumbing and urgent, and opens a case in Chatwoot with the photo and address. The agent is notified, books a plumber, and the reply returns to the tenant in Spanish.TenantBotAI modelChatwootAgent“Fuga en la cocina”Classify and triagePlumbing, urgentOpen case with photo and addressNew urgent casePlumber at 10:00Agent replyReply in Spanish
A repair request, drawn the way telecom engineers draw call flows.Message between systemsThe AI model decides

The problem

Small rental agencies take repair requests by phone and WhatsApp. Nothing is written down in one place, so an urgent leak and a request for a spare key look identical until somebody reads the messages, and tenants who don’t speak the agency’s language wait longer than everyone else.

What I built

A bot on Telegram and WhatsApp that collects what an agent actually needs: who is writing, which property, what is broken, and a photo. It classifies urgency, opens a case in Chatwoot, and relays the conversation both ways, translating in either direction. Agents work in one inbox instead of several phones. Around that sits a dashboard for cases, properties, tenants, analytics and billing.

A second, unrelated agent runs alongside it: a content pipeline that picks a sector topic, researches it, drafts a post, and asks for one approval on Telegram before publishing in Spanish, English and Russian at once. It keeps its own bot token and its own state machine, so a stuck draft never touches the tenant-facing bot. A longer analysis piece goes out on Tuesdays, a shorter one on Thursdays.

Architecture

The diagram above traces a single repair request end to end: from the tenant’s message, through the bot’s classification step, into Chatwoot where an agent handles it, and back out in the tenant’s own language.

Key decisions

Chatwoot instead of a custom agent inbox. Agents needed a real inbox with assignment, history and mobile apps. Building that would have taken months and been worse. The bot talks to Chatwoot’s API and the dashboard signs agents in with one click, so the parts I own stay small.

Every agency gets its own bot token and inbox. Isolation is per inbox, not per account, so a mistake in one agency’s configuration cannot show another agency’s conversations. Agent accounts are deliberately not administrators, because an administrator bypasses that isolation.

Muting a tenant is enforced twice, not stored once. A support ban has to actually stop every message to that tenant — reminders, agent replies, broadcasts — not just flip a flag an agent could accidentally clear by resolving the conversation. The gate sits both on the way in (nothing from a banned tenant reaches intake) and on the way out (every send path checks first), so no single code path can let a banned tenant slip through.

Photographs are checked before they are stored. Tenants send whatever their camera has. Uploads pass a content gate and a vision check that confirms the image is what it claims to be, and documents land in per-agency storage with a 90-day retention rule rather than sitting in the case forever.

The deploy script owns production, not me. It runs the test suite, tags the running image as the rollback target, uploads, rebuilds, and rolls back on its own if the container fails to start.

How Claude was used

I wrote the rules for the project down first and kept them current, so each session started from the same brief. Claude wrote nearly all of the code; I decided the architecture and what had to hold true before anything shipped, and the test suite — not a line-by-line read of the diff — was the gate. More on that in how I build with Claude.

Results

The test suite has grown to around 3,870 tests across five suites (unit, integration, dashboard, security, simulated tenants), and it still gates every deploy. The newest suite is the most unusual: 24 AI-played tenants, two per language (angry, vague, elderly, voice-only, a gas leak, a flood), each run a complete intake against the production models. Single-reply tests had missed conversation-level failures, such as safety advice in the wrong language and a skipped photo step; the first run passed 7 of 24, surfaced 13 bugs, and after the fixes passes 24 of 24 and blocks the deploy if that drops. The bot handles tenants in 12 languages without a human translator in the loop, eliminates overnight dispatcher interruptions through automated quiet-hour deferrals, and runs an autonomous bilingual marketing blog agent entirely isolated from tenant operations.

TenantDesk has been live since April 2026, and in May 2026 I moved the whole system off its original n8n workflows onto a plain Python codebase — same behaviour, but one codebase I can test and direct changes to, instead of following wires between workflow nodes.

What I’d do next

I want to extend what the bot can do: a voice agent a tenant can actually talk to instead of typing through Telegram or WhatsApp, and direct integrations with more CRMs and technician catalogues so a repair can be booked automatically instead of an agent doing it by hand.