Automatically detect Windows game zips in ~/Downloads and existing game folders in ~/Games, add them as non-Steam shortcuts with Proton Experimental, extract their icons, and restart Steam to pick them up.
Scans ~/Downloads for .zip files and ~/Games for game directories. For each new game not already in Steam, it:
- Finds the best
.exe(prefers name-match, then x64, then shallowest depth) - Adds a non-Steam shortcut to Steam with preconfigured Proton launch options
- Sets Proton Experimental as the compatibility tool
- Extracts and applies the game's icon from its
.exe - Restarts Steam so shortcuts appear immediately
- Cleans up extracted zip directories
This tool handles extraction, Steam library integration, and Proton/compatibility setup for Windows game files you already have. It does not source, verify, or provide game files — that's on you.
steam-add-games (Python) reads and writes Steam's binary shortcuts.vdf via the vdf library, and modifies config.vdf for Proton compat tool mappings. AppIDs are generated from CRC32 of (exe + name) OR'd with 0x80000000 — deterministic and self-consistent, though not matching Steam's internal algorithm.
The executable scanner filters out redistributables (DirectX, VC++ redist, PhysX), crash handlers, and setup installers. It walks game directories looking for .exe files and scores them by name similarity, architecture depth (x64 wins), and directory depth (shallow wins).
Icon extraction uses wrestool to pull PNG or icon resources from PE files, then icotool to convert to PNG if needed.
steam-gaming is two parts:
- A Bash script that finds or creates a "Gaming" virtual desktop, switches to it, launches Steam, and writes its PID to
/tmp/steam-gaming-steam-pid - A KWin JavaScript script that watches for new windows and moves any Steam-related window (by resource class, name, or PID ancestry) to the Gaming desktop
| Package | Purpose | Install |
|---|---|---|
| Python 3 | Script runtime | System package |
vdf (Python library) |
Read/write Steam VDF files | pip install vdf or python-vdf on Arch |
wrestool (icoutils) |
Extract icon resources from PE files | icoutils package |
icotool (icoutils) |
Convert ICO to PNG | icoutils package |
| Steam | Runtime | System package or steam-installer |
qdbus6 (Qt6 tools) |
KDE virtual desktop management (steam-gaming) | qt6-tools or qt6-base |
| KDE Plasma 6 | KWin scripting (steam-gaming) | Desktop environment |
git clone https://github.com/laghab/steam-onboard.git
cd steam-onboard
./install.shpip install vdfOn Arch Linux: sudo pacman -S python-vdf
steam-add-games --yesOr launch "Onboard" from your application menu (if you installed the .desktop file).
The --yes flag skips interactive prompts (auto-delete junk folders). Omit it for interactive mode.
Open Steam and check your Library — new shortcuts should appear under "Non-Steam" games.
Built with AI-assisted development (opencode) — I directed the architecture and implementation, tested extensively, and iterated based on what broke. This is a personal/learning project rather than a production-hardened one — it works for the cases I've tested, but hasn't seen wider use, so expect some rough edges.
The initial request was "automate adding non-Steam games via CLI" — no GUI interaction allowed. A lot of time went into understanding Steam's VDF format (shortcuts.vdf is binary, config.vdf is text), figuring out the correct appID generation, and handling Steam's tendency to overwrite config files on restart.
Key lessons:
vdf.binary_loads/vdf.binary_dumpshandles binary shortcuts.vdf cleanly — no need for external tools- Text VDF (config.vdf) round-trips through
vdf.dump()but formatting changes can confuse Steam — surgical string replacement is safer for sensitive sections - Editing files Steam manages (localconfig.vdf) while Steam runs is fragile — Steam rewrites them on shutdown
- Icon extraction from PE files: try PNG resources first (resource name 103), fall back to building ICO from type-3/type-14 resources and converting with icotool
MIT