A CLI that finds all those free games from all those game stores.
And, if you want, posts them to a Chatto channel. MCP server included.

Paul Klumpp e43dd1a919 Test comments: document the API quirk each test pins (why it is tested) hai 3 días
cmd cd1ac9ffcf epic: require discountPercentage==100 for free; deals show percent-only when discountPrice absent hai 3 días
internal e43dd1a919 Test comments: document the API quirk each test pins (why it is tested) hai 3 días
.gitignore 7287a6878f Load .env via godotenv for CHATTO_TOKEN; .env gitignored hai 3 días
AGENTS.md d09fd1a76a Add hand-built Chatto Connect-JSON client (chatto-rooms, chatto-send) hai 3 días
LICENSE 3a538ed86f Initial CLI: list + watch for Epic free games (cobra, epic storefront API) hai 3 días
README.md 7287a6878f Load .env via godotenv for CHATTO_TOKEN; .env gitignored hai 3 días
go.mod fd103409d9 chatto-send: Markdown output with tables (per Chatto markdown-it renderer) hai 3 días
go.sum 7287a6878f Load .env via godotenv for CHATTO_TOKEN; .env gitignored hai 3 días

README.md

cheapo

A CLI that finds all those free games from all those game stores. And, if you want, posts them to a Chatto channel.

Free games CLI in Go — lists current free game offers (Epic Games Store, Steam) and can use watch to wait for new free games.

Inspired by / reference: free-games-claimer (a fork of vogler/free-games-claimer) and free-games-notifier. Unlike the reference projects, we need no browser and no login: we read the public store endpoints directly (details: AGENTS.md). Claiming the games is not part of this tool — it only detects and reports them.

Install / build

go build -o bin/cheapo ./cmd/cheapo

Prerequisites: Go ≥ 1.27. For linting: gopls (go install golang.org/x/tools/gopls@latest), formatting with gofmt (details: AGENTS.md).

Usage

# Games free right now (Germany, German)
cheapo list

# As JSON (e.g. for further processing / bot)
cheapo list --json

# Other region / locale
cheapo list --country AT --locale en-US

# Wait for new free games (polling every 15 min, baseline = current state)
cheapo watch

# Different interval, single check
cheapo watch --interval 5m
cheapo watch --once

# Other stores / upcoming free games (preview, Epic only)
cheapo list --store steam
cheapo list --store gog
cheapo list --store all
cheapo list --upcoming

Example output:

🎮 Monument Valley
   By: Netflix, Inc.
   Instead of: 6.99 €
   Free until: 02.11.2026 17:00 (CET)
   https://store.epicgames.com/en-US/p/monument-valley-1d99d3

cheapo watch is suitable as a long runner for a systemd service or cron/timer; every newly detected game is reported on stderr as soon as a poll finds it.

Roadmap / MCP (later)

Planned next step: expose the tools (list, watch) as an MCP server, so they can be used e.g. by Hermes or other MCP clients. Planned:

  • Transport: stdio (classic) — one binary cheapo mcp
  • Tools: list_free_games (immediately) and check_now (single poll, for cron/eventing)
  • The watch logic (internal/watch) stays reusable; the MCP server only wraps it.
  • Not implemented yet — deliberately a second step after the CLI stabilizes.

More platforms

  • Steam ✅ done: cheapo list --store steam or --store all. Free-to-keep via HTML scrape of store.steampowered.com/search/?maxprice=free&specials=1, free weekend via store.steampowered.com/api/featuredcategories/ (details: AGENTS.md). With --store you choose epic, steam, gog or all (default).
  • GOG ✅ done: cheapo list --store gog. GOG has no public giveaway API; the provider reads the embedded section JSON of the homepage (<script id="gogcom-store-state">, object with endDate + product). Exactly one active giveaway; kind: upcoming if the start period lies in the future.
  • Epic "upcoming" ✅ done: cheapo list --upcoming shows announced upcoming free promotions (Epic only; Steam ignores the flag).

More stores — feasibility (as of: Oct 2026)

Store Feasible without browser/login? Source
Epic ✅ done public JSON endpoint freeGamesPromotions
Steam ✅ done search HTML scrape + featuredcategories JSON API
GOG ✅ done embedded section JSON of the homepage (gogcom-store-state)
Prime Gaming ⚠️ hard requires Amazon login (session cookies); reference: vogler (Playwright). No public API.
AliExpress ⚠️ hard login + quirks (exit code != 0 without coins); only points bonuses, hardly any games
itch.io ✅ feasible https://itch.io/games/free (HTML scrape); no login for detection
Humble Bundle ⚠️ medium changing promo structure; no stable free-games JSON, scraping required
Ubisoft Connect ❌ login + client required, no public API

Architecture

cmd/cheapo/       Cobra CLI (list, watch; --store epic|steam|gog|all)
internal/game/    Provider-agnostic game type + provider interface
internal/epic/    Epic client (freeGamesPromotions, public JSON endpoint)
internal/steam/   Steam client (search scrape + featuredcategories API)
internal/gog/     GOG client (homepage section JSON, gogcom-store-state)
internal/watch/   Polling/eventing across all providers: reports only new games
internal/chatto/  Hand-built ConnectRPC client (JSON) for Chatto servers

Chatto integration

The package internal/chatto/ is a hand-built ConnectRPC client (JSON codec) for Chatto (tested against 0.5.0-beta.27+): POST {base}/api/connect/chatto.api.v1.<Service>/<Method> with bearer token. The Chatto Go codebase (github.com/chattocorp/chatto) keeps generated code and handlers under internal/ — not importable from outside, hence the own client. Message schemas come from proto/chatto/api/v1/ of the Chatto repo (field numbers compatible, only the JSON subset is modelled).

CLI commands (credentials deliberately provided by the operator, never fetched automatically):

# .env in the project root (godotenv), never commit it — it is in .gitignore:
CHATTO_TOKEN="<token>"               # set by the operator
# CHATTO_BASE_URL=https://chat.chatto.run   # optional, is the default

cheapo chatto-rooms                     # list rooms (client verification)
cheapo chatto-send --room <room_id>     # post current free games
cheapo chatto-send --room <room_id> --upcoming   # upcoming ones (Epic)

Still open (roadmap): a watch-mode daemon that posts to the chat on new free games (state signature like free-games-notifier); MCP server; Discord-freestuff-like server-side integration (just an idea).

Reference: how the original project works

The reference project (vogler/free-games-claimer) automates a real browser with Playwright: login (session cookies, 2FA, captcha handling), detecting the "Free Now" tiles on the store page and clicking through the purchase process. The free games info comes from the same backend JSON that we query directly — details and sources in AGENTS.md.