Inspiration
Every music festival promoter operates under strict constraints: a fixed talent budget, a venue capacity limit, and a lineup to fill. Yet the traditional booking process is almost entirely greedy and intuitive: Who is trending? Who is available? Can we afford their quote?
Booking acts independently creates a massive hidden failure mode: audience cannibalization. When a promoter books several hot indie-folk or electronic acts in silos, those acts often pull from the exact same demographic pool. The festival might pay for 40,000 theoretical tickets across 8 artists, but only 12,000 distinct fans actually attend. The promoter pays three times to reach the exact same crowd.
We asked: what if a festival lineup was treated like an investment portfolio?
In portfolio theory, you never hold ten assets with identical correlations and call your portfolio diversified. Every artist is a position buying exposure to a distinct cultural taste cluster. Two acts with high similarity are correlated holdings. We built CrowdFolio to transform festival booking from a guessing game into a mathematically optimal, budget-constrained portfolio selection problem.
The core analogy at a glance:
| Portfolio theory | CrowdFolio equivalent |
|---|---|
| Asset / position | An artist booking |
| Capital budget | Talent budget |
| Correlated holdings | Artists with high taste overlap |
| Diversification | Reaching distinct taste clusters |
| Return | Modeled unique fans reached |
| Efficient frontier | Best lineup at every budget level |
What it does
CrowdFolio is an agentic, budget-constrained festival lineup optimizer grounded in Qloo's cultural taste graph. Tagline: "Lineups are portfolios."
Given a target market (e.g. Austin, New York, Tokyo), a venue capacity ceiling, an overall talent budget, and seed artists, it works in four steps:
- Builds a Cultural Universe: resolves artists through Qloo and pulls 50-neighbor affinity projections weighted by hyperlocal DMA draw indices.
- Computes Taste Overlap: constructs a pairwise cosine similarity matrix across affinity vectors to quantify cultural covariance between candidates.
- Solves the Portfolio: runs a deterministic, submodular max-coverage solver paired with 1-swap local search to maximize distinct demand reached per talent dollar.
- Delivers Mathematical Receipts: every booked slot features an unvarnished audit receipt with modeled unique fans added, taste overlap against already-selected acts, fee estimates, and Qloo's explainability attribution.
How the pipeline flows:
Promoter brief Qloo taste graph Deterministic solver
(market, budget, ---> (entity resolution, ---> (submodular greedy +
capacity, seeds) 50-neighbor affinity, 1-swap local search)
DMA geo-weights) |
v
Audit receipts <--- Lineup + analysis <--- Overlap matrix (cosine)
(per-slot proof) (frontier, robustness,
Monte Carlo)
Side-by-side results
CrowdFolio evaluates the optimized lineup against a traditional naive booking baseline at identical spend. On an Austin $250,000 brief:
| Metric | Naive baseline | CrowdFolio | Change |
|---|---|---|---|
| Modeled unique demand (attendees) | 8,940 | 13,019 | +45.6% |
| Average taste overlap | 10.0% | 0.0% | -10.0 points |
| Capital efficiency (unique fans per dollar) | baseline | optimized | +30.2% |
| Talent spend | $250,000 | $250,000 | unchanged |
How to read the graphs below: each bar is drawn to scale within its own chart, so a longer bar means a larger value. Compare the two bars in each chart to see the improvement.
Graph 1: Modeled unique demand (higher is better)
Naive baseline |###################### 8,940
CrowdFolio |################################ 13,019 (+45.6%)
+--------------------------------
Graph 2: Average taste overlap between booked acts (lower is better)
Naive baseline |########## 10.0%
CrowdFolio | 0.0% (no shared taste pool)
+----------
Graph 3: Why overlap wastes money (illustrative example from the story above)
Tickets "paid for" |######################################## 40,000
Distinct fans |############ 12,000
+----------------------------------------
The gap is audience cannibalization.
Agentic controls and deep analysis
| Feature | What it does | Why it matters |
|---|---|---|
| Efficient Frontier | Sweeps budgets from 40% to 120% in 12 discrete steps in under 50ms | Shows the best lineup at every spend level, so the budget slider can be scrubbed live |
| Robustness analysis | Re-solves across 20 fee-perturbed runs (±25%) | Classifies each slot as stable or swappable |
| Monte Carlo uncertainty | Simulates demand outcomes | Reports p10 / p50 / p90 demand bands instead of one false-precision number |
| Natural Language Parsing | Parses promoter briefs into hard constraints | Accepts requests like the example below |
An example promoter brief the agent can parse:
lock in Mitski, cap electronic acts at 2, and add at least 2 local Texas artists
How to read the Monte Carlo bands:
p10 ---------- p50 ---------- p90
| | |
pessimistic median optimistic
(9 in 10 runs (typical (only 1 in 10 runs
do better) outcome) does better)
How we built it
CrowdFolio is built with a zero-compromise architectural contract.
| Layer | Technology | Role |
|---|---|---|
| Data layer | Qloo Insights API | Structural backbone of the objective function |
| Solver | Pure TypeScript, no math libraries | Submodular greedy selection plus local search |
| Agent layer | LLM agent | Parses promoter constraints and narrates receipts |
| Frontend | Next.js 15 (App Router), Tailwind CSS, WebGL fluid shaders, SVG/Canvas taste matrices | Interactive visuals |
| Infrastructure | Upstash Redis (7-day TTL cache), Zod validation, Vercel | Speed, safety, deployment |
Data layer details:
/searchfor entity resolution/v2/insightswithsignal.interests.entitiesfor 512-dimensional vector projectionsfilter.location.queryfor DMA geo-weightssrc/lib/qloo/client.tsis the sole, strictly-validated network gateway
Pure deterministic solver: uses submodular greedy selection and local search with deterministic tie-breaking by Qloo entityId, ensuring byte-identical outputs for identical inputs.
Zero-hallucination invariant: the LLM never generates or modifies a numerical figure. Every metric rendered comes directly from Qloo or the deterministic solver.
Data flow of trust:
Numbers: Qloo --> Solver --> UI (always)
Language: LLM --> narration only (never a figure)
Challenges we ran into
| Challenge | What went wrong | How we solved it |
|---|---|---|
| The Scale-Invariance Trap | Talent fees were a function of the active budget slider, so moving the slider scaled all fees proportionally and never changed the optimal lineup | Anchored fees to a fixed market reference capacity, B_ref = CAP x $50, so the slider genuinely restructures the roster |
| Cultural embeddings vs. raw noise | Niche and local artists have sparser data in cultural graphs | Added an affinity floor of 0.15 and local market geo-weighting so zero-overlap lineups stay coherent instead of drifting into unrelated genres |
| Recursive solver pitfalls | Monte Carlo and fee-perturbation sweeps risked recursive execution overhead | Added explicit analysis-skip flags and PRNG seeds, guaranteeing complete sweeps in under 45ms |
| Honest vocabulary | Easy to confuse taste overlap with audience overlap | Enforced a strict invariant across code, UI, and docs (see below) |
Honest vocabulary, defined:
| Term | What it actually measures | Source |
|---|---|---|
| Taste overlap | Cosine similarity of embeddings in Qloo's taste space | Qloo (modeled) |
| Audience overlap | Real fans shared between artists | Ticket scanner telemetry (not used) |
All modeled figures are labeled as modeled.
Accomplishments that we're proud of
- Proven economic value: a validated +45.6% modeled unique demand uplift and +30.2% capital efficiency gain (unique fans per dollar spent) on benchmark festival runs, without increasing talent spend.
- Sub-50ms execution: fast optimization of a complex combinatorial graph problem, allowing live budget scrubbing on the frontend.
- 100% grounded agent architecture: an AI tool that promoters and finance executives can actually trust, with zero hallucinated figures, transparent attribution, and reproducible receipts.
- Complete test suite: 38 Vitest suites covering model invariants, edge cases, deterministic tie-breakers, and scenario persistence, with zero typecheck errors in TypeScript strict mode.
Speed and quality at a glance:
| Measure | Result |
|---|---|
| Efficient frontier sweep (12 budget steps) | under 50ms |
| Robustness and Monte Carlo sweeps | under 45ms |
| Test suites | 38 |
| TypeScript strict-mode errors | 0 |
| Hallucinated figures | 0 |
What we learned
- Constraints define the problem: a budget slider that merely rescales everything is not a real constraint. Anchoring fees to a fixed reference made the trade-offs real.
- Determinism builds trust: byte-identical outputs for identical inputs make every receipt reproducible and auditable.
- Keep the LLM out of the math: let the model parse intent and narrate, and let Qloo and the solver own every number.
- Label modeled data honestly: distinguishing taste overlap from audience overlap protects credibility with finance-minded users.
- Sparse data needs guardrails: an affinity floor and geo-weighting keep niche and local artists from adding noise.
What's next for CrowdFolio
| Next step | Description |
|---|---|
| Multi-stage conflict minimization | Expand the stage and day allocation algorithm to automatically separate artists with correlated fanbases across time slots, preventing crowd bottlenecks at concurrent sets |
| Full venue season scheduling | Adapt the portfolio solver from single weekend festivals to 30/60/90-day venue residency calendars, so performing arts centers and clubs avoid booking competing acts on adjacent weekends |
| Sponsorship affinity matching | Overlay festival lineup taste graphs with corporate sponsor profiles (beverage, automotive, fashion) to identify high-affinity brand partnerships backed by vector proof |
Roadmap:
Today Next Later
Single-festival --> Multi-stage / multi-day --> Season-long venue
lineup optimizer conflict minimization scheduling + sponsor
affinity matching
Built With
- next.js-15
- nextjs
- qloo
- qloo-insights-api
- tailwind-css
- typescript
- upstash-redis
- vitest
- webgl
- zod
Log in or sign up for Devpost to join the conversation.