Go to file
Krzysztof kuhy Rudnicki a191c8e459 Release a game after one new achievement instead of 100% completion
Requiring 100% locked the user onto one game for weeks, which proved
ineffective. The assignment and every manual pick now release as soon as one
achievement is unlocked after the game was assigned (Steam unlock_time vs the
pick's started_at / State.current_assigned_at).

- finished_app_ids still means 100% complete; a game released below 100% gets
  released_at plus a 7-day cooldown and returns to the pool.
- Next pick: least recently assigned first, then shortest HLTB time.
- Releasing never evicts: released/expired picks stay installed and playable
  until the user explicitly chooses another game (new pick-manual, or
  accepting the next assignment); with no replacement the current game stays.
- Tampering detection judges a released game by unlocks after its release.
- The daemon reloads every State field each tick so its sweep save cannot
  overwrite cooldowns or assignment times written by the CLI.
- State.load backfills assignment times once and persists them; load-time
  migrations moved to _state_migrations.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhzaTAWtRfJk8gre6NLSka
2026-09-26 16:46:03 +02:00
.github/workflows CI runs the vitest coverage bar; it only ran on pre-push before 2026-09-20 22:12:24 +02:00
docs/explanations feat(enforcer): raise manual pick cap from 2 to 3 concurrent games 2026-07-23 18:05:29 +02:00
pacman-hooks Add a daily gaming-time budget with a binary-level cutoff 2026-08-04 20:00:08 +02:00
prompts Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 19:55:43 +02:00
scripts pre-push is a 1-second stamp check; the suites moved to the manual stage 2026-09-20 21:21:48 +02:00
steam_backlog_enforcer Release a game after one new achievement instead of 100% completion 2026-09-26 16:46:03 +02:00
web Today's stable bumps: pylint, ruff and the web dev deps (jsdom, vite) 2026-09-25 18:49:25 +02:00
.gitignore Add CI-mirror pre-push gate + requirements-sync check 2026-07-11 17:47:14 +02:00
.mcp.json Add MCP server exposing the enforcer to Claude Code 2026-07-10 21:05:17 +02:00
.pre-commit-config.yaml Today's stable bumps: pylint, ruff and the web dev deps (jsdom, vite) 2026-09-25 18:49:25 +02:00
AGENTS.md Adopt the four markdown namespaces and gate them 2026-08-24 15:54:34 +02:00
CLAUDE.md Adopt the four markdown namespaces and gate them 2026-08-24 15:54:34 +02:00
install.sh Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 19:55:43 +02:00
pyproject.toml Import split-out names from the modules that own them; drop the four lazy facades 2026-09-12 20:22:44 +02:00
README.md Release a game after one new achievement instead of 100% completion 2026-09-26 16:46:03 +02:00
requirements.txt Today's stable bumps: pylint, ruff and the web dev deps (jsdom, vite) 2026-09-25 18:49:25 +02:00
run.sh feat: add block-gaming command (Stage 4) + guard-lib migration cleanup 2026-07-04 11:45:54 +02:00
steam-backlog-enforcer-web.service Stop the web UI serving numbers the enforcer is not applying 2026-08-29 23:39:40 +02:00
steam-backlog-enforcer.service Keep Steam Runtime's logger out of the journal 2026-09-13 10:51:50 +02:00
TODO-file-length-250.md Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 19:55:43 +02:00

Steam Backlog Enforcer

Forces you to play one Steam game at a time: earn at least one new achievement in the assigned game before moving on to the next.

Requiring 100% completion kept you locked onto one game for weeks, which proved ineffective. A game released after one new achievement stays in the backlog (it is not counted as finished) and comes round again later.

Features

  • Achievement tracking: Picks the least-recently-assigned game next, then the shortest HLTB completionist time; a released game sits out a 7-day cooldown
  • Store blocking: Blocks store.steampowered.com via /etc/hosts
  • Game uninstalling: Removes all installed games except the assigned one
  • Process enforcement: Kills unauthorized game processes
  • Tampering detection: Detects achievement unlocks on non-assigned games
  • HLTB integration: Estimates completion time with persistent cache

Setup

python -m python_pkg.steam_backlog_enforcer.main setup

Commands

Command Description
scan Scan library, fetch HLTB data, assign game
check Check assigned game for a new achievement
status Show current assignment and blocking
list List incomplete games from snapshot
skip Skip the currently assigned game
enforce Run enforcer (block, uninstall, kill)
unblock Remove store blocking
reset Reset all state
installed List currently installed Steam games
uninstall Interactively uninstall non-assigned games
setup First-time configuration

Enforce mode

sudo python -m python_pkg.steam_backlog_enforcer.main enforce

This will:

  1. Block Steam store in /etc/hosts
  2. Uninstall all games except the assigned one
  3. Continuously kill any unauthorized game processes

Game Uninstall

Directly removes appmanifest files and game directories from ~/.local/share/Steam/steamapps/. Preserves Proton versions and Steam Linux Runtime.

python -m python_pkg.steam_backlog_enforcer.main uninstall

MCP server (Claude Code integration)

The enforcer exposes an MCP server (steam_backlog_enforcer._mcp) so Claude Code and its subagents can query the backlog and drive it through typed tools.

  • Read tools: get_dataset, get_status, get_stats, list_backlog.
  • Gated write tools: pick_manual, block_gaming — each defaults to a dry-run preview; pass confirm=true to actually apply. These write tools must never be added to a permission allowlist (a subagent could otherwise bypass the human confirmation).

The mcp SDK is an optional dependency (pip install -e '.[mcp]'), kept out of the CLI/systemd system-python path. One-time setup of the dedicated venv that Claude Code spawns:

./scripts/setup_mcp.sh

Registration lives in the checked-in .mcp.json (project scope). Restart Claude Code in this repo and approve the project MCP-server prompt for it to load. Verify with claude mcp list.