steam-linux
This skill should be used when working with Steam on Linux - managing non-Steam game shortcuts, configuring Proton/Wine compatibility, parsing VDF files, or finding Steam paths and prefixes. MUST BE USED when user mentions Steam launch options, modifying shortcuts.vdf, Proton environment variables (PROTON_*, WINE*), Battle.net/Blizzard games on Linux, or RTX 4000+ performance fixes. ALSO USE when troubleshooting Proton/Wine game issues (black screen, game won't launch, launcher issues, CEF/Chromium rendering problems).
What this skill does
# 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
```python
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):
```python
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:
```python
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:
```python
{
'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
```python
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
```python
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
```bash
steam steam://rungameid/{APP_ID}
xdg-open steam://rungameid/{APP_ID}
```
### Via Command Line
```bash
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:
```python
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 fRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.