How a safari lodge runs on AI day to day, and the times it embarrassed us
When a guest messages the lodge at three in the morning, someone answers, and in July we found out exactly how fast. We pulled every WhatsApp message the lodge had sent or received since March, about 19,000 of them across 721 chats: the median time to a first reply was four minutes, and there's a reply in that pile sent at 02:58, two minutes after the question. One guest put it as "everywhere else we went it was impossible to communicate with anyone on the ground."
That speed was entirely manual. Three of us, phones in hand, all day and most of the night. And the same analysis showed it breaking: median first reply was 2 minutes in May, 6 in June, 13 in the first week of July, as high season arrived and the same three people took on another fifteen or so messages a day on top of everything else the season brings. A quote once stalled for a week because the person holding the thread got sick.
I build software for a living alongside the lodge, so the obvious question was what a model could take off our plates without making us worse. What follows is what runs today, in roughly the order it reaches a guest, and the places it has gone wrong.
The chat on the website
Open marahilltop.com and there's a chat in the corner called Ranger. It answers around the clock, and it can do things: check real availability for your dates, quote a stay from the same rate table our front desk uses, hold a room as a tentative booking, and leave your details for the team. It cannot confirm, cancel or discount anything, and it can't see other guests' data. Guests with a booking get a second version of it, tied to their reservation, which can also take a dinner order or put a game drive on their bill.
The rule that keeps its prices straight is boring: every room price it states has to come from a price lookup for real dates made in that same conversation. It's not allowed to remember a price from earlier, or from the knowledge base, or to add two numbers together. If you ask for "early October" it quotes the 5th and says so. If you're travelling with children it asks their ages before quoting, because age decides who's charged. If a tool result and the knowledge base disagree, the tool wins.
It had no rule against agreeing to things it couldn't do. In July a guest booked through this chat and asked it to note that she'd like to upgrade to a luxury tent if one freed up. Her words: "If a better accomodation get free such as luxury tent I would consider the upgrade. Please add this note." Its reply: "Noted! I've flagged your reservation with this request." When I pulled the transcript, the tool log was empty. It had no tool that could flag anything, and it did the same with her WhatsApp number a few lines later. My first instinct was to switch to a smarter model. But there wasn't a single error on the tools it did have, and a different model can't call a tool that doesn't exist. The fix was a rule rather than a tool: anything it says it has noted has to be written into the lead or the booking it created in that conversation, through the two tools it does have, and if it isn't written anywhere it doesn't say "noted". The dedicated note-for-staff tool I wanted is still on the list.
The guest chat had its best and worst minute in late August. A guest sent both IDs through it before arriving, then booked a $300 full-day game drive himself by tapping the booking card in the chat, with no staff involved until the confirmation landed in our team's Telegram group. That's the thing working. Thirty seconds later he typed "just send booking for full day game drive" to double-check, and the bot, which couldn't see the booking it had just made, told him to tap and submit again. He didn't. If he had, we'd have charged him twice. The fix, checking his reservation before telling anyone to book, is written, reviewed, and sitting in a pull request I haven't merged.
The quieter failure I only found by asking whether anyone used the website chat at all. Its first three months: 134 real conversations, twenty-four of which reached a full quote with dates and prices, four people who left any way to reach them, one confirmed booking. Three leads it had captured had sat untouched since the day they were created, which was on us, not the bot. The bot only asked for contact details if you said the word "book", so we changed that in July, and in late August someone still spent ten minutes building a full January package, correct to the dollar, and left without a name, email or phone. It had put "send me this package by email" among the suggestion chips once, early, and a chip is not an ask; it never put the question in the reply itself, even at the exact moment its own instructions say to. The rule existed and the model still missed it, so the fix that time was a worked example in the prompt, and it's waiting to ship too.
The trip planner

The newest of them is a planner at marahilltop.com/en/plan that turns "six days, two of us, August, first safari" into a day-by-day itinerary with a route map and an itemised price, with park fees listed separately because you pay those at the gate. The model in it is not allowed to compute or state a price; a deterministic engine prices every line from contracted tariffs. The page promises that a person confirms the quote within two hours, between 7am and 10pm, and that promise is ours to keep.

On launch day it priced a competitor's lodge on our own website, because it only quotes lodges with a contract rate card in its store, and our own lodge, the one whose live rates we hold, was the one property not in it. Two days later I found that a real family had planned a twelve-day trip on that same launch day, with five Mara nights at somebody else's camp, $9,878 and the other lodge's name printed on the card. The planner gets a post of its own.
The inbox that reads everything
This is the piece nobody sees and the one that changed our days most. Every WhatsApp message to the lodge number and every email to hello@ lands in the inbox of KaribuKit, the property system we built and run the lodge on, normally within five minutes. A model reads each thread as it grows, writes a one-sentence summary, and tags whether we owe a reply and what the thread needs next: a quote, a transfer time, a payment link, a voucher.
The reply is a separate step, and a person is in it. One of us opens an assistant that can read the thread and the live rate card, and it writes the draft in our voice from a playbook we built out of 682 real conversations. Then we read it, and either send it or rewrite it. The model's job is to make sure nothing sits unseen and that every price and policy in a draft comes out of the system rather than out of anyone's memory. The warmth and the judgement calls stay with us.
The July analysis is what made this urgent, and its findings were not flattering. About one in five lead conversations was us doing free travel-agency work, building multi-city itineraries and scouting other people's hotels, hundreds of messages at a time. One in six touched payment friction: a link sent late, a deposit chased after it had already been paid, bank details re-typed per booking. And the lodge contradicted itself constantly. Our cancellation policy had been quoted four different ways in one batch of chats. Two activity price lists were circulating at once, and a staff member pasted the stale one into a guest group in July. A full-day game drive had been quoted at five different prices across overlapping weeks. Guests kept screenshots of the older price, and won.
So the first AI project was one price sheet and one policy document, no chatbot anywhere in it, and a rule that the model drafts from those and only those. The inbox did flag, one Monday in August, that we'd promised a guest the contact for the driver meeting her at the airstrip that morning and nobody had sent it. The summary said so in plain words. At half past nine it still hadn't been sent, and she landed at three. The single sheet hasn't fully held, either: in September the October rate was still turning up three different ways, in the system, in the planner's rate card, and in a quote we'd sent a fortnight earlier.
In the six weeks since the inbox went live, the feed has died quietly twice, once in August on my own laptop and once in September on the server, for forty-one hours in high season, while the health check reported everything fine because email was still flowing through the same process. When it reconnected, twenty-odd threads backfilled, including a guest asking about a second debit after she'd already paid. The check that would have caught it is a simple one, the age of the newest real WhatsApp message, and it has been on my list since 9 August. It's still there.
Proposals from one sentence
For multi-lodge trips, the kind that used to eat an evening of hand-typed arithmetic with the occasional mistake in it (I have found "340 × 2 = 640" in our own sent messages), any of us can now type something like "build a proposal for the family of four, three nights with us plus two at a partner lodge in Naivasha, full board, mid-August" into a chat, and get back a branded proposal with a day-by-day itinerary, our own live room rates, the partner lodge priced from its signed contract rate, and a share link. Nobody, human or model, types a partner price by hand any more; the engine fetches it from the rate card. If a partner's rate card has expired, the proposal refuses to send until someone re-quotes that lodge. Sending still waits for a person to say go.
The back office, through a chat window
KaribuKit exposes about ninety operations to a model, with scoped keys for who may do what, and I reach for it before any screen we've built. Two examples from this summer. In July I had it set all of 2027's room rates across every season in one afternoon, about a hundred writes, by telling it which mistakes were cheap ("as long as it's not crazy pricing like $100 for the Lux room") instead of approving each row. Along the way it found that 21 December to 10 January, our most expensive three weeks, had no luxury-tent price override at all and was quietly selling at $320 a night instead of $340. A missing override doesn't error. It just charges the wrong number.
The same week it unwound a double booking, two groups created for the same party, with the one real $1,760 bank transfer on one of them and a duplicate cash entry for the same money keyed onto the other. I said "fix it from the database" twice. It declined both times and used the reversal path instead, so there's an audit trail and the tax system isn't lied to. I'd rather be argued with than agreed with on money.
The writing, including this
Every post on this blog, this one included, is drafted with AI and, since late May, handed to a second model whose only job is to argue with the first against our tone guide and our own records. In July the critic caught a fabricated statistic, a wrong Tourism Fund penalty figure and a claim that high season was "full" when it had just started, all before I read the drafts. The one that still bothers me predates it: a post published in April said, in my voice, that my parents had lived in Nairobi for most of my childhood. They've been here almost seventeen years; I visited constantly and moved here properly only recently. It was wrong for nearly five months in eight languages, and the wrong version had become the source the next draft was written from. There is now a rule about biographical claims. The gate doesn't catch everything either. The first version of this post went out with more than a dozen claims that had drifted from the records behind them, most of them fixes I'd described as finished when they were still plans, and two rounds of review caught them after it was already live.
Who may do what
Here is the division of labour.
| Where | A model does this on its own | A person does this |
|---|---|---|
| Website chat (visitors) | Answers, checks availability, quotes real dates, holds a room as tentative, saves your details for the team | Confirms, cancels, discounts, takes any payment |
| Guest chat (booked guests) | Answers, takes a food order, puts an activity on the bill | Changes dates or rooms, refunds |
| WhatsApp and email | Reads, summarises, tags, flags what we owe | Drafts with an assistant, then every send |
| Proposals | Builds the itinerary and prices every line from rate cards | Says go before it reaches the guest |
| Trip planner | Builds the itinerary; the pricing engine sets every number | Confirms every quote, inside the two hours the page promises |
| Back office | Reads what its key allows; writes rates, bookings and reversals when a staff member asks, on that person's key, with an audit trail | Gives the instruction, checks the result |
| This blog | Drafts and critiques | Publishes |
The model that reads inbound email and WhatsApp has no tools and can only return a fixed summary, and the assistant that drafts a reply only ever writes into the drafts folder. Access is read-only by default: write access is granted one scope at a time, on a key that says who may do what.
The number I'm watching is the one this started with. Thirteen minutes to a first reply in the first week of high season, with three people. Thirteen minutes is what it costs to have three people and a phone as the whole system. Next July will show what it costs with the models in it, and I'll publish that number whichever way it goes.
— NJ, Mara Hilltop