Inspiration
Every gamer I know has the same problem: a backlog of twenty games and no idea which one to start. Steam's own numbers say roughly half of all purchased games are never launched. The "What next?" feature in MustPlay 1.0 picked randomly, and it worked — people liked having the decision made for them — but it had no idea why one game would fit better than another.
Agents are good at reasoning and terrible at taste. Ask an LLM what to play after Hades and you get the same five names everyone gets. What I wanted was an agent that knows what this player loves, and can say why a pick fits in words grounded in real data rather than vibes. That's exactly what Qloo's taste graph is for.
What it does
Scout lives inside MustPlay, a shipped iOS gaming bucket-list app (App Store, October 2026). It reads the games you finished and rated highly, resolves them to Qloo entities, and asks Qloo's taste graph of 250M+ entities what fits. Six things it does that only work because of Qloo:
- Pick from my pile. Ranks your own Want list against your loved games. Not "games like X" from the whole internet — the specific pile you already own, ordered by Qloo affinity, with a reason that names the shared tags and the game it connects to.
- Find me something new. Taste-grounded discovery with natural-language constraints ("short and cozy, on Switch"). Constraints become Qloo tag filters; platforms and years are filtered locally; results come back with IGDB covers and a one-tap Add to list.
- What's my taste? Qloo taste analysis over your loved games, rendered as a profile card and a shareable 1080×1920 poster with your top covers.
- Post-credits pick. Finish a game and Scout pairs it with a film or series, an artist, and a podcast or book via Qloo's cross-domain recommendations. Hades → Wolfwalkers, Kero Kero Bonito and Retronauts. No other API does this.
- Why not X? After a pick, one tap asks why another game in your pile lost. Scout re-ranks the pile and answers with the tags X shares with your taste, the tags Qloo does not associate with your loved games, and what the winner has that X lacks.
- Deep cuts. Hidden gems in your lane: the same taste signal with Qloo's popularity capped (
filter.popularity.max), so the cards are games you have probably never heard of, badged "Under the radar".
Signals are weighted: 5★ games count more than 4★, a game you're playing counts a little, and the game you just finished dominates the post-credits pairing. Games you finished but rated 1–2★ are negative signals: Scout takes the tags they carry that none of your loved games share and passes them to Qloo as filter.exclude.tags, then tells you which game taught it that ("Open World is a tag you bounced off in Elden Ring"). Every card shows "Closest to: Celeste, Hades", taken from Qloo's explainability, so the player sees which of their own games drove the suggestion.
Every reason cites tags returned by Qloo. Scout is free for all users; nothing is gated.
How I built it
- iOS (SwiftUI, SwiftData, iOS 17+):
ScoutViewchat sheet with four quick prompts and free text, streaming cards over SSE;TasteShareCardposter rendered with ImageRenderer; Qloo entity ids cached on the game model so repeat questions skip resolution. - Cloudflare Worker (TypeScript):
POST /agentruns a tool loop. The model (DeepSeek via an OpenAI-compatible API; Workers AI is a one-line fallback) gets five tools and decides the order:qloo_resolve→GET /search?types=urn:entity:videogame(normalised title match, exact-name first)qloo_recommend→POST /v2/insightswith weightedsignal.interests.entities([{id, weight}]),filter.exclude.entitiesfor the player's own library,filter.exclude.tagsfor negative signals,filter.popularity.maxfor deep cuts, optionalfilter.tags,feature.explainability=true; same-domain and cross-domain (filter.type=urn:entity:movie|tv_show|artist|book|podcast). The Worker sets the weights from ratings; the model never sees them.qloo_tags→GET /v2/tagsplus synthesised game-tag ids (urn:tag:category:qloo:<slug>) validated with a one-result insights call, because the tag search endpoint is weak for gamesqloo_taste→GET /v2/insights?filter.type=urn:tag&filter.parents.types=urn:entity:videogame&filter.tag.types=…igdb_lookup→ covers, platforms and IGDB ids for anything Qloo recommends- plus
show_games/show_taste/show_crossoverto render cards. The Worker enforces thatshow_tastecan only follow a realqloo_tastecall, that reasons come after tool results, and that no card is shown without a resolvable title.
- Guardrails: canned prompts refuse to run without seeds (no 4★+ games yet, empty Want pile) and say what to do instead; tag filters fall back to tag signals and then drop with an honest note; Qloo responses are memoised in the isolate (the Cache API counts against the 50-subrequest budget).
What Qloo made possible (and what I learned about the API)
- Coverage is excellent for games: 23 of 24 common titles resolved to an exact entity; the 24th was a diacritic.
- Game entities carry rich tag types (
category,gameplay_type,emotional_tone,audience,art_style,skill_level), which is what makes "Hand-drawn, challenging, tight controls — the same brutal, rewarding lane as Celeste and Hades" possible without the model inventing anything. - Cross-domain affinity from game seeds to films, artists and books is real and often delightful (Lore Olympus for Hades fans).
- Taste analysis needs
filter.parents.typesandfilter.tag.typesto stay on-topic; without them you get keyword noise. filter.release_yearis ignored for games (filtered locally);urn:tag:genre:media:*ids match nothing for games, so constraints are built fromurn:tag:category:qloo:*and friends.
Challenges
- Making the agent agentic without letting it hallucinate: tool outputs are the only source of tags and titles, and the Worker post-validates every card.
- Llama 3.3 on Workers AI produced thin reasons and blew through the free daily budget in an afternoon of testing; switching to DeepSeek through the same OpenAI-compatible adapter fixed both.
- The hackathon guide says
urn:entity:video_game; the API only acceptsurn:entity:videogame. Logged in the repo'sdocs/qloo-api-notes.mdwith every other verified shape.
Accomplishments
A shipped app got a genuinely new capability in two weeks, with Qloo as the differentiator rather than a decoration. The post-credits pairing is the thing people screenshot.
What's next
Scout-driven push nudges ("Three games in your pile fit your Celeste streak") and a "taste twins" mode that compares two players' pools.
What changed since September 30
MustPlay 1.0 (submitted to the App Store on 26 Sept, live 12 Oct) had no Qloo integration and no agent. Everything Scout-related was built after 12 Oct 2026 and ships in 1.1:
- Worker:
worker/src/agent.ts,qloo.ts,llm.ts,fixture.ts,env.ts;index.tsrewritten in TypeScript withPOST /agent - iOS:
Services/ScoutClient.swift,Views/ScoutView.swift,Views/TasteShareCard.swift;BucketGame.qlooEntityID; "Ask Scout" entry on the list; post-credits hand-off after completion - Docs:
docs/qloo-hackathon-plan.md,docs/qloo-api-notes.md; privacy policy and terms updated for Scout - Git history from 12 Oct onward shows the full sequence.
Testing instructions for judges
- No iPhone? Open the web demo at https://kbfox.github.io/mustplay-site/scout.html — it runs the same agent with a list you build in the browser (load a sample list, press any of the four prompts, and tick "Show raw events" to see the agent protocol).
- Install MustPlay from the App Store on an iPhone (iOS 17+): https://apps.apple.com/app/id6816116027 (free; Scout ships in 1.1.0, live since 14 Oct 2026).
- Tap + and add a few games you have finished; open each, mark Completed and rate 4–5 stars. Then add two or three games you mean to play (they stay in "Want to Play"). Two minutes is enough.
- Tap Ask Scout on the list and try all four prompts. Free text works too: "something like Hollow Knight but shorter".
- Complete any game to see the post-credits pairing.
No account or sign-in. Scout is free. Each answer takes 5–15 seconds.
Curl access for judges who prefer the API (same Worker the app uses; a request body example is in the README):
curl -N -X POST https://mustplay-igdb.kbfoxtk.workers.dev/agent \
-H 'content-type: application/json' \
--data '{"intent":"pick","messages":[{"role":"user","content":"What next?"}],
"library":[{"igdb_id":1,"name":"Hades","status":"completed","rating":5},
{"igdb_id":2,"name":"Celeste","status":"completed","rating":5},
{"igdb_id":3,"name":"Dead Cells","status":"wantToPlay"},
{"igdb_id":4,"name":"Unpacking","status":"wantToPlay"}]}'
Built With
- cloudflare-workers
- deepseek
- igdb
- qloo
- revenuecat
- swift
- swiftdata
- swiftui
- typescript
Log in or sign up for Devpost to join the conversation.