# 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=` — 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=` (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//trending.xml`,
`https://imho.run/feeds//new-coop-games.xml`,
`https://imho.run/feeds//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