Every concert is also a hospitality event. Someone at the venue decides what the kitchen serves, what the bar pours, what the DJ plays between sets, which brands get a moment and where the crowd goes after the show. Almost everywhere, that decision is a guess, and it comes out the same every night: burgers, house lager and "current chart hits", whether the headliner is a jazz-pop singer or a hardcore band.

We tried the obvious fix first: we asked an LLM to plan a Laufey night. It suggested artisan sandwiches, craft mocktails and a chill DJ, which is the answer it would give for anyone, because it has no idea who Laufey's fans are. That's the gap Qloo fills. Its taste graph knows what the fans of a given artist also eat, drink, wear, listen to and where they spend time. So we set out to build an agent that turns "who are this artist's fans?" into a run sheet a venue team can act on, then does the outreach itself.

What it does

Convivium is an autonomous agent for venue and promoter teams. You connect a venue's iCal calendar once. From then on, every new or changed show triggers a run with no clicks:

  1. Observe. The agent reads the calendar every 15 minutes and fingerprints each show (title, date and lineup).
  2. Reason. It resolves the lineup in Qloo, gathers taste evidence in parallel, writes a plan, checks it against the venue's rules and rewrites it until it passes.
  3. Act. It drafts pitches to after-show partners and brands, sends the run sheet to the ops team and posts it to the team channel, each with its real delivery status.
  4. Learn. When the venue reports what sold, what flopped and who declined, the agent stores the lesson and re-plans the next shows.

Each plan covers the food, drinks (with a non-alcoholic share tuned to the audience), a DJ set between acts, brand moments, after-show partners, a fan-hotspot map for promotion and a run of show.

The comparison is built into the product. Every plan has a With Qloo / Without Qloo switch. "Without" is the same task, the same LLM and the same venue rules, but with no Qloo data. Take two real plans for the same New York venue:

  • Laufey, with Qloo: chocolate soufflé, a DJ set of ANRI and Ginger Root, Urbanears, and an after-show at Battery Gardens.
  • Turnstile, with Qloo: cauliflower wings, a DJ set of Fiddlehead and Drug Church, Dickies, and an after-show at Baby's All Right.
  • Laufey, without Qloo: "artisan mini sandwiches, craft mocktails, a chill after-show DJ".

How we built it

Qloo, about 12 calls per plan. /search resolves the headliner and support acts to Qloo entities. /v2/tags finds the place-category ids. The rest are /v2/insights calls run in parallel:

  • Artists the fans love, capped at the headliner's popularity, for the DJ set.
  • Brands, for brand moments and pitches.
  • Restaurants and bars in the city, for after-show partners.
  • Three typed tag calls: dishes, cuisines, and music genres and styles.
  • Demographics, for the audience read and the non-alcoholic share.
  • A city heatmap, for promotion.

Every call is logged as a receipt with its purpose, parameters, result count, latency and cache status. The client has a 6-hour cache and retries with backoff that respects Retry-After. One failed call shows up as an honest gap instead of sinking the run.

The agent is a LangGraph StateGraph:

resolve → gather → recall → plan ⟲ critic → finalize → act → remember → baseline

The critic checks a draft against venue rules in code: alcohol-free, dietary options, a partner cap, and past lessons such as no declined partners and no flopped items. It sends violations back to the LLM for up to 3 drafts; anything left over is fixed deterministically.

The LLM is openai/gpt-oss-120b on Groq, writing structured output into a Pydantic plan schema. There is a deterministic composer for when no LLM is available.

Grounding is enforced in code, not in the prompt. Every artist, brand and venue the plan names must cite an id from the matching Qloo pool, or it's removed. A dish or drink keeps its evidence only if a cited tag actually explains it; otherwise it's labelled as agent inference. Each plan shows its grounding share:

$$ g \;=\; \frac{\left|{\, i \in I : \operatorname{evidence}(i) \neq \varnothing \ \wedge\ \operatorname{evidence}(i) \subseteq Q \,}\right|}{|I|} $$

where $I$ is the set of plan items and $Q$ is the set of Qloo ids returned in this run. On the live Laufey plan, $g = 15/18$. On the no-Qloo version, $g = 0/8$.

Stack: FastAPI and Uvicorn, LangGraph and LangChain, Pydantic v2, async httpx, icalendar, SQLite (or Mem0) for venue memory, Resend email and Slack/Discord webhooks. The front end is vanilla JS with Leaflet. It's deployed on Fly.io as one always-on machine with a persistent volume, so it never sleeps during judging, and it has 56 offline tests built on Qloo-shaped fixtures and a fake LLM.

Challenges we ran into

  • Real Qloo responses didn't match our assumptions.
    • Tags come back with tag_id and subtype, and untyped tag calls return mostly media keywords. Every tag call is now typed.
    • Place results include closed venues and non-hospitality places, which we filter by primary genre.
    • The heatmap returns hundreds of cells across a whole region. We keep only cells within 40 km of the median of the fans' places $(\bar\varphi, \bar\lambda)$, using an equirectangular distance: $$ d \approx R\sqrt{(\Delta\varphi)^2 + (\cos\bar\varphi\,\Delta\lambda)^2},\qquad R = 6371\text{ km} $$
  • Latency on the judge path. The no-Qloo baseline ran in the same LangGraph superstep as gather, so the plan had to wait for it, and both LLM calls competed for Groq's free-tier budget of 8k tokens a minute. Moving the baseline after remember turned $$ T = t_{\text{gather}} + t_{\text{baseline}} + t_{\text{plan}} \quad\text{into}\quad T = t_{\text{gather}} + t_{\text{plan}}, $$ so a fresh live plan now appears in about 18 s, down from 39–56 s. We also cut prompt tokens by replacing Qloo ids with short references, and we pace the background demo plans one a minute.
  • LLM slop.
    • The model copied our prompt examples ("Matcha Lemonade" appeared in 4 of 5 cities), so we removed every copyable example.
    • It invented clock times for the run of show, put restaurant names into dish titles and used marketing filler. Each now has a code guard.
  • False positives in the rules. "gin" matched inside "ginger" and flagged mocktails as alcoholic, which wasted all three drafts on the alcohol-free Turnstile venue. Alcohol detection now uses whole-word matching.

Accomplishments we're proud of

  • The with/without comparison is honest and built into the product: same task, same model, same rules, and the only variable is Qloo.
  • Nothing is dressed up. Qloo-backed items are rose, inference is amber, fixture data says so, and actions show their real status.
  • It works worldwide: we tested live plans in New York, London, Mexico City, Tokyo, Berlin, Dublin and Lagos.

What we learned

  • Grounding has to live in code. Prompts ask; validators enforce.
  • Cross-domain taste is the moat. An LLM can write a menu. Only taste data tells you that Turnstile fans in New York go for Dickies and Baby's All Right, and Laufey fans for Urbanears and a café at the Asia Society.
  • Agent latency is mostly orchestration, not model speed. One misplaced parallel branch cost us more than 20 seconds.

What's next

  • Ticketing and POS integrations, so "sold well / flopped" comes in automatically instead of being reported.
  • Multi-venue tours: plan a whole tour city by city, reusing partner lessons.
  • Partner reply handling, so the agent follows up on accepted pitches by itself. ````

Built With

Share this project:

Updates

Submission history