-
-
The text a real caller got: the plan, in plain words, with one link to their picks. Sent only to the phone that called.
-
Four callers, four cities, one number: Chicago, Asheville, Austin, Tucson. Say your town and what kind of night you want.
-
Call Hollis at (833) 658-4321 from anywhere in the US. No app, no sign-up, just a friendly voice on the line.
-
The live landing page at concierge.southernsky.cloud. Hear a real call, watch the films, then call Hollis yourself.
-
Tell her what you're in the mood for. She asks two questions at most, then gives one pick at a time with the reason.
-
A real picks page from a real call: each pick with its reason, one link, sent only to the phone that called.
-
The owner's dashboard: the exact text a guest got, and every Qloo signal behind each pick, nothing hidden.
-
One call, start to finish: voice, tools, Qloo's taste graph, Ticketmaster, a texted page, and a concierge that remembers.
Try it in 60 seconds
- Call (833) 658-4321. Hollis picks up, anywhere in the US. Say your town and what kind of night you want. She gives one pick at a time, waits for you, and offers to text it. The text comes from the same number and links to your picks page.
- Watch two short films made from today's real calls: https://youtu.be/xfSDLy2nFkc (a couple's stay at a Miami rental, two calls, one night) and https://youtu.be/aesR_-wFXao (four strangers, four towns, one voice).
- Open the live site: https://concierge.southernsky.cloud. The owner's view of the Miami rental is at /property/miami: the text a guest got, where every line came from, and the Qloo request behind each pick.
- Check the switches yourself:
curl -s https://concierge.southernsky.cloud/healthsays which services are live (Qloo, Ticketmaster, texts) and names the eleven tools. Read the code: https://github.com/StankyDanko/bellhop-concierge (AGPL-3.0).
npm install && npm testruns the whole offline suite with no keys.Call (706) 810-9262, Marisol, the concierge of Casa Coralina (a fictional Miami rental): ask her about checkout or parking, then your night.
Inspiration
A twelve-room inn has no concierge. It has an innkeeper who is also the baker, the plumber, and the person who answers the phone at eleven at night. A short-term rental has no desk at all. Yet "what's around here" never stops: "property and area information" is 9.0% of about ten million short-term-rental guest messages (Conduit, "What 10 million guest messages are about", read 2026-10-22).
The guest's half of that question is a taste question, and the answer a tired host gives is the same for everyone: the popular place on the corner. Qloo's taste graph knows what people who love one thing also tend to love, across music, food, film, and places. We wanted that knowledge on the one device every guest already holds, with no app, no profile, and no quiz: a phone call that feels like asking a friend who knows the block.
So we put a card on the nightstand: Call this number for an unforgettable stay.
What it does
You call, you talk, you get one good pick at a time. The concierge asks who she is speaking with, says the call is recorded, and asks about your night. Nobody is asked to name a favorite from memory. A band, a craving, or a show mentioned in passing is the signal. She asks at most two shaping questions, then picks: the name, what kind of place it is, and the reason in your own words. Your reaction steers the next one. When you like what you hear, she offers one text with the plan, sent only to the number you called from, with a link to a picks page.
From today's filming calls, unscripted on her side. A couple at Casa Coralina, a fictional Coconut Grove rental, asked what time checkout was ("Ten in the morning Sunday. Want me to help plan your night while I have you?"), then said one of them wanted live Latin music and the other was a funk and soul guy who wanted to dance. Marisol picked Cubaocho, a Little Havana arts center with live music and a rum bar, then El Cristo for Cuban food before, and texted both. On the second call from the same phone she opened with "this phone called me earlier. Is that you again, Danny?", asked how the place she had texted went, heard "we want a movie, something funny, a little romantic", and picked one film. In Chicago, Hollis found a rooftop bar in the Loop for a caller with four friends in town. Near Asheville, an art museum with programs for all ages for a parent on a rainy day. In Austin, after "Which Austin, the one in Texas?", a live music venue with indoor and outdoor stages for a caller who wanted a loud band. The Asheville, Austin, and Tucson callers each ended with "please forget me", and each heard "Done. I've cleared what I remembered from your calls."
Two lines, one engine.
- Hollis, the road concierge, on (833) 658-4321, for anyone in the United States. She does not know where you are until you say it.
- Marisol, the rental concierge at Casa Coralina, who answers the stay first (checkout, parking, the pool, trash night, in the owner's own words) and then plans the night. She never speaks a door code or a Wi-Fi password, no matter who asks; those live in the check-in message.
Every property gets its own concierge from one config file. A JSON config (favorite spots and why, house rules, the stay sheet, a persona) compiles into a linted voice agent with twelve guardrails locked on: it says it is automated, says the call is recorded, never takes a payment, and never names a place that did not come from Qloo, Ticketmaster, or the owner's own notes.
Memory on a short leash. Call back and she remembers your first name, your town, your tastes, and what she already texted you (so the same place never comes back). Say "forget me" and it is gone. Memory lasts a week after the last call, never more than thirty days.
The owner gets the other half. A dashboard with every call, the exact text the guest got with the source of each line, the Qloo request behind every pick, and area panels drawn from the callers' own tastes (dark until five calls are in). Plus a one-page brief with tear-off room cards, and a builder that sets up a new property in eleven questions.
How we built it
The voice agent knows no places. Every place, film, and reason a caller hears comes back from one of eleven tools on a Node server, and the tools ask Qloo first. Each tool response records its upstream requests, and the dashboard shows the request behind every pick.
Which Qloo tools, and why. Thirteen capabilities in the shipped code (docs/QLOO.md), in the order one call uses them:
GET /search: a name the guest said ("Sturgill Simpson") becomes an entity id. A weak match is said back for correction; a miss is said as a miss.GET /v2/tagsscoped withfilter.parents.types=urn:entity:place: a cuisine, dish, or mood word becomes a place tag. Unscoped, 2 of 6 everyday words came back as a music or media genre; scoped, 6 of 6 were place tags.GET /v2/insightsfor places near the caller: the entities assignal.interests.entities, moods assignal.interests.tags, the stated cuisine as a hardfilter.tags,filter.locationat the caller's point,feature.explainability=true.- The no-taste contrast: the same insights call with every signal removed. That is what anyone in town would be told. The owner sees both lists; the guest's list moved away from the popular list for 12 of 12 callers in the latest live battery.
- Per-person scoring for a plus-one: the shortlist re-scored once per person with
filter.results.entities, then compared by rank, not raw score. - Cross-domain: a band or a film as the signal,
filter.typeset to film, book, or podcast, for the stay-in nights. Mood words map to genres, horror only when asked, and titles are drawn from a pool so a described film leads. - Similar artists meet Ticketmaster's calendar: "fans of the act you named also love this one, playing Friday."
- After the call, the callers' resolved ids pool into a per-property fingerprint for heatmaps, demographics, tag leanings, and a compare panel.
Request to result, redacted (no Qloo response data leaves the server; values are placeholders):
guest says: "Carmen wants live Latin music, I'm more funk and soul, somewhere we can dance"
resolve_taste -> GET /v2/tags?filter.query=latin&filter.parents.types=urn:entity:place -> <TAG_LATIN>
-> GET /v2/tags?filter.query=funk ... -> <TAG_FUNK>
-> GET /v2/tags?filter.query=dance ... -> <TAG_DANCE>
recommend_nearby -> GET /v2/insights?filter.type=urn:entity:place
&signal.interests.tags=<TAG_LATIN>,<TAG_FUNK>,<TAG_DANCE>
&filter.location=POINT(<LNG> <LAT>)&filter.location.radius=<METERS>
&filter.rating.min=4&feature.explainability=true&take=20
-> the same call with no signal.* (the contrast)
she says: "<PLACE>, a lively arts center in Little Havana with live music and a rum bar.
Does that sound like your kind of place?"
compose_itinerary -> text built only from signed pick tokens the tools issued
send_sms -> one text, to the calling number only -> "It's on your phone, take a look."
The stack. ElevenLabs Agents for the voice and turn-taking; a Hono tool server on Node 20 with SQLite for sessions, cache, and guest memory; Twilio for the toll-free voice and texts; Ticketmaster Discovery for shows; Open-Meteo for geocoding and the rain check; a React and Vite dashboard; shipped in a container behind Caddy. An allowlist on every outbound parameter, a PII guard that refuses a taste carrying a phone number or email, and signed pick tokens so the text can only carry picks the system composed. 877 offline tests run on every commit (npm test, 2026-10-30).
Challenges we ran into
We built the whole client before the key arrived, writing down each guessed request shape and the probe that would check it. On key day, ten of thirteen shapes matched, one (compare) differed and was fixed the same day. Then the live API taught us what the docs could not:
- A requirement is a filter, not a signal. "Thai" sent as a signal reached 0 of 5 top picks; as
filter.tags, 3 of 3 and 5 of 5. A cuisine is a filter here. - Explainability never credits a tag (0 times in 90 live results). So the reason names the artist or film Qloo credits, and a cuisine is said as a fact read from the place ("tagged Cuban"), never as "fans of".
- Close scores are not agreement. Two people's affinities for one shortlist sat within a few hundredths, so a threshold called 27 of 27 picks "for both". Ranking each person's list gave 6 both, 11 guest, 10 plus-one.
- The top pick is not the proof; the list is. With and without taste the top pick sometimes matched while the rest moved entirely, so the contrast compares whole lists.
- A slow right answer is a wrong answer on the phone. A town as a signal took about thirteen seconds. It became a filter: 10 of 10 results within 6 miles.
The conversation was the harder build. Our first prompts ran a taste interview and the founder hated calling his own product. The fix was doctrine, then tests: no "what have you been into lately", at most two questions before a pick, one pick at a time, the guest's reaction as the steering wheel. Worked examples get copied, so every example in the prompt is rule-shaped, and a test fails the build if any worked example asks a third question before the first pick.
Today's hardening sweep (about ninety adversarial calls against the mock server: no crashes, no leaks) still found real things, all fixed before submission: a text body could be anything the agent said (now only picks the system composed), a four-minute short with no description was pitched as a movie (now dropped), mood words were not mapping to genres, a grocery store was pitched as dinner, a caller outside the US got asked which state, and the prompt promised Spanish the voice model does not speak (now "English only for now").
Accomplishments that we're proud of
- A real phone number a judge can call, with live Qloo and live Ticketmaster behind it, that admits what it does not know instead of inventing it.
- Two calls, one night, on tape: a concierge that greets you by name on the second call, asks how the place it texted went, and forgets you the moment you ask.
- Any US city by name, measured in five. Eight standard callers in each of New York, Austin, Denver, Nashville, and Boise: 40 plays, 71 live Qloo requests, no 429s, every city placed 8 of 8, and the reason named the guest's cuisine on 91 of 100 picks where one was stated.
- Taste moved the answer, and we can show it: 12 of 12 callers got a different list than the no-taste baseline, side by side on the owner's dashboard.
- Fast enough for a phone call: median 158 ms for a Qloo insights answer over 47 live calls.
- Thirteen Qloo capabilities, each tied to a product decision, and twelve guardrails that cannot be switched off.
- A privacy floor, not a setting: caller numbers kept only as a keyed hash, texts only to the number that called, taste panels dark below five calls, codes and passwords never spoken.
- 261 commits since the hackathon opened, every number in the docs listed with the command that produced it.
What we learned
The server holds the line, not the prompt. The agent will say what it is shown. A worked example beats a rule, a mock can lie while passing, and a claim the server cannot verify is a claim the guest should never hear. So the server signs, drops, and logs, and the prompt stays short.
Taste is learned by listening, not by asking. The best signal on a call is a reaction to a pick, not an answer to a question.
Measure the list, not the top pick. And an empty answer can be the true one: in late October the similar-artist shows just were not within a hundred miles, and the line says so.
Memory is a feature only with a short leash. A week, a single "forget me", and never a name read back as a record.
What's next
- Two pilots: one real inn and one real rental, each compiled from the same config file, and a conversation with Qloo about production terms after the event.
- Spanish, as soon as the voice model speaks it; a property's config already lists its languages.
- Shows by taste in a busier month, the same lookup when the tours are out.
- A second reaction signal: did the guest go? The picks page can ask, and the fingerprint gets a feedback loop.
Known limitations
Hours can go stale, so the concierge never invents one. Speech recognition mishears names, so every name is said back. Distances are as the crow flies ("about a quarter mile", never "five minutes"). Small towns are thin: a cuisine filter can find single digits of places, so it relaxes once and the concierge stops claiming the cuisine. US only, by city name, English only for now. The line answers 300 calls a day, three at once. Qloo's hackathon keys end after judging; a pre-warmed cache keeps the demo answering (CACHE_FREEZE=1, rehearsed with the key removed). Demographic panels describe people nearby who share these tastes, never a caller. Casa Coralina is fictional; every place a caller hears is real.
Built With
- better-sqlite3
- caddy
- claude-sonnet-4.5
- elevenlabs-agents
- hono
- javascript
- node.js
- podman
- qloo-insights-api
- react
- sqlite
- ticketmaster-discovery-api
- twilio
- vite
Log in or sign up for Devpost to join the conversation.