smithery.ai

steam-linux

Explicit-use only — invoke when the user explicitly names this skill, or when an active explicitly invoked workflow calls it. Provides explicitly requested Steam-on-Linux, Proton, Wine, shortcut, and launcher guidance.

First seen Apr 1, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,623 B
  • docs SUMMARY.md 209 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Steam Linux Management

Use this skill when modifying Steam shortcuts, configuring Proton, or working with Steam's configuration files on Linux.

Steam Paths

STEAM_ROOT = ~/.local/share/Steam
├── config/
│   ├── config.vdf          # Text VDF - Proton mappings, settings
│   └── libraryfolders.vdf  # Text VDF - Steam library locations
├── steamapps/
│   ├── common/             # Installed games and Proton versions
│   ├── compatdata/         # Proton prefixes (Wine bottles)
│   └── libraryfolders.vdf  # Library paths
└── userdata/{USER_ID}/
    └── config/
        └── shortcuts.vdf   # Binary VDF - Non-Steam game shortcuts

Finding Steam User ID

from pathlib import Path
STEAM_ROOT = Path.home() / ".local/share/Steam"
userdata = STEAM_ROOT / "userdata"
user_id = next((d.name for d in userdata.iterdir() if d.is_dir() and d.name.isdigit()), None)

Finding Steam Library Folders

Parse libraryfolders.vdf (text VDF):

libs = [STEAM_ROOT]
with open(STEAM_ROOT / "steamapps/libraryfolders.vdf") as f:
    for line in f:
        if '"path"' in line:
            path = line.split('"')[3]
            libs.append(Path(path))

Binary VDF Format (shortcuts.vdf)

Non-Steam shortcuts use binary VDF format.

Type Bytes

  • 0x00 - Nested object start
  • 0x01 - String value
  • 0x02 - Int32 value (little-endian)
  • 0x08 - Object end

Structure

0x00 "shortcuts" 0x00
  0x00 "0" 0x00           # First shortcut (index)
    0x02 "appid" 0x00 [4 bytes LE int]
    0x01 "AppName" 0x00 "Game Name" 0x00
    0x01 "Exe" 0x00 "\"path/to/exe\"" 0x00
    0x01 "StartDir" 0x00 "\"path/to/dir\"" 0x00
    0x01 "LaunchOptions" 0x00 "options" 0x00
    ...
  0x08                     # End of shortcut
0x08 0x08                  # End of shortcuts, end of root

Parsing Example

See references/vdf-parser.py for complete implementation.

Shortcut App ID Generation

Steam generates app IDs for non-Steam games using CRC32:

import zlib
def generate_app_id(exe_path, app_name):
    key = f'"{exe_path}"{app_name}'
    crc = zlib.crc32(key.encode('utf-8')) & 0xFFFFFFFF
    return crc | 0x80000000

Shortcut Fields

Required fields for a shortcut entry:

{
    'appid': int,           # Generated app ID
    'AppName': str,         # Display name
    'Exe': str,             # Path in quotes: '"path/to/exe"'
    'StartDir': str,        # Working dir in quotes
    'icon': str,            # Icon path (optional)
    'ShortcutPath': str,    # Usually empty
    'LaunchOptions': str,   # Command line args
    'IsHidden': int,        # 0 or 1
    'AllowDesktopConfig': int,
    'AllowOverlay': int,
    'OpenVR': int,
    'Devkit': int,
    'DevkitGameID': str,
    'DevkitOverrideAppID': int,
    'LastPlayTime': int,    # Unix timestamp
    'FlatpakAppID': str,
    'tags': {}              # Nested object for categories
}

Text VDF Format (config.vdf)

Steam's main config uses text VDF format - key-value pairs with tabs.

Proton Compatibility Tool Mapping

Located in config.vdf under CompatToolMapping:

"CompatToolMapping"
{
    "APP_ID"
    {
        "name"      "proton_experimental"
        "config"    ""
        "priority"  "250"
    }
}

Adding Proton Mapping

def add_compat_tool_mapping(app_id, tool="proton_experimental"):
    config_path = STEAM_ROOT / "config/config.vdf"
    with open(config_path, 'r') as f:
        content = f.read()

    # Check if already exists in CompatToolMapping section
    compat_start = content.find('"CompatToolMapping"')
    if compat_start != -1:
        compat_section = content[compat_start:compat_start+5000]
        if f'"{app_id}"' in compat_section:
            return  # Already configured

    # Find insertion point after CompatToolMapping {
    pos = content.find('"CompatToolMapping"')
    brace_pos = content.find('{', pos)

    # Build entry (use chr(9) for tabs to avoid template issues)
    TAB = chr(9)
    NL = chr(10)
    entry = NL + TAB*5 + f'"{app_id}"' + NL
    entry += TAB*5 + '{' + NL
    entry += TAB*6 + '"name"' + TAB*2 + f'"{tool}"' + NL
    entry += TAB*6 + '"config"' + TAB*2 + '""' + NL
    entry += TAB*6 + '"priority"' + TAB*2 + '"250"' + NL
    entry += TAB*5 + '}'

    new_content = content[:brace_pos+1] + entry + content[brace_pos+1:]
    with open(config_path, 'w') as f:
        f.write(new_content)

Proton/Compatdata

Each game/shortcut has a Wine prefix in compatdata:

~/.local/share/Steam/steamapps/compatdata/{APP_ID}/
├── pfx/                    # Wine prefix root
│   └── drive_c/           # C: drive
│       ├── Program Files/
│       ├── Program Files (x86)/
│       └── users/steamuser/
├── version                 # Proton version used
└── config_info            # Configuration metadata

Finding a Game's Prefix

def find_game_prefix(game_name_pattern):
    """Find compatdata prefix containing a specific game/app."""
    for lib in get_steam_libraries():
        compatdata = lib / "steamapps/compatdata"
        if not compatdata.exists():
            continue
        for prefix in compatdata.iterdir():
            # Check for the game in common Windows install locations
            for check_path in [
                prefix / "pfx/drive_c/Program Files" / game_name_pattern,
                prefix / "pfx/drive_c/Program Files (x86)" / game_name_pattern,
            ]:
                if check_path.exists():
                    return prefix
    return None

Sharing Prefixes Between Shortcuts

To make a shortcut use an existing prefix (e.g., for Battle.net games):

LaunchOptions: STEAM_COMPAT_DATA_PATH="/path/to/compatdata/APP_ID" %command% [args]

Proton Versions

Common Proton tool IDs:

  • proton_experimental - Proton Experimental
  • proton_10 - Proton 10.0
  • proton_9 - Proton 9.0

Proton locations:

{LIBRARY}/steamapps/common/Proton - Experimental/proton
{LIBRARY}/steamapps/common/Proton 10.0/proton

Launching Games

Via Steam Protocol

steam steam://rungameid/{APP_ID}
xdg-open steam://rungameid/{APP_ID}

Via Command Line

steam -applaunch {APP_ID}

Note: These require Steam to be running and may not work reliably for non-Steam shortcuts.

Modifying LaunchOptions in shortcuts.vdf

To modify launch options for a non-Steam shortcut programmatically:

import shutil
from pathlib import Path

vdf_path = Path.home() / ".local/share/Steam/userdata/{USER_ID}/config/shortcuts.vdf"

# Always backup first
shutil.copy2(vdf_path, str(vdf_path) + '.bak')

with open(vdf_path, 'rb') as f:
    data = f.read()

# Find LaunchOptions field (binary format: \x01LaunchOptions\x00value\x00)
launch_options_marker = b'\x01LaunchOptions\x00'
pos = data.find(launch_options_marker)

if pos != -1:
    value_start = pos + len(launch_options_marker)
    value_end = data.find(b'\x00', value_start)

    # Replace with new value
    new_options = b'PROTON_NVIDIA_LIBS_NO_32BIT=1 %command%'
    new_data = data[:value_start] + new_options + data[value_end:]

    with open(vdf_path, 'wb') as f:
        f.write(new_data)

Common Launch Options

RTX 4000+ performance fix:

PROTON_NVIDIA_LIBS_NO_32BIT=1 %command%

Disable FSYNC (fallback to ESYNC):

PROTON_NO_FSYNC=1 %command%

Force specific Proton prefix:

STEAM_COMPAT_DATA_PATH="/path/to/compatdata/APP_ID" %command%

Troubleshooting

Steam/Proton Won't Launch - "User namespaces" or Mount Errors

Symptoms: Steam fails to start with errors like:

  • bwrap: Can't bind mount /oldroot/ on /newroot/: Unable to apply mount flags
  • Steam now requires user namespaces to be enabled
  • Proton games silently fail to launch

Cause: Steam's pressure-vessel container (bubblewrap) tries to bind-mount ALL existing mount points. If any mount is stale or unavailable (e.g., network share with x-systemd.automount when the server is offline), the entire container fails.

Diagnosis:

# Check for problematic mounts
mount | grep -E "autofs|cifs|nfs"
ls -la /mnt/  # Look for entries showing "?" (stale mounts)

Fix:

# Find the problematic fstab entry
grep -E "automount|cifs|nfs" /etc/fstab

# Comment out unavailable automount entries
sudo sed -i 's|^//server/share|#//server/share|' /etc/fstab
sudo systemctl daemon-reload
sudo systemctl stop mnt-sharename.automount  # Replace with actual unit name

Prevention: For network shares that may be unavailable, consider:

  • Using x-systemd.automount with x-systemd.mount-timeout=5 to fail faster
  • Mounting on-demand via a script instead of fstab automount
  • Using nofail option (though this doesn't help with automount)

Important Notes

  1. Close Steam before modifying config files - Steam may overwrite changes
  2. Restart Steam after changes - New shortcuts won't appear until restart
  3. App IDs for shortcuts - Must use the CRC32-based generation algorithm
  4. Quote paths in Exe/StartDir - Always wrap paths in double quotes
  5. Template escaping - When using in chezmoi templates, avoid \n, \t, use chr() instead
  6. Binary VDF backups - Always backup shortcuts.vdf before modifying