Goal: Get AlecaFrame — a Warframe companion app built on Overwolf — to actually read live in-game data (inventory, relics, missions, etc.) when Warframe runs on Linux through ** umu-launcher + Proton**,
withoutSteam.
What this achieves (verified working):
- ✅ AlecaFrame's data/tracking works— inventory and the rest populate from the live game. - ✅ A single command launches Warframe and auto-prepares AlecaFrame in the correct order. - ✅ It is self-healing and survives reboots, Overwolf self-updates, and AlecaFrame data updates. - ❌ The transparent in-game overlay (Ctrl+Tab) does NOT work under DXVK/Proton and almost certainly can't without upstream changes. You use AlecaFrame'sstandalone window instead. (Full technical reason below — it's a real wall, not a missing setting.)
This guide was largely written by AI (Opus 4.8).Every step was validated on a live system, but treat the Wine/Overwolf internals as "true as of the versions tested" (see[Versions]) and adapt paths to your setup. Nothing here modifies the game itself — it only adds launcher scripts, window rules, and a couple of harmless local files.
Contents: TL;DR · Prerequisites · Background · 1. ptrace_scope · 2. Scripts · 3. First-run seed · 4. Hide junk windows · 5. Daily use · Overlay limitation · Versions
- Warframe runs via umu-launcher + Proton (DXVK). Overwolf is a separate Windows app; it can only
read the game if it runs
inside the same Proton/pressure-vessel container as the game. - umu can re-enter that container: a second
umu-run
with thesame plusWINEPREFIX
+GAMEID
UMU_CONTAINER_NSENTER=1
andPROTON_VERB=runinprefix
"nsenters" into the running game container. - AlecaFrame's data does
not come from the EE.log — it comes from Overwolf'smemory scanner(gep_warframeext.dll
) reading the game's RAM. Three things must all be true for that to work:(Wine reads process memory viakernel.yama.ptrace_scope = 0
ptrace
).- The game must have
in Overwolf's<OOPO>True</OOPO>
GamesList
(otherwise, under DXVK, Overwolf's renderer-detection fails and it never loads the scanner). - AlecaFrame's data cache (
cachedData/json.7z
) must be present & match the remote MD5, or its .NET inithangs trying to re-download over Wine's TLS.
-
AlecaFrame must finish initializing before the game process starts (load order matters). - Two small launcher scripts automate all of this, including self-healing #3 on every launch.
-
Warframe already installed and working via umu-launcher + Proton (this guide does not cover installing Warframe itself). - Overwolf + AlecaFrame already installed into the same Warframe Proton prefix. Doing this on a non-Steam umu prefix is fiddly (the Overwolf web installer fails under Wine) — seeInstalling Overwolf into a Proton / umu-launcher prefixfor the working route, then install AlecaFrame from Overwolf's App Store. You should have launched Overwolf at least once so the
Overwolf/
folders andGamesList*.xml
exist in the prefix. curl
(orwget
),awk
,grep
,md5sum
on the host.- Passwordless
sudo
(or root) once, to set a sysctl. - A compositor/WM where you can add window rules (examples use Sway; adapt for yours).
Throughout, replace these with your values:
| Placeholder | Meaning |
|---|---|
WINEPREFIX |
|
Your Warframe Proton prefix, e.g. $HOME/Games/Warframe-Proton-Prefix |
|
GAMEID |
|
The umu game id you launch Warframe with, e.g. umu-warframe |
|
LAUNCHER_EXE |
|
Unix path to Warframe's Tools/Launcher.exe |
Inside a Proton prefix the user folder is
, so app data lives understeamuser
"$WINEPREFIX/drive_c/users/steamuser/AppData/Local/..."
. Use that, not your Linux username.
AlecaFrame is an Overwolf app. Overwolf can only see Warframe if it shares the game's
wine/Proton session (same wineserver
, same pressure-vessel mount/PID namespaces). A plain second
umu-run
builds its own container and is blind to the game.
umu-launcher solves this: launch a second umu-run
with the same WINEPREFIX and GAMEID and set
UMU_CONTAINER_NSENTER=1
PROTON_VERB=runinprefix
. umu then re-enters the existing container (you'll see "Re-entering container through bus …"). The injected Overwolf processes end up sharing the game's namespaces.
AlecaFrame's inventory/relics/etc. are not parsed from EE.log
. Overwolf's General Game Events Provider (GEP) loads a native plugin ** gep_warframeext.dll** that scans
Warframe.x64.exe
's
memory (ReadProcessMemory
/VirtualQueryEx
). Only the player name comes from
EE.log
.The GEP only loads that scanner if it knows the game's renderer or the game is flagged out-of-process-overlay (OOPO). Under DXVK, Overwolf's renderer detection returns ** Unknown**, so without OOPO the scanner is never loaded (GEP just logs
"Waiting for renderer.."). Setting
<OOPO>True</OOPO>
for Warframe forces the scanner to load — and, as a bonus, the renderer then
detects as D3D11. With it set you can confirm in the GEP log:
Warframe plugin loaded: {"status":"success"}
and "oopOverlay":true
.Under Wine/Proton, wineserver
performs ReadProcessMemory
using Linux ** ptrace** (
/proc/<pid>/mem
).
The scanner, the game, and wineserver
are siblingprocesses, so the kernel's Yama
restricted-ptrace(
ptrace_scope = 1
, the common default) blocks the cross-process reads and AlecaFrame shows no data. Setting
kernel.yama.ptrace_scope = 0
allows it.
Security note:ptrace_scope = 0
lowers system-wide ptrace hardening (any process of your user can read another's memory). That's a normal tradeoff on a single-user gaming desktop, but make the call for your threat model.= 1
will break the data feature.
On startup AlecaFrame's .NET client MD5-checks cachedData/json.7z
. If that archive is missing
(only the extracted json/
folder present), it logs
Got local data MD5: |==FILE-NOT-FOUND==|
and tries to re-download the data over HTTPS — which
hangs forever under Wine's TLS, pinning a CEF process near 100% CPU. AlecaFrame deletes/renews
json.7z
whenever the upstream data changes, so this recurs over time. Keep json.7z
present and matching the remote MD5 → it logs "no data download is needed" and initializes in ~25s. The script below self-heals this from the CDN.
If AlecaFrame (re)initializes after Warframe.x64.exe
is already running, it hits the hang in #4. So: start the launcher, inject + initialize AlecaFrame to "ready", then press Play.
sudo tee /etc/sysctl.d/50-alecaframe-ptrace.conf >/dev/null <<'EOF'
kernel.yama.ptrace_scope = 0
EOF
sudo sysctl --system
cat /proc/sys/kernel/yama/ptrace_scope # must print 0
Put both on your $PATH
(e.g. ~/.local/bin
) and chmod +x
them. Edit the CONFIG block at the top of each to match your prefix, game id, and launcher path.
#!/bin/sh
#
#
WINEPREFIX="$HOME/Games/Warframe-Proton-Prefix"
GAMEID="umu-warframe"
LAUNCHER_EXE="$HOME/Games/Warframe-Proton-Prefix/drive_c/users/steamuser/AppData/Local/Warframe/Downloaded/Public/Tools/Launcher.exe"
if [ -z "$NO_ALECA" ] && command -v alecaframe >/dev/null 2>&1; then
setsid alecaframe wait-prepare >/tmp/alecaframe-autostart.log 2>&1 &
fi
exec env \
WINEPREFIX="$WINEPREFIX" \
GAMEID="$GAMEID" \
STORE=none \
umu-run "$LAUNCHER_EXE" "$@"
Add
gamemoderun
beforeenv
if you use gamemode. Keep the umu knobs identical to thealecaframe
script (below) or umu computes a different prefix hash and won't re-enter the container.
#!/bin/sh
WINEPREFIX="$HOME/Games/Warframe-Proton-Prefix"
GAMEID="umu-warframe"
STORE="none"
OW_LAUNCHER='C:\Program Files (x86)\Overwolf\OverwolfLauncher.exe'
AF_EXTID="afmcagbpgggkpdkokjhjkllpegnadmkignlonpjm" # AlecaFrame's Overwolf extension id (stable)
WF_GAME_ID="89541" # Warframe's Overwolf game id (stable)
LOG="/tmp/alecaframe-overwolf.log"
OW_BASE="$WINEPREFIX/drive_c/users/steamuser/AppData/Local/Overwolf"
AF_BGLOG="$OW_BASE/Log/Apps/AlecaFrame/BackGround.html.log"
AF_DATA_CDN="https://cdn.alecaframe.com/warframeData"
gameslist_files() {
for d in "$OW_BASE" "$WINEPREFIX/drive_c/Program Files (x86)/Overwolf"/*/Resources; do
[ -d "$d" ] || continue
for f in "$d"/GamesList*.xml; do [ -f "$f" ] && printf '%s\n' "$f"; done
done
}
oopo_present_in() { # 0 if Warframe's block in $1 already has <OOPO>True</OOPO>
awk -v id="$WF_GAME_ID" '
/<GameInfo>/ { blk=""; isWF=0 }
{ blk=blk $0 ORS }
$0 ~ ("<ID>" id "</ID>") { isWF=1 }
/<\/GameInfo>/ { if (isWF && blk ~ /<OOPO>True<\/OOPO>/) found=1 }
END { exit(found?0:1) }' "$1" 2>/dev/null
}
ensure_oopo() {
gameslist_files | while IFS= read -r GL; do
oopo_present_in "$GL" && continue
cp -f "$GL" "$GL.bak.$(date +%Y%m%d-%H%M%S)" 2>/dev/null
awk -v id="$WF_GAME_ID" '
/<GameInfo>/ { isWF=0 }
$0 ~ ("<ID>" id "</ID>") { isWF=1 }
(isWF && /<\/GameInfo>/ && !done) { print " <OOPO>True</OOPO>"; done=1; isWF=0 }
{ print }' "$GL" > "$GL.tmp" 2>/dev/null && mv "$GL.tmp" "$GL"
oopo_present_in "$GL" && \
echo " (re-applied <OOPO>True</OOPO> to Warframe in $(basename "$GL") so data/inventory works)"
done
}
ensure_data_cache() {
tool=""
for t in curl wget; do command -v "$t" >/dev/null 2>&1 && { tool="$t"; break; }; done
[ -n "$tool" ] || return 0
for U in steamuser "$USER"; do
CD="$WINEPREFIX/drive_c/users/$U/AppData/Local/AlecaFrame/cachedData"
[ -d "$CD" ] || continue
want=""; [ -f "$CD/receivedMD5.txt" ] && want=$(awk '{print $1; exit}' "$CD/receivedMD5.txt" 2>/dev/null)
cur=""; [ -f "$CD/json.7z" ] && cur=$(md5sum "$CD/json.7z" 2>/dev/null | awk '{print $1}')
[ -n "$cur" ] && [ -n "$want" ] && [ "$cur" = "$want" ] && continue
if [ "$tool" = curl ]; then rmd5=$(curl -fsSL "$AF_DATA_CDN/json7z.md5" 2>/dev/null | awk '{print $1; exit}')
else rmd5=$(wget -qO- "$AF_DATA_CDN/json7z.md5" 2>/dev/null | awk '{print $1; exit}'); fi
[ -n "$rmd5" ] || continue
if [ -n "$cur" ] && [ "$cur" = "$rmd5" ]; then printf '%s json.7z\n' "$rmd5" > "$CD/receivedMD5.txt"; continue; fi
echo " (refreshing AlecaFrame data cache json.7z so init won't hang...)"
if [ "$tool" = curl ]; then curl -fsSL "$AF_DATA_CDN/json.7z" -o "$CD/json.7z.dl" 2>/dev/null
else wget -qO "$CD/json.7z.dl" "$AF_DATA_CDN/json.7z" 2>/dev/null; fi
got=$(md5sum "$CD/json.7z.dl" 2>/dev/null | awk '{print $1}')
if [ -n "$got" ] && [ "$got" = "$rmd5" ]; then
mv -f "$CD/json.7z.dl" "$CD/json.7z"; printf '%s json.7z\n' "$rmd5" > "$CD/receivedMD5.txt"
echo " (data cache ready: $rmd5)"
else rm -f "$CD/json.7z.dl"; echo " (WARN: could not refresh json.7z)"; fi
done
}
launcher_container_up() { ps -eo args 2>/dev/null | grep -E 'umu-run.*Launcher\.exe' | grep -qv grep; }
game_running() { ps -eo comm 2>/dev/null | grep -q 'Warframe.x64'; }
overwolf_running() { ps -eo args 2>/dev/null | grep -i 'OverwolfBrowser.exe' | grep -qv grep; }
inject() {
setsid nohup env \
WINEPREFIX="$WINEPREFIX" GAMEID="$GAMEID" STORE="$STORE" \
PROTON_VERB="runinprefix" UMU_CONTAINER_NSENTER=1 UMU_RUNTIME_UPDATE=0 \
umu-run "$@" </dev/null >"$LOG" 2>&1 &
}
wait_for_init() { # 0 once AlecaFrame reports success, 1 on timeout
secs="${1:-120}"; i=0
while [ "$i" -lt "$secs" ]; do
grep -q "Plugin initialization successful" "$AF_BGLOG" 2>/dev/null && return 0
game_running && echo "[alecaframe] WARNING: game started before AlecaFrame finished init (will hang). Don't press Play until READY."
i=$((i + 1)); sleep 1
done
return 1
}
do_prepare() {
if overwolf_running; then echo "Overwolf already running. For a clean start: alecaframe stop, then prepare."; return 0; fi
if ! launcher_container_up; then
echo "The Warframe LAUNCHER isn't running yet. Start it (e.g. 'NO_ALECA=1 warframe'),"
echo "stay on the launcher, then run 'alecaframe prepare' and wait for READY before Play."
return 1
fi
if game_running; then echo "Game already running; AlecaFrame can't init cleanly now. Close it and retry from the launcher."; return 1; fi
echo "Injecting Overwolf + AlecaFrame..."
ensure_oopo
ensure_data_cache
: > "$AF_BGLOG" 2>/dev/null || true # truncate so init-detection can't read a stale success line
inject "$OW_LAUNCHER"
echo "Waiting for Overwolf to come up..."
i=0; ow=0
while [ "$i" -lt 60 ]; do overwolf_running && { ow=1; break; }; i=$((i+1)); sleep 1; done
[ "$ow" -eq 1 ] || { echo "Overwolf did not start."; return 1; }
sleep 5
echo "Opening AlecaFrame (retrying until it starts)..."
started=0; try=0
while [ "$try" -lt 5 ]; do
try=$((try+1)); inject "$OW_LAUNCHER" -launchapp "$AF_EXTID"; j=0
while [ "$j" -lt 20 ]; do
grep -qE 'Plugin (early )?initialization (started|completed)|Starting plugin initialization|Plugin instantiated' "$AF_BGLOG" 2>/dev/null && { started=1; break; }
grep -q 'Plugin initialization successful' "$AF_BGLOG" 2>/dev/null && { started=1; break; }
j=$((j+1)); sleep 1
done
[ "$started" -eq 1 ] && break
echo " (didn't start on attempt $try; retrying...)"
done
[ "$started" -eq 1 ] || { echo "AlecaFrame would not start. Try: alecaframe stop, then prepare."; return 1; }
echo "Waiting for AlecaFrame to finish initializing (up to 120s)..."
if wait_for_init 120; then
echo; echo "==== READY — AlecaFrame initialized. You can now press PLAY in the launcher. ===="
return 0
fi
echo "AlecaFrame did NOT initialize in time. Check: tail -n 40 \"$AF_BGLOG\""
echo "If stuck at FILE-NOT-FOUND, the game likely started too early: alecaframe stop, close game, retry."
return 1
}
case "$1" in
stop)
echo "Stopping Overwolf/AlecaFrame (never touches the game)..."
PIDS=$(ps -eo pid,args 2>/dev/null | grep -i 'Overwolf' | grep -v grep | awk '{print $1}' | tr '\n' ' ')
[ -n "$PIDS" ] && { kill -TERM $PIDS 2>/dev/null; sleep 3; echo " stopped: $PIDS"; } || echo " (not running)"
;;
status)
launcher_container_up && echo "Launcher: RUNNING" || echo "Launcher: not running"
game_running && echo "Game: RUNNING" || echo "Game: not running"
overwolf_running && echo "Overwolf: RUNNING" || echo "Overwolf: not running"
;;
wait-prepare)
if overwolf_running && ! grep -q 'Plugin initialization successful' "$AF_BGLOG" 2>/dev/null; then
echo "[alecaframe] stale Overwolf detected; cleaning it first." >&2
PIDS=$(ps -eo pid,args 2>/dev/null | grep -i 'Overwolf' | grep -v grep | awk '{print $1}' | tr '\n' ' ')
[ -n "$PIDS" ] && { kill -TERM $PIDS 2>/dev/null; sleep 3; }
fi
i=0
while [ "$i" -lt 180 ]; do
game_running && { echo "[alecaframe] game already running before prepare; skipping." >&2; exit 0; }
launcher_container_up && { sleep 3; do_prepare; exit 0; }
i=$((i + 1)); sleep 1
done
;;
prepare|"") do_prepare ;;
*) echo "Usage: alecaframe [prepare|stop|status]"; exit 2 ;;
esac
The scripts self-heal both on every launch, but you can seed them once manually to confirm:
PREFIX="$HOME/Games/Warframe-Proton-Prefix" # your WINEPREFIX
OW="$PREFIX/drive_c/users/steamuser/AppData/Local/Overwolf"
CD="$PREFIX/drive_c/users/steamuser/AppData/Local/AlecaFrame/cachedData"
for GL in "$OW"/GamesList*.xml "$PREFIX/drive_c/Program Files (x86)/Overwolf"/*/Resources/GamesList*.xml; do
[ -f "$GL" ] || continue
awk '/<GameInfo>/{b="";w=0}{b=b $0 RS}/<ID>89541<\/ID>/{w=1}/<\/GameInfo>/{if(w&&b~/<OOPO>True<\/OOPO>/)k=1}
END{exit(k?0:1)}' "$GL" \
&& echo "OOPO ok : $GL" || echo "OOPO MISSING (run 'alecaframe prepare' to fix): $GL"
done
mkdir -p "$CD"
curl -fsSL https://cdn.alecaframe.com/warframeData/json.7z -o "$CD/json.7z"
curl -fsSL https://cdn.alecaframe.com/warframeData/json7z.md5 | awk '{print $1" json.7z"}' > "$CD/receivedMD5.txt"
md5sum "$CD/json.7z"; cat "$CD/receivedMD5.txt" # the two hashes must match
(Just running alecaframe prepare
once does all of the above automatically.)
Under Wine/Xwayland, several Overwolf/Wine windows show up as class steam_app_warframe
and are
useless or broken on Linux: the black out-of-process overlay surface (title ow overlay
), the
Quick Launcher, and Wine's tiny title-less explorer.exe /desktop
artifact. Hide them (Sway shown; translate the idea to your WM):
for_window [class="steam_app_warframe" title="^Overwolf$"] floating enable, move position 230 130
for_window [class="steam_app_warframe" title="^AlecaFrame$"] floating enable, move position 80 100
for_window [class="steam_app_warframe" title="^Overwolf Quick Launcher$"] floating enable, move scratchpad
for_window [class="steam_app_warframe" title="^ow overlay$"] floating enable, move scratchpad
for_window [class="steam_app_warframe" title="^$"] floating enable, move scratchpad
Reload your WM config. (title="^$"
catches the title-less Wine desktop window; the real Overwolf/ AlecaFrame/launcher/game windows all map with a title, and move-to-scratchpad is non-destructive.)
warframe # starts the launcher AND auto-prepares AlecaFrame
NO_ALECA=1 warframe # launch the game only
alecaframe stop # stop Overwolf/AlecaFrame without touching the game
Open AlecaFrame's standalone window (from the Overwolf client) on a second monitor for your data.
If something gets stuck, the reliable reset is:
alecaframe stop
WINEPREFIX="$HOME/Games/Warframe-Proton-Prefix" \
"$HOME/.local/share/umu/compatibilitytools/UMU-Latest/files/bin/wineserver" -k # adapt path to your Proton
rm -f "$HOME/Games/Warframe-Proton-Prefix/pfx.lock"
Symptom: pressing Ctrl+Tab shows a fully black surface over the game (and Overwolf's own
Settings
window is black too).
Root cause:
- Overwolf renders the overlay UI with
CEF (Chromium) off-screen, then hands the pixels to its compositor
ow-overlay.exe
as across-process D3D11 shared texture(NT-handle / keyed-mutex), optionally via** DirectComposition**. DXVK does not support cross-process D3D11 shared textures: its shared-resource table is per-process, so the texture created by CEF's GPU process can't be opened byow-overlay.exe
(D3D11Device::OpenSharedResourceGeneric: Handle not found
). DXVK also lacksCreateSwapChainForComposition
. CEF itself reportsshared texture compatibility: False
anddirect_composition: false
. Result: the pixels never reach the overlay surface → black.
Things that don't fix it (tested):
- Forcing only
ow-overlay.exe
ontowined3d(whichdoesimplement composition swapchains): it shares a folder with Overwolf's CEF browser, so CEF picks up wined3d too and renders broken; and a per-app WineDllOverride
ofdxgi/d3d11=builtin
can't beat DXVK because DXVK is installed by physically replacingsystem32\dxgi.dll
. Even if it loaded, the failure is also on the CEF-GPU side, so the handoff still breaks. - There's no Overwolf/CEF setting found to force a CPU/shared-memory overlay transport.
So the overlay needs upstream support (DXVK cross-process shared NT-handle textures, or an Overwolf CPU-copy overlay path). Until then: use the standalone window. Everything else works.
Non-fatal noise you can ignore: gamemodeauto: dlopen failed libgamemode.so
, occasional
worldState.php
404s (an upstream Warframe endpoint moved; only affects a world-timer panel),
Uninstall registry key not found
.
- umu-launcher +
UMU-Proton 10.0(Wine 10),** DXVK 2.5.1**. - Overwolf client
0.304.x
, AlecaFrame2.6.89
, GEP307.4.3
. - AMD GPU (RADV/amdgpu), Wayland (Sway). The data approach is GPU-agnostic; the overlay limitation is DXVK-wide, not vendor-specific.
Overwolf/AlecaFrame are third-party software; their internals can change and break these specifics. The general approach (container re-entry, OOPO, ptrace, data-cache, load order) should remain valid.