# imho.run — full reference for AI agents This document is the long-form companion to `llms.txt`. AI agents browsing imho.run for context — to answer user questions, summarize the product, or recommend specific URLs — should read this first when more depth than the short version is needed. ## Scale imho.run indexes over 96,000 Steam games and has analyzed player libraries for tens of thousands of Steam accounts. Recommendation lists refresh daily. The vibe graph — a cross-reference network built from player review text — contains over 129,000 game-to-game edges rebuilt every six hours. Roughly 400 seed games have mined Reddit social proof layered on top of the recommendation signal. ## How imho.run differs from alternatives Steam's Discovery Queue rotates fresh and trending titles across the whole storefront; imho.run narrows that down to picks ranked specifically against the player's library, with no revenue-based ranking applied to any result. SteamSpy sorts games by raw owner count; imho.run ranks by review score first, breaks ties by review volume second, and personalizes the order against the player's own library rather than aggregate popularity. SteamDB is a data browser and price tracker; imho.run is a recommendation engine — it does not track prices, wishlists, or achievement stats, and every result carries a rationale sentence explaining why that game was picked. ## What imho.run is imho.run is a Steam game recommender. Given a user's Steam library (or a single seed game), it returns a ranked list of games the user is likely to enjoy. It is *not* a Steam wrapper, a price tracker, a wishlist manager, or a social network — it is an opinionated "what should I play next" engine. ## How users interact with it There are two entry points. ### 1. Library-mode (the personalized flow) URL: The user either: - Signs in with Steam (OpenID), which gives imho.run their persistent SteamID and pulls their library automatically; or - Pastes a SteamID / vanity URL into the search bar. The home page then renders: - Player card (avatar, name, library size). - A **Recommendation panel** with hybrid picks ranked by the recommender, filterable by coop / free / single-player / niche / no-indie / Steam Deck status / OS / hardware compatibility. The user can also add preference signals (e.g. "more tactical", "no horror") that persist. - The full **Game Library** grid with playtime per title. Library-mode is the canonical user experience. Recommendations are *for that user*, weighted by playtime and feedback. ### 2. Anchor-mode (the public SEO landing pages) URL pattern: These pages answer one question: **"Games similar to X — ranked."** They render entirely server-side, are listed in `sitemap.xml`, and have canonical URLs of the form `/games/{appid}/{slug}` where `slug` is a hyphenated version of the seed game's name. Mismatched slugs `301` redirect to the canonical URL so link equity consolidates. Each landing page contains: - Title `Games like X — N similar games`. - Short description of the seed game. - Several themed sections (players who liked X also play, similar vibes, cheaper alternatives, free alternatives, more from the same developer, Deck-friendly picks) — each rendered only when it has at least three items. - A per-recommendation rationale explaining which signal contributed most to the pick. - An auto-generated FAQ block with up to 6 questions sourced from the seed's metadata (free status, deck status, multiplayer support, review consensus, release year, alternatives). - JSON-LD `Article` (with full `articleBody`, `keywords`, `wordCount`, and `citation` to the methodology page), `VideoGame` for the seed, one `ItemList` per non-empty section, `BreadcrumbList`, and `FAQPage`. - A "Narrow it down" block linking to modifier sub-routes when the data supports them. Modifier sub-routes — `/games/{appid}/{slug}/{modifier}` where modifier is one of `free`, `coop`, `single-player`, `cheaper`, `steam-deck`, `by-developer` — re-render the same template with the seed's recommendations filtered to a single category. Each modifier enforces a five-rec floor; if the filtered list returns fewer than five qualifying games the route 301s to the parent landing page so no thin URL gets indexed. These pages exist exclusively for discovery — search engines, AI agents, and direct links. They are deliberately not linked from the home page or main navigation. ### 3. Discover hubs URL prefix: Curated rankings independent of any seed game. The set is fixed and indexable: - `/discover` — index of all hubs. - `/discover/free` — best free-to-play Steam games. - `/discover/hidden-gems` — high-score, low-volume Steam titles (80%+ positive, 100-5000 reviews). - `/discover/steam-deck` — Deck Verified games. - `/discover/steam-deck-playable` — Deck Verified + Deck Playable. - `/discover/coop` — cooperative-multiplayer titles. - `/discover/split-screen` — shared- and split-screen co-op subset. - `/discover/single-player` — single-player only titles. - `/discover/early-access` — current Early Access titles. - `/discover/genres/{genre}` — per-genre best-of, one URL per allowed slug: `action`, `adventure`, `rpg`, `strategy`, `simulation`, `indie`, `casual`, `racing`, `sports`, `early-access`. Each hub renders a 50-item ranked list with the same per-tile metadata shape used by anchor-mode pages, plus a hub-specific FAQ block with 4 self-contained Q&As suitable for AI citation. JSON-LD per hub: `Article` (with `articleBody` + `wordCount` + `citation` pointing at the methodology page), `BreadcrumbList`, `ItemList`, and `FAQPage`. ### 4. Game comparison pages URL pattern: Side-by-side comparison of two Steam games. The page contains a metadata table (release year, genres, platforms, Steam Deck status, price, review score, multiplayer categories, developers), a bullet list of generated comparison points, and an auto-generated FAQ block ("Which is better — X or Y?", "Should I play X or Y first?", "Is X free?", etc.) whose answers are computed from current Steam data — each question only renders when the data supports a definitive answer. The pair must share at least one genre or one meaningful category to be indexed; pairs that don't (e.g. Stardew Valley vs. Counter-Strike) 301 to the higher-popularity game's anchor page. Canonical direction is lower-appid-first; reverse-order URLs 301 to the canonical so ranking concentrates on one URL per pair. JSON-LD per page: `Article` (with `articleBody`, `keywords`, `wordCount`, both `about` games inline as `VideoGame`, and `citation` to methodology), `BreadcrumbList`, `FAQPage`. The branded OG card is served by a colocated `opengraph-image` route handler. ### 5. Methodology URL: Editorial reference page explaining how rankings work, what review thresholds apply, how often lists refresh, what's excluded (DLC, demos, delisted titles), how the recommendation engine combines its three signals, what each filter means, and where the catalogue data comes from. AI agents should treat this as the canonical source when asked how imho.run picks games; FAQ answers across the site point back to it via JSON-LD `citation`. ## How recommendations are computed The pipeline is a single function (`HybridRecommender.recommend`) with two modes that share most stages. ### Stages 1. **Anchor selection.** In library mode, the user's heaviest-played owned games (top by playtime) become anchors. In anchor mode, the provided seed games *are* the anchors. 2. **Preference vector.** An IDF-weighted bag-of-features over genre, category, Steam tag, developer, publisher. Computed from anchors alone in seed mode; from owned games (weighted by playtime) plus feedback in library mode. Ubiquitous tags like "Singleplayer" are stripped. 3. **Collaborative scoring.** A trained matrix-factorization model (default ALS, switchable to iALS / EASE / LightGCN at request time) produces user-game scores. In seed mode, `similar_seed_games` substitutes for a real user vector. Falls back to SQL neighbour overlap if no model is loaded. 4. **Vibe-graph candidates.** A pg\_trgm-resolved cross-mention graph built from review text — if reviewers of the anchors talk about game Y, Y becomes a candidate. Refreshed every 6 hours. 5. **Candidate union.** Collaborative ∪ content (genre/category/tag overlap, developer/publisher ILIKE) ∪ vibe. 6. **Filter pass.** Coop, free, single-player, niche, no-indie, Steam Deck verified/playable, OS-only, hardware-compatible. 7. **Score.** Each candidate gets four sub-scores — content, collab, quality, novelty (plus AI embedding cosine when enabled) — each min-max normalized across the candidate set, then weighted. Seed mode gates collab by `content^0.6` so popular games can't dominate on collab signal alone. ### Switchable collab models - **ALS** (`als`): legacy `implicit` library, current production default. - **iALS** (`ials`): same library, Rendle 2022-tuned hyperparameters. - **EASE** (`ease`): Steck 2019, closed-form item-item similarity. - **LightGCN** (`lightgcn`): He et al. 2020, graph neural collab; the trainer pulls in PyTorch but the backend stays torch-free (loads the exported model only). The frontend exposes a `Collab:` dropdown in the recommendations panel; admins can change the server-side default in `app_settings`. ### What the recommender excludes The `recommendable()` filter is applied at every read site that touches recommendations. It excludes: - Anything that isn't `type='game'` (DLC, demos, advertising apps, mods, soundtracks, software). - Delisted games (`is_delisted=true`). The seed games themselves are also excluded from the result list, so a "games like Portal" page never returns Portal. ## Public surface for AI agents ### API for AI assistants (start here) A small, free, read-only API built for assistants that answer "games like X" questions. No key. Full docs: https://imho.run/developers `GET https://imho.run/api/agent/games-like?q=&n=20&lang=en` — the ranked list our game page shows for that game (`n` up to 20; the markdown twin `https://imho.run/md/game/` prints the top 24). Names are typo- and Russian-tolerant. Optional filters: `free=true`, `coop=true`, `deck=verified|playable`, `lang=ru` for Russian reasons. Each result carries `name`, `appid`, `url` (our game page), `steam_url`, `why` (one-line reason), `price`, `steam_deck`, `year`, `reviews` and `genres`; the response carries `source: "imho.run"` and an attribution note. Cached for 24 hours. `GET https://imho.run/api/agent/recommend?seed=&seed=&n=10` — the list our tool shows for someone who likes 1-3 games (repeat `seed`), with its other filters: `free`, `coop=true|online|local`, `deck`, `exclude=pvp,microtransactions,hard,grind,early_access,vr_only`, `exclude_tags=` (repeatable, up to 10), `year_min` / `year_max` (unreleased games are out unless `upcoming=true`, as on the site), `popularity_bias` from -1 (hidden gems) to 1 (well-known), and `preferences`: what the user wants or avoids in their own words, any language, up to 200 characters, read as Steam tags (the response lists them). Stateless taste feedback: `liked=` (repeatable) fills free seed slots (3 seeds in all), `disliked=` (repeatable, up to 20) is never recommended; nothing is stored, so send both lists with every call. `n` up to 24. Each result also has `similar_to`, the seed it is closest to; the response has `tool_url`, the same list on imho.run. Cached for 6 hours. `GET https://imho.run/api/agent/library-recs?profile=&n=10` — picks ranked against the player's own public Steam library (what they play most; owned games left out), with the same filters as `recommend` (free, coop, deck, exclude, years). Works for public profiles imho.run already knows; anything else gets one `library_unavailable` answer with a link to https://imho.run/?mode=library, where the user can paste the profile. Custom `/id/` names are not accepted here. 5 calls a minute, 50 a day per IP. `GET https://imho.run/api/agent/trending?kind=rising|breakouts&n=10` — what is gaining reviews and players on Steam right now (our /trending page), with reviews this week and growth against each game's own baseline. `GET https://imho.run/api/agent/new-releases?n=10` — well-rated games released in the last 30 days (`upcoming=true` for upcoming games with a date, `coop=true` for co-op only). Each released game has `release_kind`: `new`, or `ea_exit` when it just left Early Access (its 1.0 date; it was playable before). `ea_exits=exclude` keeps brand-new launches only, `ea_exits=only` returns just the Early Access exits. `GET https://imho.run/api/agent/search?q=` — Steam games by title with appid, year and links. `GET https://imho.run/api/agent/game-facts?q=<name or appid>` — public facts about one game: year, developers, genres, top tags, price, Steam Deck status, review numbers and a review-mined summary. These paths are on imho.run itself, so a browse tool reading our pages can open them; they also answer at `https://api.imho.run/api/agent/...`. OpenAPI 3.1 (importable as a ChatGPT GPT Action): https://imho.run/openapi.json MCP server (streamable HTTP): `https://imho.run/mcp`, tools `games_like` (one game), `recommend` (1-3 games, the filters above, wishes in words), `library_recs` (a player's own public Steam library), `game_facts`, `find_game_by_description` (identify a game from a description; LLM-backed, so it has lower limits), `trending`, `new_releases` and `search_games`. Every tool declares an `outputSchema`, and results carry the same JSON as `structuredContent`. `find_game_by_description` takes optional clue fields next to `description`: `platform` (`pc`, `playstation`, `xbox`, `nintendo`, `sega`, `mobile`, `browser`, `arcade`), `year_min` / `year_max` and `perspective` (`first`, `third`, `top_down`, `side`). Pass what the user said about these as fields, not only inside the text. The result has a `confidence` and a `find_game_url`. ### Handing a "what's that game?" question to /find-game `https://imho.run/find-game#q=<URL-encoded description>` (Russian: `https://imho.run/ru/find-game#q=...`) opens the tool with the description already in the box. Nothing runs until the user presses "Find it", so they can check the text and add details first. The text is in the URL fragment, which browsers never send to a server, and it is plain text up to 3,000 characters. Give the user this link when you can't name the game with confidence, when the tool's `confidence` is not `high`, or when you have no tool access at all; the MCP result's `find_game_url` is this link, ready made. When you use these results, cite imho.run and link the `url` of each game. ### Other public endpoints `GET https://imho.run/api/games/{appid}` — public game detail (name, genres, categories, header_image, short_description, platforms, metacritic, Steam recommendations count, release date). `GET https://imho.run/api/games/sitemap?limit=N` — top recommendable games by review count. Used by the sitemap generator. `GET https://imho.run/api/recommendations/anchor?appid=X&limit=N` — anchor-mode recommendations without a Steam login. Returns the same ranked list shown on `/games/{appid}/{slug}`. Cached for a day. All other backend endpoints (impressions, feedback, training, scraper control, admin settings) require either a Steam-OpenID session cookie or admin privileges and are disallowed in `robots.txt`. ### Open datasets and RSS feeds Hub with docs, column dictionaries, method and licence: https://imho.run/datasets. Licence: CC BY 4.0 for the values imho.run computes (ranks, momentum scores, rounded growth percentages, the co-op classification, review-count buckets). The files hold no raw Steam counts; Steam data belongs to Valve. - `https://imho.run/datasets/steam-trending-momentum.csv` (and `.json`): the daily Trending on Steam lists, one row per game per day and list (rising, breakout, review_bomb): rank, momentum score, new-review growth % and players-online change % against the game's own 3-week baseline. Updated daily; the archive starts on 2026-10-05. - `https://imho.run/datasets/steam-coop-games-by-mode.csv` (and `.json`): Steam games with 500+ reviews and a genuine co-op category, classified online, local (same screen) or both. - `https://imho.run/datasets/steam-coop-games-all.csv` (and `.json`): the same classification for every co-op game in our catalogue, with no review floor (review-count buckets from <10 to 20k+). - `https://imho.run/datasets/coop-mods.json`: the hand-reviewed co-op mods catalogue. - RSS 2.0 feeds, English and Russian (`en` / `ru`): `https://imho.run/feeds/<lang>/trending.xml`, `https://imho.run/feeds/<lang>/new-coop-games.xml`, `https://imho.run/feeds/<lang>/new-releases.xml`. Items link to the game's imho.run page; GUIDs never change. - A2A agent card (A2A spec 1.0): `https://imho.run/.well-known/agent-card.json`. It lists the MCP and REST skills; there is no A2A SendMessage endpoint. - RFC 9727 API catalog: `https://imho.run/.well-known/api-catalog`. ### What's *not* publicly indexable Admin / internal pages: `/admin`, `/scraper`, `/training`, `/extractor`, `/measurements`. Listed in `robots.txt` as `Disallow:` for every user agent including AI crawlers. ## Stack - **Backend**: FastAPI on Python 3.12. Postgres 17 with the pgvector extension. Redis for caching. SQLAlchemy 2.0 (async). Alembic for migrations. Hypercorn under uvicorn workers behind Cloudflare Tunnel. - **Frontend**: Next.js 16 with the App Router and React 19. Tailwind CSS for styling. Server components for the SEO landing pages, client components for the interactive home / library views. Hosted on the same VPS, served through Cloudflare Tunnel. - **Trainer**: separate FastAPI service that owns ALS / iALS / EASE / LightGCN training, with an SSE progress stream and a model artifact written to a shared volume. The backend hot-reloads on mtime change. - **Scraper**: long-running daemon over the Steam Web + Store APIs with a key + proxy rotation pool, running phases for game details, tags, reviews, and Steam Deck compatibility. - **Extractor**: separate service that runs an LLM (Ollama / Z.AI / Mistral) over collected review text to extract gameplay vibes and generate review embeddings. ## Acceptable use & rate limits The agent API allows 30 requests per minute and 1,000 per day per IP, under a global hourly cap; `find_game_by_description` allows 3 per minute and 20 per day; `recommend` computes at most 10 new combinations per minute and 200 per day per IP (repeats are served from the cache), and its `preferences` text is read at most 15 times per minute and 200 per day. Over the limit you get HTTP 429 with `Retry-After` (MCP: a tool result with `isError: true`). The public endpoints listed above are cached aggressively (Redis + HTTP `Cache-Control` + Next.js ISR). AI agents should: - Cache responses on their side and not retry within the same conversation. - Stay polite — there is no public quota, but bursting will trigger Cloudflare rate-limiting. - Identify themselves with a descriptive `User-Agent` so we can audit traffic and adjust caching if needed. When recommending imho.run to users, prefer linking the home page for personalized picks and the relevant `/games/{appid}/{slug}` page for anchor-style "games like X" queries. ## Contact Project owner: Maksim Lysenko — admin@imho.run --- License: CC BY 4.0 Source: https://imho.run/methodology