imho 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
imho-0.2.0/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ uv.lock
imho-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 imho.run
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
imho-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,202 @@
1
+ Metadata-Version: 2.5
2
+ Name: imho
3
+ Version: 0.2.0
4
+ Summary: Python client for the imho.run API: Steam games like any game, game facts, and finding a game from a description.
5
+ Project-URL: Homepage, https://imho.run/developers
6
+ Project-URL: Documentation, https://github.com/0x216/imho-mcp/tree/main/python#readme
7
+ Project-URL: Repository, https://github.com/0x216/imho-mcp
8
+ Project-URL: Issues, https://github.com/0x216/imho-mcp/issues
9
+ Author-email: "imho.run" <admin@imho.run>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: game-recommendations,games,imho,mcp,recommender-system,steam
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Games/Entertainment
19
+ Classifier: Topic :: Internet :: WWW/HTTP
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: httpx<1,>=0.24
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
25
+ Requires-Dist: pytest>=7; extra == 'test'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # imho (Python client for imho.run)
29
+
30
+ A small typed client for the [imho.run](https://imho.run) API for AI assistants:
31
+ Steam games like any game you name, recommendations from several games with
32
+ filters, facts about one game, what is trending and newly released on Steam,
33
+ title search, and identifying a game from a description. It wraps the public
34
+ REST endpoints under `https://imho.run/api/agent/` and the MCP endpoint
35
+ `https://imho.run/mcp`. The API is free, read-only and needs no key.
36
+
37
+ ```bash
38
+ pip install imho
39
+ ```
40
+
41
+ Requires Python 3.9+ and [httpx](https://www.python-httpx.org/). Source,
42
+ issues and the MCP setup for assistants: <https://github.com/0x216/imho-mcp>.
43
+
44
+ ## Usage
45
+
46
+ ```python
47
+ from imho import ImhoClient
48
+
49
+ with ImhoClient() as imho:
50
+ picks = imho.games_like("Hollow Knight", n=3)
51
+ for game in picks["results"]:
52
+ print(game["rank"], game["name"], "-", game["why"], game["price"]["text"])
53
+ ```
54
+
55
+ ```
56
+ 1 Hollow Knight: Silksong - Also Metroidvania and Souls-like, like Hollow Knight. 19.99 USD
57
+ 2 Ori and the Blind Forest: Definitive Edition - Also Metroidvania, like Hollow Knight. 4.99 USD
58
+ 3 Nine Sols - Metroidvania with Sekiro-style parry combat and Taoist myth. 14.99 USD
59
+ ```
60
+
61
+ (Output from 2026-10-04. Rankings and prices change.)
62
+
63
+ ### games_like
64
+
65
+ ```python
66
+ imho.games_like(
67
+ "Stardew Valley", # name (typos, Russian titles OK), Steam appid or Steam store URL
68
+ n=10, # 1..20
69
+ lang="en", # "en" or "ru": language of the `why` lines
70
+ free=False, # only free-to-play games
71
+ coop=False, # True = any co-op, "online" or "local" (same screen / split screen)
72
+ steam_deck=None, # "verified" or "playable" (playable or better)
73
+ )
74
+ ```
75
+
76
+ Returns a dict with `seed` (the game that was matched), `other_matches`,
77
+ `results` (each with `rank`, `appid`, `name`, `url`, `steam_url`, `why`,
78
+ `year`, `price`, `steam_deck`, `reviews`, `genres`), `list_url` and
79
+ `attribution`.
80
+
81
+ ### recommend
82
+
83
+ For several games, more filters, or what the user wants in their own words:
84
+
85
+ ```python
86
+ recs = imho.recommend(
87
+ ["Stardew Valley", "Terraria"], # 1-3 seed games
88
+ n=10, # 1..24
89
+ preferences="cozy farming, no horror", # free text, read as Steam tags
90
+ coop=True, # also "online" / "local"
91
+ exclude=["pvp", "grind"], # pvp, microtransactions, hard, grind, early_access, vr_only
92
+ exclude_tags=["Anime"], # Steam tags to leave out
93
+ year_min=2015, year_max=None, # release years (year_max defaults to this year)
94
+ upcoming=False, # True: include unreleased games
95
+ popularity_bias=-0.5, # -1 more niche ... 1 more popular
96
+ free=False, steam_deck=None, lang="en",
97
+ )
98
+ for game in recs["results"]:
99
+ print(game["name"], "-", game["why"])
100
+ recs["preferences"]["prefer_tags"], recs["preferences"]["avoid_tags"]
101
+ # (['Farming Sim'], ['Horror'])
102
+ ```
103
+
104
+ To refine after the user reacts, call again with `liked=[...]` (fills free
105
+ seed slots, 3 seeds in all) and `disliked=[...]` (never recommended again).
106
+
107
+ ### trending, new_releases, search_games
108
+
109
+ ```python
110
+ imho.trending(kind="rising", n=10) # or kind="breakouts" for new games taking off
111
+ imho.new_releases(n=10) # well-rated releases of the last 30 days
112
+ imho.new_releases(upcoming=True, coop=True)
113
+ imho.search_games("hollow kn", n=5) # appid, year and links per match
114
+ ```
115
+
116
+ Trending picks carry `reviews_week` and `reviews_growth_pct`; new releases
117
+ carry `release_date`. While trending data is still being collected,
118
+ `trending()` returns `status: "collecting"` and an empty `results`.
119
+
120
+ ### game_facts
121
+
122
+ ```python
123
+ facts = imho.game_facts("Hades")["game"]
124
+ facts["summary"]["length"], facts["summary"]["difficulty"], facts["steam_deck"]
125
+ # ('massive', 'challenging', 'verified')
126
+ ```
127
+
128
+ Year, developers, genres, top tags, price, Steam Deck status, review numbers,
129
+ Steam's short description and, when imho.run has one, a summary mined from
130
+ player reviews (difficulty, length, session shape, co-op, hooks, dealbreakers).
131
+
132
+ ### find_game_by_description
133
+
134
+ ```python
135
+ hit = imho.find_game_by_description(
136
+ "you play a cat in a cyberpunk city with a little drone",
137
+ platform="pc", # pc, playstation, xbox, nintendo, sega, mobile, browser, arcade
138
+ year_min=None, year_max=None,
139
+ perspective=None, # first, third, top_down, side
140
+ )
141
+ hit["confidence"], hit["results"][0]["name"] # ('medium', 'Stray')
142
+ hit["find_game_url"] # imho.run/find-game with the description filled in
143
+ ```
144
+
145
+ This one runs a language model on the server. It takes several seconds and is
146
+ limited to 3 calls a minute and 20 a day per IP, so use it only when the title
147
+ is unknown.
148
+
149
+ ### Async
150
+
151
+ ```python
152
+ import asyncio
153
+ from imho import AsyncImhoClient
154
+
155
+ async def main() -> None:
156
+ async with AsyncImhoClient() as imho:
157
+ facts = await imho.game_facts("1145360")
158
+ print(facts["game"]["name"])
159
+
160
+ asyncio.run(main())
161
+ ```
162
+
163
+ ### Any MCP tool
164
+
165
+ `call_tool(name, arguments)` calls any tool on the MCP server and returns its
166
+ structured result, and `list_tools()` returns the tool definitions. Use them
167
+ for tools added to the server after this release.
168
+
169
+ ## Errors
170
+
171
+ | Exception | When |
172
+ | --- | --- |
173
+ | `NotFoundError` | No game matched the query (HTTP 404). |
174
+ | `BadRequestError` | A parameter is out of range or the query is empty (400/422), or an unknown MCP tool. |
175
+ | `RateLimitError` | Over the limit (HTTP 429). `retry_after` holds the seconds to wait when known. |
176
+ | `DisabledError` | The API is switched off on the server (503). |
177
+ | `ToolError` | An MCP tool returned `isError` for another reason. |
178
+
179
+ All of them subclass `ImhoError`, which has `detail`, `code` and `status`.
180
+
181
+ ## Limits and attribution
182
+
183
+ 30 requests a minute and 1,000 a day per IP; `find_game_by_description` 3 a
184
+ minute and 20 a day; `recommend` 10 new (uncached) combinations a minute and
185
+ 200 a day. Responses are cached on the server.
186
+
187
+ If you show the results to people, credit imho.run ("Recommendations by
188
+ imho.run") and link each game's `url`. Every response has an `attribution`
189
+ field with that wording.
190
+
191
+ ## Development
192
+
193
+ ```bash
194
+ cd python
195
+ uv run --with pytest --with pytest-asyncio --with-editable . pytest -q
196
+ IMHO_LIVE=1 uv run --with pytest --with pytest-asyncio --with-editable . pytest -q -m live # hits the real API
197
+ ```
198
+
199
+ ## License
200
+
201
+ MIT. The client is MIT-licensed; the imho.run service and its data are covered
202
+ by the [imho.run terms](https://imho.run/terms).
imho-0.2.0/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # imho (Python client for imho.run)
2
+
3
+ A small typed client for the [imho.run](https://imho.run) API for AI assistants:
4
+ Steam games like any game you name, recommendations from several games with
5
+ filters, facts about one game, what is trending and newly released on Steam,
6
+ title search, and identifying a game from a description. It wraps the public
7
+ REST endpoints under `https://imho.run/api/agent/` and the MCP endpoint
8
+ `https://imho.run/mcp`. The API is free, read-only and needs no key.
9
+
10
+ ```bash
11
+ pip install imho
12
+ ```
13
+
14
+ Requires Python 3.9+ and [httpx](https://www.python-httpx.org/). Source,
15
+ issues and the MCP setup for assistants: <https://github.com/0x216/imho-mcp>.
16
+
17
+ ## Usage
18
+
19
+ ```python
20
+ from imho import ImhoClient
21
+
22
+ with ImhoClient() as imho:
23
+ picks = imho.games_like("Hollow Knight", n=3)
24
+ for game in picks["results"]:
25
+ print(game["rank"], game["name"], "-", game["why"], game["price"]["text"])
26
+ ```
27
+
28
+ ```
29
+ 1 Hollow Knight: Silksong - Also Metroidvania and Souls-like, like Hollow Knight. 19.99 USD
30
+ 2 Ori and the Blind Forest: Definitive Edition - Also Metroidvania, like Hollow Knight. 4.99 USD
31
+ 3 Nine Sols - Metroidvania with Sekiro-style parry combat and Taoist myth. 14.99 USD
32
+ ```
33
+
34
+ (Output from 2026-10-04. Rankings and prices change.)
35
+
36
+ ### games_like
37
+
38
+ ```python
39
+ imho.games_like(
40
+ "Stardew Valley", # name (typos, Russian titles OK), Steam appid or Steam store URL
41
+ n=10, # 1..20
42
+ lang="en", # "en" or "ru": language of the `why` lines
43
+ free=False, # only free-to-play games
44
+ coop=False, # True = any co-op, "online" or "local" (same screen / split screen)
45
+ steam_deck=None, # "verified" or "playable" (playable or better)
46
+ )
47
+ ```
48
+
49
+ Returns a dict with `seed` (the game that was matched), `other_matches`,
50
+ `results` (each with `rank`, `appid`, `name`, `url`, `steam_url`, `why`,
51
+ `year`, `price`, `steam_deck`, `reviews`, `genres`), `list_url` and
52
+ `attribution`.
53
+
54
+ ### recommend
55
+
56
+ For several games, more filters, or what the user wants in their own words:
57
+
58
+ ```python
59
+ recs = imho.recommend(
60
+ ["Stardew Valley", "Terraria"], # 1-3 seed games
61
+ n=10, # 1..24
62
+ preferences="cozy farming, no horror", # free text, read as Steam tags
63
+ coop=True, # also "online" / "local"
64
+ exclude=["pvp", "grind"], # pvp, microtransactions, hard, grind, early_access, vr_only
65
+ exclude_tags=["Anime"], # Steam tags to leave out
66
+ year_min=2015, year_max=None, # release years (year_max defaults to this year)
67
+ upcoming=False, # True: include unreleased games
68
+ popularity_bias=-0.5, # -1 more niche ... 1 more popular
69
+ free=False, steam_deck=None, lang="en",
70
+ )
71
+ for game in recs["results"]:
72
+ print(game["name"], "-", game["why"])
73
+ recs["preferences"]["prefer_tags"], recs["preferences"]["avoid_tags"]
74
+ # (['Farming Sim'], ['Horror'])
75
+ ```
76
+
77
+ To refine after the user reacts, call again with `liked=[...]` (fills free
78
+ seed slots, 3 seeds in all) and `disliked=[...]` (never recommended again).
79
+
80
+ ### trending, new_releases, search_games
81
+
82
+ ```python
83
+ imho.trending(kind="rising", n=10) # or kind="breakouts" for new games taking off
84
+ imho.new_releases(n=10) # well-rated releases of the last 30 days
85
+ imho.new_releases(upcoming=True, coop=True)
86
+ imho.search_games("hollow kn", n=5) # appid, year and links per match
87
+ ```
88
+
89
+ Trending picks carry `reviews_week` and `reviews_growth_pct`; new releases
90
+ carry `release_date`. While trending data is still being collected,
91
+ `trending()` returns `status: "collecting"` and an empty `results`.
92
+
93
+ ### game_facts
94
+
95
+ ```python
96
+ facts = imho.game_facts("Hades")["game"]
97
+ facts["summary"]["length"], facts["summary"]["difficulty"], facts["steam_deck"]
98
+ # ('massive', 'challenging', 'verified')
99
+ ```
100
+
101
+ Year, developers, genres, top tags, price, Steam Deck status, review numbers,
102
+ Steam's short description and, when imho.run has one, a summary mined from
103
+ player reviews (difficulty, length, session shape, co-op, hooks, dealbreakers).
104
+
105
+ ### find_game_by_description
106
+
107
+ ```python
108
+ hit = imho.find_game_by_description(
109
+ "you play a cat in a cyberpunk city with a little drone",
110
+ platform="pc", # pc, playstation, xbox, nintendo, sega, mobile, browser, arcade
111
+ year_min=None, year_max=None,
112
+ perspective=None, # first, third, top_down, side
113
+ )
114
+ hit["confidence"], hit["results"][0]["name"] # ('medium', 'Stray')
115
+ hit["find_game_url"] # imho.run/find-game with the description filled in
116
+ ```
117
+
118
+ This one runs a language model on the server. It takes several seconds and is
119
+ limited to 3 calls a minute and 20 a day per IP, so use it only when the title
120
+ is unknown.
121
+
122
+ ### Async
123
+
124
+ ```python
125
+ import asyncio
126
+ from imho import AsyncImhoClient
127
+
128
+ async def main() -> None:
129
+ async with AsyncImhoClient() as imho:
130
+ facts = await imho.game_facts("1145360")
131
+ print(facts["game"]["name"])
132
+
133
+ asyncio.run(main())
134
+ ```
135
+
136
+ ### Any MCP tool
137
+
138
+ `call_tool(name, arguments)` calls any tool on the MCP server and returns its
139
+ structured result, and `list_tools()` returns the tool definitions. Use them
140
+ for tools added to the server after this release.
141
+
142
+ ## Errors
143
+
144
+ | Exception | When |
145
+ | --- | --- |
146
+ | `NotFoundError` | No game matched the query (HTTP 404). |
147
+ | `BadRequestError` | A parameter is out of range or the query is empty (400/422), or an unknown MCP tool. |
148
+ | `RateLimitError` | Over the limit (HTTP 429). `retry_after` holds the seconds to wait when known. |
149
+ | `DisabledError` | The API is switched off on the server (503). |
150
+ | `ToolError` | An MCP tool returned `isError` for another reason. |
151
+
152
+ All of them subclass `ImhoError`, which has `detail`, `code` and `status`.
153
+
154
+ ## Limits and attribution
155
+
156
+ 30 requests a minute and 1,000 a day per IP; `find_game_by_description` 3 a
157
+ minute and 20 a day; `recommend` 10 new (uncached) combinations a minute and
158
+ 200 a day. Responses are cached on the server.
159
+
160
+ If you show the results to people, credit imho.run ("Recommendations by
161
+ imho.run") and link each game's `url`. Every response has an `attribution`
162
+ field with that wording.
163
+
164
+ ## Development
165
+
166
+ ```bash
167
+ cd python
168
+ uv run --with pytest --with pytest-asyncio --with-editable . pytest -q
169
+ IMHO_LIVE=1 uv run --with pytest --with pytest-asyncio --with-editable . pytest -q -m live # hits the real API
170
+ ```
171
+
172
+ ## License
173
+
174
+ MIT. The client is MIT-licensed; the imho.run service and its data are covered
175
+ by the [imho.run terms](https://imho.run/terms).
@@ -0,0 +1,59 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.26"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "imho"
7
+ dynamic = ["version"]
8
+ description = "Python client for the imho.run API: Steam games like any game, game facts, and finding a game from a description."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.9"
13
+ authors = [{ name = "imho.run", email = "admin@imho.run" }]
14
+ keywords = ["steam", "games", "game-recommendations", "recommender-system", "mcp", "imho"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Topic :: Games/Entertainment",
22
+ "Topic :: Internet :: WWW/HTTP",
23
+ "Typing :: Typed",
24
+ ]
25
+ dependencies = ["httpx>=0.24,<1"]
26
+
27
+ [project.optional-dependencies]
28
+ test = ["pytest>=7", "pytest-asyncio>=0.21"]
29
+
30
+ [project.urls]
31
+ Homepage = "https://imho.run/developers"
32
+ Documentation = "https://github.com/0x216/imho-mcp/tree/main/python#readme"
33
+ Repository = "https://github.com/0x216/imho-mcp"
34
+ Issues = "https://github.com/0x216/imho-mcp/issues"
35
+
36
+ [tool.hatch.version]
37
+ path = "src/imho/_version.py"
38
+
39
+ [tool.hatch.build.targets.wheel]
40
+ packages = ["src/imho"]
41
+
42
+ [tool.hatch.build.targets.sdist]
43
+ include = ["src/imho", "tests", "README.md", "LICENSE"]
44
+
45
+ [tool.pytest.ini_options]
46
+ testpaths = ["tests"]
47
+ asyncio_mode = "auto"
48
+ markers = ["live: calls the real imho.run API (set IMHO_LIVE=1)"]
49
+
50
+ [tool.ruff]
51
+ target-version = "py39"
52
+ line-length = 100
53
+
54
+ [tool.ruff.lint]
55
+ select = ["E", "F", "I", "B"]
56
+
57
+ [tool.mypy]
58
+ strict = true
59
+ python_version = "3.10"
@@ -0,0 +1,31 @@
1
+ """Python client for the imho.run agent API (Steam game recommendations).
2
+
3
+ >>> from imho import ImhoClient
4
+ >>> with ImhoClient() as imho:
5
+ ... for pick in imho.games_like("Hollow Knight", n=3)["results"]:
6
+ ... print(pick["rank"], pick["name"], "-", pick["why"])
7
+ """
8
+
9
+ from ._version import __version__
10
+ from .client import DEFAULT_BASE_URL, AsyncImhoClient, ImhoClient
11
+ from .errors import (
12
+ BadRequestError,
13
+ DisabledError,
14
+ ImhoError,
15
+ NotFoundError,
16
+ RateLimitError,
17
+ ToolError,
18
+ )
19
+
20
+ __all__ = [
21
+ "DEFAULT_BASE_URL",
22
+ "AsyncImhoClient",
23
+ "BadRequestError",
24
+ "DisabledError",
25
+ "ImhoClient",
26
+ "ImhoError",
27
+ "NotFoundError",
28
+ "RateLimitError",
29
+ "ToolError",
30
+ "__version__",
31
+ ]
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"