Releases: Necrosiak/SkullKey
Release list
SkullKey v1.12.3 — store logins land where they are read from
Signing in to Epic, GOG or Amazon appeared to do nothing: the store kept asking for a login even though the credentials had been written to disk. They were — one directory away from where SkullKey looked for them.
Fixed
- Store logins were written outside the account space they are read from. SkullKey keeps each Steam account's store logins under
accounts/<steamid>/, resolved byscripts/settings.sh. The login helpers are launched directly by Steam and source only their own store'ssettings.sh, where the account directory silently fell back to the runtime root. Solegendary authwrote to<runtime>/legendarywhile the status check readaccounts/<steamid>/legendaryand answered<not logged in>forever. All three stores shared that fallback, which is why all three behaved the same way. - Existing installations recover without signing in again. Credentials and databases stranded in the runtime root — or in the
defaultspace used while Steam is not yet running — are adopted by the active account. Only what the account space is missing is moved: nothing is overwritten, nothing is deleted. A store directory that already exists is completed entry by entry, which matters in practice: alegendary statusleaves an emptylegendary/behind, and refusing the recovery because of it would leave you signed out with the credentials sitting next door. - The Epic login window no longer reports a failure on every page it loads. It parsed each finished page as JSON, including the sign-in form, filling the log with
Expecting value: line 1 column 1 (char 0)and making ordinary navigation look like a fault.
Thanks to @tobal37, whose diagnostic output located the stranded user.json and settled this (#3).
Full Changelog: v1.12.2...v1.12.3
SkullKey v1.12.2
Fixed
- GOG no longer fails first-run provisioning on Python 3.14 distributions such as CachyOS. SkullKey now installs Heroic's official architecture-specific gogdl 1.3.0 standalone release and verifies its SHA-256, avoiding the failing native-extension build.
- Store dependency provisioning now returns and logs a real failure when an executable is still missing instead of reporting that the ensure task finished successfully.
Full Changelog: v1.12.1...v1.12.2
SkullKey v1.12.1
Fixed
- Epic login no longer closes immediately when SkullKey uses its native Legendary environment. SkullKey now captures the Epic authorization code in its embedded GTK/WebKit window and passes it to Legendary non-interactively.
- Epic, GOG, and Amazon now check for GTK/WebKit before opening their login window. When the dependency is missing, SkullKey shows the correct installation command for the detected Linux distribution instead of silently closing.
Full Changelog: v1.12.0...v1.12.1
v1.12.0
Fixed
Store logins appeared to be lost after a Steam update — Epic, GOG and Amazon
alike. You could sign in, the sign-in would succeed, and the store would still
say you were not connected.
SkullKey keeps each store's session under the active Steam account, so that two
people sharing a console do not inherit each other's libraries. Finding that
account relied on two things Steam has since changed:
registry.vdfno longer publishes a numericActiveUserloginusers.vdfno longer carriesMostRecent
Both probes came back empty, so SkullKey fell back to a generic profile — an
empty one — while your real session sat untouched in the folder belonging to your
actual account.
Epic showed it worst, because its configuration is reached through a symlink that
was being repointed at the empty profile on every run: a fresh login was written
to one folder and read back from another. GOG and Amazon receive their paths
directly, so they were simply looked up in the wrong place.
The active account is now resolved from AutoLoginUser, matched by account name,
then from AutoLogin, then from the most recent Timestamp. The older
ActiveUser and MostRecent keys are still tried first, so an older Steam
behaves exactly as it did before.
Nothing was lost. Your sessions are still in the account folder they were
written to, and become visible again as soon as the account is detected properly.
If you signed in several times while this was happening, the most recent session
is the one to keep — the others are simply idle copies under other profiles.
v1.11.4 — a failed auto-update no longer passes for a success
A one-line correctness fix on the update path, found while investigating the same defect in BoneCast.
Fixed
A failed automatic update was reported as a success. apply() returns a dictionary, and {"ok": False, "error": …} is always truthy in Python. The boot-time auto-updater therefore treated every failure exactly like a success: it restarted Decky as if the new version had landed — and did it again at the next boot, since the installed version had not moved. It now reads the result and logs why it gave up.
The manual update button already checked the result properly, so this only ever affected the silent check at startup.
SkullKey's own file-replacement fallback has been in place since v1.11.2, so the permission failure that made this visible in BoneCast does not apply here.
v1.11.3 — unload no longer dies on a RecursionError
A maintenance release. Nothing changes while you play — both fixes are about what the plugin does on the way out, and about controller focus in the About tab.
Fixed
RecursionError on every plugin unload (#2)
Every time the plugin was unloaded — Decky restarting, Steam shutting down, the plugin being disabled — the backend log ended on a RecursionError raised several hundred frames deep inside Task.cancel().
The unload routine gathered the tasks to cancel with asyncio.all_tasks(), which includes the currently running task — that is, the unload coroutine itself. So it cancelled itself, Task.cancel() recursed through the waiter chain until Python gave up, and the gather() that followed was waiting on itself. Everything past that point never ran, including clearing the action cache, and the shutdown line was never reached. The sweep was also too broad: it cancelled every task the loop happened to be running, not just the plugin's own.
SkullKey now tracks its own background tasks and cancels only those. Nothing was visible while playing, but a teardown that never finishes is the kind of thing that turns into a hang at shutdown later.
Background tasks could be collected while still running. The four tasks started at boot kept no reference, and asyncio holds only a weak one — so Python was free to garbage-collect a task mid-execution. They are now held for their whole lifetime.
Controller navigation in the About tab. flow-children="horizontal" is not a value the Steam client's focus engine accepts; it fell through to a default branch that logged Unhandled flow-children on every render and produced no focus flow at all. Replaced with row. This one was fixed in the repository back on 2026-07-23 and simply never made it into a release — it ships here.
Also worth recording
While fixing the above, one Decky behaviour turned out to be worth writing down for anyone else building a plugin: the plugin's event loop stops being run as soon as _unload suspends, so no await past that point ever resumes. With the recursion fixed but a bounded asyncio.wait() still in place after the cancellation, the log stopped dead at Cancelling N pending tasks... and never reached the end. Cancellation itself is synchronous, so it lands regardless — but nothing that matters may sit behind an await during unload.
Full changelog: CHANGELOG.md
v1.11.2
v1.11.1 — Root-owned update fix
Maintenance pass, ported over from the same work on Steamcord v1.16.1.
Fixed
- In-plugin updates failed on root-owned installs. The updater overwrote files with
shutil.copy2, which ends with achmodon the destination — something a non-root process cannot do on root-owned files even when they are world-writable. Files are now replaced via a temp file + atomicos.replace, which only needs write permission on the directory — and every replaced file becomes owned by the user, so a root-owned install heals itself as it updates.
Full Changelog: v1.11.0...v1.11.1
v1.11.0 — ⛏️ Minecraft: Java, Bedrock & Modrinth modpacks (version picker + world backups)
⛏️ Minecraft comes to SkullKey
A whole new Minecraft store tab — everything installs through the legitimate launchers (owning the game is required; each launcher enforces its own sign-in).
Java Edition — one click to the game
Installed through the official Prism Launcher AppImage, pre-configured for you: language follows your console, Java downloads automatically, no setup wizard. The only first-launch step is signing in with the Microsoft account that owns the game — after that, the Steam shortcut boots straight into the latest Minecraft release. Prism itself and the Vanilla instance stay current through the daily auto-update.
Bedrock Edition — best fit for Game Mode
Installed from Flathub through the community mcpelauncher. Sign in with a Google account that owns Minecraft on Google Play and the launcher downloads the game itself. Native controller support, silent daily launcher updates, and your worlds are kept if you ever uninstall.
Modrinth modpacks — the whole catalog
The most-downloaded packs are on display, and the store's filter box doubles as a live search across all of Modrinth (17,000+ packs: Fabulously Optimized, Cobblemon, Better MC…). Each pack becomes its own Prism instance with its own Steam shortcut — the .mrpack is resolved headlessly (parallel mod downloads with SHA-1 verification, overrides, pack icon in Prism), no launcher UI involved. Individual mods and resource packs stay manageable through the Prism Launcher utility entry.
🎚️ Version picker
Every Minecraft item gets a Version editor in its Config menu: keep Latest (auto-update) for silent daily updates, or pin any exact version — every Mojang release for Java, any published version for a modpack. Pinning stops auto-updates for that item and re-syncs it immediately; going back to Latest re-enables them.
💾 Automatic world backups
A Minecraft downgrade can refuse — or corrupt — worlds created on a newer version. So your worlds are snapshotted automatically before every version change and before uninstalling (last 3 snapshots per instance, stored in ~/.local/share/skullkey-saves/minecraft, outside the game folders so they survive a full uninstall). A confirmed Restore worlds backup action in the game menu brings the newest snapshot back — the current worlds are snapshotted first, so a restore never loses anything.
9-language UI texts as always (EN/FR/DE/ES/IT/PT/NL/PL/RU). Existing installs pick this up automatically through the plugin's auto-update.
v1.10.0 — game save backup & restore (ludusavi)
💾 Save backup & restore
Two new actions in the game menu of the Epic, GOG and Amazon stores (installed games only):
- Backup saves — snapshots the game's progression into
~/.local/share/skullkey-saves. - Restore saves — (with confirmation) puts the files back at their original locations.
Powered by ludusavi: a native binary from PATH is used when present, otherwise the latest release is downloaded automatically into an isolated directory (isolated XDG dirs — your own ludusavi setup is never touched). The game is matched against the ludusavi manifest from its store title, and the backup scans the game's own Proton prefix (compatdata/<id>/pfx), so each Steam account's saves stay separate.
Note: a "No save files found" result can be legitimate — some games only create their save folder after the first manual save.
Docs: new saves bullet in the READMEs (9 languages) + CHANGELOG entry.