Repository navigation
Releases: DeroXP/ghostshell
Release list
v2.9.9.8
GhostShell v2.9.9.8
User-facing error reporting. When something breaks, you now see what
broke and a one-click path to file it on GitHub.
⚠ What's new
Automatic error capture
Three classes of error now surface in a clear modal instead of disappearing
into the log buffer:
- Uncaught JavaScript exceptions — anything thrown by frontend code
that wasn't caught by atry/catchblock. - Unhandled promise rejections — async errors that nobody awaited.
- Server errors — when an API call returns HTTP 5xx (Flask hit an
unhandled exception in a route) or the backend isn't reachable at all.
Each surfaces as a modal:
┌──────────────────────────────────────────────────────────┐
│ ⚠ Server error │
│ │
│ ╭─────────────────────────────────────────────────╮ │
│ │ 500 on /api/gpu/oc/apply │ │
│ ╰─────────────────────────────────────────────────╯ │
│ │
│ ▸ Technical detail (click to expand) │
│ │
│ GhostShell hit an unexpected error. If this keeps │
│ happening, please report it so we can fix it — the │
│ report includes your hardware, recent logs, and the │
│ error detail above (no personal data beyond what's │
│ already in your file paths). │
│ │
│ [Dismiss] [Copy details] [Report on GitHub →] │
└──────────────────────────────────────────────────────────┘
One-click GitHub issue with pre-filled body
Clicking Report on GitHub opens your default browser with a new-issue
form on the GhostShell repo, body pre-populated with:
- The error kind, message, and stack/detail
- GhostShell version
- OS version + build
- GPU + CPU model
- Whether running as administrator
- The last 30 log lines
…so the report is actionable without you having to type anything except
"this is what I was doing when it crashed".
If the URL would exceed GitHub's ~7 KB limit (long stack traces), the body
gets truncated in the URL but the full body is also copied to your
clipboard automatically — paste it into the issue body once the form
opens.
Manual reporting
Open Settings → REPORT A PROBLEM anytime to file an issue without
needing GhostShell to actually error first. Useful for "this feature
behaves weirdly" reports that wouldn't trigger an exception.
Smart de-duping
If the same error fires repeatedly within 30 seconds, only the first one
shows the modal — no spam if a tight loop keeps tripping the same bug.
The first 1.5 seconds after page load are also suppressed, so transient
"backend not ready yet" hiccups don't generate spurious modals.
🔌 New endpoint
GET /api/diagnostics/snapshot — returns the bundled context attached to
each report:
{
"app": { "version", "name", "admin", "frozen" },
"os": { "platform", "release", "version", "build" },
"hardware": { "cpu", "gpu", "ram_gb", "drives" },
"gpu_oc": { "current_offsets", "live", "stock_baseline", "crash_state" },
"logs": [...last 80 entries...]
}Useful even outside of error reporting — power users / scripts can poll
this endpoint to programmatically check GhostShell's state.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.9 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After upgrading: nothing is visible until something errors. When it
does, you'll see the new modal. Or hit Settings → REPORT A PROBLEM
to test it manually.
v2.9.9.7
GhostShell v2.9.9.7
Two important changes that pave the road for the v3 development cycle.
🛡 Auto-OC now steps down on crash instead of giving up
Old behaviour: a single hard crash anywhere during Quick Tune killed the
entire session. If your card crashed at +600 MHz core but +550 had already
been verified stable, the +550 result was discarded and memory tuning never
ran.
New behaviour: on a hard crash (TDR / WebGL context loss / driver hang
/ pixel artifacts) the algorithm now:
- Records the crashing offset as the upper bound for the axis
- Locks the last-known-stable offset as the axis winner
- Waits 5 seconds for the GPU to recover from the TDR
- Re-applies the locked offset and runs a 15 s sanity probe
- Advances to the next axis if the sanity probe passes
- Aborts the entire session only if EVEN the last-stable offset crashes
during the sanity probe (genuinely unrecoverable)
So:
Old New
─── ───
+0 → stable +0 → stable
+50 → stable +50 → stable
+100→ stable +100→ stable
+150→ stable +150→ stable
+200→ CRASH +200→ CRASH
↓ wait 5 s, re-apply +150, sanity probe → stable
[STOP — done] [Lock core+150, advance to memory axis]
...continues with memory tuning at core+150...
If you hit "GPU crash at last-stable also crashes" — extremely rare but
possible if the driver got wedged — the whole session aborts cleanly with
a clear banner explaining what happened. No half-applied state.
This applies to Quick Tune in this release; Benchmark Tune already
walks each ladder step independently and only stops the current axis on a
crash, which is the same behaviour.
📡 Update channel filter
A new Update channel dropdown in Settings → AUTO-UPDATE:
-
Stable (default — what existing v2 users will be on after upgrading)
Only sees v2.x.x.x non-prerelease releases. v3 alpha / beta builds are
ignored even when their semver tag is higher. -
Insiders (opt-in only)
Sees everything, including v3 prereleases.
This matters because v3 is being built as a major architectural change
(new dashboard UI, Railway-backed cloud sync, per-game profiles, RTSS
overlay, CPU OC + UV, Adaptive Tuning, etc.). v3 alphas/betas will be
tagged as GitHub prereleases. Existing v2 users on Stable will not be
auto-upgraded into them — your install stays on v2 until v3 ships out of
beta. At that point the major >= 3 filter gets relaxed and Stable
users will be offered the v3 final.
If you want to follow v3 development as it happens, switch to Insiders in
Settings. You can switch back to Stable any time.
This release also belt-and-braces: even a v3 release that's accidentally
NOT marked prerelease will still be filtered out for Stable channel users
because of the major >= 3 rule. Multiple safety nets so a tag mistake
can't drag everyone into a beta.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.9 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After upgrading:
- If your auto-tune crashes mid-session, you'll see "Crash at core+X — GPU
recovering, will step down to last stable" in the log instead of "hard
crash detected — auto-tune stopped". - Open Settings → AUTO-UPDATE to see the new Update channel dropdown.
It's set to Stable by default — leave it there unless you want to
follow v3 betas.
👀 What's next
This is the last v2.9.x feature release. v3 development starts immediately
on a separate branch and will be tagged as v3.0.0-beta.1, v3.0.0-beta.2,
etc., as Insiders-channel prereleases. v2.x users will stay on this
branch and only see future v2.x bugfix releases (if any) until v3 final
ships.
v2.9.9.6
GhostShell v2.9.9.6
Two changes — auto-enable game mode on launch, and a much bigger game database.
🎮 Game mode now auto-enables on GhostShell boot
The game-detection monitor used to require you to click Start Monitoring
in the Profiles tab every time GhostShell launched. v2.9.9.6 turns that
into a one-line toggle in Settings → GAME MODE, ON by default:
☑ Auto-enable game mode at GhostShell launch
Starts the game-detection monitor automatically when GhostShell boots so
any game you launch afterwards gets the gaming profile applied.
How it works:
- Settings persist in
%APPDATA%\GhostShell\game_profiles_settings.json app.py.main()callsgame_profiles.auto_enable_on_boot_if_set()after
the boot-prep delay (60 s in autostart mode, 0 s in manual launch)- If the setting is on AND monitoring isn't already running → starts the
detection loop - Idempotent — won't restart if you've already started it manually
- Toggle off any time in Settings to go back to manual control
The Settings card also shows live status: whether monitoring is currently
running, what game (if any) is being tracked, and the size of the game
database.
📚 Game database expanded to ~830 entries
The database grew from ~470 to ~830 known game executables, adding
roughly 120 lines covering:
2024–2025 AAA / live-service:
Indiana Jones and the Great Circle, Avowed, S.T.A.L.K.E.R. 2,
Throne and Liberty, Once Human, Metaphor: ReFantazio, Silent Hill 2 (remake),
Monster Hunter Wilds, Skull and Bones, Star Wars Outlaws, Concord (RIP),
Atomic Heart
More FPS / shooters:
Crossfire / CrossfireX / CrossfireHD, Tarkov Arena, Delta Force,
Trepang2, Boundary, Selaco, Prodeus, Metro 2033/Last Light/Exodus, Red Dead 2,
GTA V (incl. FiveM), Saints Row series, Mafia, Watch Dogs 1/2/Legion,
Far Cry 3/4/5/6/New Dawn
Roguelite / indie picks:
Risk of Rain 1/2, Vampire Survivors, Enter the Gungeon, Slay the Spire,
Dead Cells, Binding of Isaac, Noita, Cult of the Lamb, Balatro, Brotato,
Backpack Battles, Peglin, DRG: Survivor
MMO:
Throne and Liberty, Black Desert, Albion Online, DDO, LotRO, Wakfu, Dofus,
SWTOR, Tibia, RuneScape (incl. RuneLite), EverQuest 1/2, FFXI, Blue Protocol
Racing sims (recent):
Le Mans Ultimate, Rennsport, EA WRC, CarX 2, Test Drive Unlimited Solar Crown
Sports:
NHL 23/24/25/26, TopSpin 2K25, Tony Hawk's Pro Skater 1+2,
EA Sports PGA Tour, Golf With Friends
Strategy + sims:
Victoria 3, Old World, AoS: Realms of Ruin, Heroes of Might and Magic 3 (HotA),
WARNO, Steel Division 2, Regiments, BattleTech, MechWarrior 5, MWO,
Tropico 5/6, KSP 1/2, Caves of Qud, Cogmind
Survival / sandbox:
Pacific Drive, Icarus, The Long Dark, SCUM, Stranded Deep, Craftopia,
Wuthering Waves, Tarisland, Aska
Horror:
Outlast 1/2 / Trials, Amnesia (all), Callisto Protocol, Dead Space (all),
The First Descendant
Fighting / brawler:
Killer Instinct, Skullgirls, KOF XV, Rivals of Aether 2, Samurai Shodown
Platformers / 3D adventure:
A Hat in Time, Sonic Frontiers / Generations / Shadow / Superstars,
Rayman series, Crash Bandicoot series, Spyro Reignited, SpongeBob
Open world / RPG:
ELEX 1/2, Gothic, Risen, Kingdoms of Amalur, Wo Long: Fallen Dynasty,
Nioh 1/2, Ghost of Yotei, Pentiment, Disco Elysium
Misc / streamer picks:
Schedule I, Drug Dealer Simulator, Goat Simulator 3, ULTRAKILL, DUSK,
Amid Evil, Cultic, Another Crab's Treasure
The full list of ~830 entries is in core/game_profiles.py:KNOWN_GAME_EXES.
If your favourite game isn't on the list, you can still add it manually in
the Profiles tab → Add Custom Game.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After upgrading, launch a game (~830 are detected automatically). The
gaming profile applies the moment GhostShell sees the .exe and reverts
when the game closes — no manual Start Monitoring click needed.
v2.9.9.5
GhostShell v2.9.9.5
Hotfix for the +25 MHz showed 0/0/0 problem from your last screenshot.
🐛 The exact bug
Your screenshot:
✓ Core +0 MHz — fps 4140.7 / 1%low 3704 / σ 1.7% / 67°C ← real data
✓ Core +25 MHz — fps 0 / 1%low 0 / σ 0% / 45°C ← FPS columns empty, temp real
Real temp (read from nvidia-smi by the backend) but zero FPS and zero
1%-low — meaning the WebGL stress submitted no measurable frames
during the +25 step.
Root cause: stopWebGLStress() was calling
WEBGL_lose_context.loseContext() after every step:
function stopWebGLStress(state) {
if (!state) return;
if (state.rafId) cancelAnimationFrame(state.rafId);
try {
var ext = state.gl.getExtension('WEBGL_lose_context');
if (ext) ext.loseContext(); // ← KILLED THE CONTEXT
} catch (e) {}
}For the first step that worked fine — context dies, GPU resources freed.
For the second step (and every subsequent one in benchmark mode), the
next startWebGLStress() called canvas.getContext('webgl') and got back
either null or a still-lost context. Either way no draws actually ran.
The temp came back fine because it's read by the Python backend via
nvidia-smi, which doesn't care about WebGL — but everything FPS-related
silently produced zero samples.
✨ The fix
stopWebGLStress now just cancels the rAF. The WebGL context stays
alive on the canvas across step transitions; the next step's call to
startWebGLStress reuses it, compiles fresh shaders into it, and runs
cleanly.
function stopWebGLStress(state) {
if (!state) return;
if (state.rafId) cancelAnimationFrame(state.rafId);
// No more loseContext() — was breaking every step after the first.
}What you'll see now
✓ Core +0 MHz ← fps 4141 / 1%low 3704 / σ 1.7% / 67°C
✓ Core +25 MHz ← fps 4192 / 1%low 3741 / σ 1.6% / 68°C
✓ Core +50 MHz ← fps 4249 / 1%low 3789 / σ 1.7% / 70°C
✓ Core +75 MHz ← fps 4301 / 1%low 3823 / σ 1.8% / 72°C
✓ Core +100 MHz ← fps 4358 / 1%low 3870 / σ 1.7% / 74°C
Real numbers on every row. Each step distinguishable so the benchmark
winner reflects actual performance differences.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
Re-run Benchmark Tune — every row should show real FPS now, not just
the first one.
v2.9.9.4
GhostShell v2.9.9.4
Hotfix for the 3 million FPS problem you spotted (and the +25 MHz row showing zero).
🐛 What was broken
Your screenshot showed:
✓ Core +0 MHz — fps 3072075.6 / 1%low 0 / σ 25% / 68°C ← bogus
✓ Core +25 MHz — fps 0 / 1%low 0 / σ 0% / 47°C ← stuck zero
Two root causes:
1. gl.finish() doesn't sync on Chromium
In v2.9.9.3 I used gl.finish() to block JS until the GPU finished a batch
of 32 draws. The WebGL spec says finish() MUST do that. In practice,
Chromium's WebGL backend (which WebView2 uses) returns from gl.finish()
immediately because GPU submission crosses a renderer / GPU-process
boundary asynchronously. Result: batch_time = ~0.001 ms, per-draw = ~0.0003 ms, FPS = 3 million.
2. The +25 MHz step had no time to settle
After applying a new offset, the GPU's boost curve takes a moment to
actually transition. The previous build only waited 1.5 s before starting
to record frames. If the previous step had been hammering at full power,
1.5 s wasn't enough — the new step started recording while the GPU was
still in a transition state, sometimes producing zero usable samples.
✨ The fix
gl.readPixels for guaranteed GPU sync
The reliable WebGL synchronization primitive is gl.readPixels() — it must
round-trip to the GPU and pull bytes back, which forces an actual sync that
even Chromium can't no-op. We now read a single pixel after each batch:
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, syncBuf);Cost is trivial (one pixel, 4 bytes). Effect: batch timing now reflects
true GPU work, not just submission overhead.
1-second warmup discard
The first 1 s of every step's frame samples is discarded. Cold-cache and
first-RAF outliers (browser still composing, GPU clock still ramping)
won't pollute the per-step average.
Sanity rejection of impossible per-draw values
Anything below 0.05 ms per draw or above 500 ms per draw gets dropped
on the JS side instead of recorded. A draw that fast means the sync
didn't actually sync; that slow means a hung frame. Either way it's not
a real measurement.
Belt-and-braces clamps
- Backend score formula now clamps
avg_fpsandmin_fpsto[0, 5000]
so a leaked bogus reading can't produce an infinite score. - Frontend results table also clamps the displayed FPS to
[0, 5000]so
the user never sees3072075.6even if everything else fails.
3-second settle delay between benchmark steps (was 1.5 s)
Combined with the 1 s WebGL warmup discard inside each step, that's 4 s
total between applying a new offset and recording the first frame sample.
Plenty of time for the boost curve to transition and the GPU to reach
steady state at the new clocks.
What you'll see now
✓ Core +0 MHz ← fps 580 / 1%low 540 / σ 1.2% / 51°C
✓ Core +25 MHz ← fps 595 / 1%low 558 / σ 1.1% / 53°C
✓ Core +50 MHz ← fps 612 / 1%low 575 / σ 1.0% / 56°C
✓ Core +75 MHz ← fps 624 / 1%low 583 / σ 1.1% / 58°C
Real, finite, monotonically-related-to-OC numbers, with each step
distinguishable from the next.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
Re-run Benchmark Tune — this time the FPS column will contain real
numbers and the picked winner will reflect actual measured performance.
v2.9.9.3
GhostShell v2.9.9.3
Hotfix for the Benchmark Tune FPS-cap problem you spotted.
🐛 What was wrong
Your screenshot showed Core +0 MHz — fps 244 / 1%low 244 / σ 0.1% / 48°C.
Every offset was reporting 244 FPS — which is exactly your monitor's
refresh rate (240 Hz + the overscan a vsync'd browser sees). Because every
candidate scored identically, the benchmark always picked +0 MHz (ties broke
toward the first candidate in the ladder).
Root cause: the WebGL stress loop counted requestAnimationFrame
callbacks as "frames", and rAF is vsync-locked. Even though we drew 4 GPU
passes per RAF, only one frame got counted per refresh tick. So the FPS
number was a measure of your monitor, not your GPU.
✨ The fix
Three changes to the WebGL stress loop:
1. Per-draw counting instead of per-RAF counting
- Before:
frameCount++once per RAF callback → max 244 FPS - After:
frameCount += BATCH_SIZE(32) per RAF → reports actual
draws-per-second, uncapped from refresh
2. Bigger batch + GPU sync for accurate timing
- 32 draws submitted per RAF callback (was 4)
gl.finish()once at end of batch — blocks JS until all 32 GPU draws
complete, so wall-clock timing reflects real GPU time- Per-draw frame time =
batch_time / BATCH_SIZE→ variance and 1%-low
calculations now have real per-draw resolution
3. Higher canvas internal resolution
- Before: 512 × 512 (262 K pixels) — too small for modern GPUs to
saturate, finished a draw in <1 ms - After: 1280 × 1280 (1.6 M pixels) — ~6.4× more fragment work per
draw. Combined with the heavy ray-march shader from v2.9.9.2, a single
draw now takes 1–4 ms on most cards, so a batch of 32 takes 32–128 ms
per RAF — well above the 16.6 ms vsync budget, guaranteeing GPU-bound
measurement.
4. Bigger frame-time ring buffer
- Before: 600 entries — at the new draw rate that was only ~0.6 s of
history, making the 1%-low metric noisy - After: 5000 entries — gives 5–25 s of history depending on GPU speed
What you'll see
For your RTX 5070 Ti the FPS numbers will now look something like:
[core_each] Core +0 MHz ← fps 580 / 1%low 540 / σ 1.2% / 51°C
[core_each] Core +25 MHz ← fps 595 / 1%low 558 / σ 1.1% / 53°C
[core_each] Core +50 MHz ← fps 612 / 1%low 575 / σ 1.0% / 56°C
[core_each] Core +75 MHz ← fps 624 / 1%low 583 / σ 1.1% / 58°C
[core_each] Core +100 MHz ← fps 638 / 1%low 596 / σ 1.0% / 60°C
...
Each row will be visibly different from the previous one (1–3 % per 25 MHz
on a typical card), so the highest-scoring offset can actually be picked
based on real performance differences instead of all candidates tying at
your monitor's refresh rate.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After upgrading, re-run Benchmark Tune. This time you'll see different
FPS numbers for each offset, and the winner will reflect the actual
best-performing setting — not the one that ties everyone else at your
monitor's refresh rate.
v2.9.9.2
GhostShell v2.9.9.2
Three significant fixes — manual sliders, benchmark stress shader, and GPU-crash recovery.
🎚 Manual sliders actually use the new max
In v2.9.9.1 the backend clamps were bumped to 950 / 4500 MHz, but a leftover line in the JS (coreSlider.max = 400; memSlider.max = 2000) was overwriting the HTML attribute back to the old defaults on every page load. So your sliders kept showing +400 / +2000.
Fix: the JS now reads limits.core_max_offset / limits.mem_max_offset from the /api/gpu/oc/capability response (newly exposed in this release) and applies them to the slider's max attribute. Sliders go to +950 / +4500 as intended.
🔥 Benchmark stress shader matches stress-test.py
The Benchmark Tune stress shader was a relatively cheap mandelbrot + noise loop — useful for crash detection but not load-equivalent to the reference stress-test.py script. Scores between GhostShell and the script weren't directly comparable.
v2.9.9.2 ports the shader verbatim from your stress-test.py reference:
- 18-iteration rotating noise loop (matrix rotations + sin/cos + hash-based noise per iter)
- 14-iteration fractal-fold loop (
q = abs(q) / dot(q, q + 0.7) - 0.6) pow(col, vec3(0.85))final tone-map- The 4×4 deterministic checksum block at the bottom-left is preserved on top so the pixel-correctness GPU-crash detector still works
This is roughly 6× the GPU work per pixel — your card will reach the same throttling / TDP / clock-dip behaviour it sees in the reference script, so scores are directly comparable.
🛡 GPU-crash detection + auto-recovery
You said "my GPU disconnects for a little bit or my screen just goes black for a little bit". The previous build would just mark that step "unstable" and march on to the next offset, often crashing the GPU again.
v2.9.9.2 turns crash recovery into a first-class system:
Detection signals (any one of these triggers)
| Signal | Where | Latency |
|---|---|---|
| WebGL context lost | Frontend webglcontextlost event |
< 50 ms |
| Pixel checksum mismatch (≥2 frames) | Frontend pixel readback | < 1 s |
| nvidia-smi non-response | Backend read_live_state() |
~5 s timeout |
| nvidia-smi gap > 5 s during probe | Backend watchdog | next probe tick |
| Driver TDR (nvlddmkm 153 / 4101) | Backend Event Log scan | every 5th tick |
What happens on detection
- Backend records the crash in
_crash_state(kind, offset, timestamp). emergency_reset_oc()fires immediately — best-effort all-paths reset:- VF curve → 0
- Sparse SetPstates20 graphics → 0
- Sparse SetPstates20 memory → 0
nvidia-smi -rgcand-rmcto clear any clock locks- Each step in its own try/except so a degraded NVAPI can't block the others
- Returns
ok: Trueif AT LEAST ONE path landed
- Frontend receives
kind=context_loss/hang/tdr/crashfrom the probe verdict and:- Hard-stops the auto-tune / benchmark loop (no more steps)
- Waits 4 seconds for the GPU to settle
- Pops a red "⚠ Auto-tune stopped" banner with the crashing offset and reason
- Belt-and-braces: the WebGL
webglcontextlostevent handler ALSO POSTs/api/gpu/oc/emergency-resetdirectly, so reset fires even if the probe-tick path is blocked.
After-the-fact recovery
When you come back to GhostShell after the screen has gone black and recovered, the page-load handler polls /api/gpu/oc/crash-state. If a crash happened in the last 10 minutes, you get a banner like:
⚠ Recent GPU crash detected
GPU recovered from a context_loss at core+275 / mem+1500 (47s ago).
NVAPI offsets were automatically reset to stock. Try a smaller offset next time.
New API endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/api/gpu/oc/emergency-reset |
POST | Best-effort, never-raises reset |
/api/gpu/oc/crash-state |
GET | Most recent crash record (for the UI banner) |
/api/gpu/oc/crash-state |
POST | Acknowledge / clear the recent crash |
How crash-recovery makes Benchmark Tune actually safe
Before v2.9.9.2, a Benchmark Tune session that crashed at core+225 would treat that as "unstable" and try core+250 next — guaranteed to crash again, possibly worse. Now the session stops immediately on crash, leaves the GPU at stock, and shows you the banner with the failing offset. Re-run with a lower core_max_offset if you keep hitting the same wall.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After upgrading:
- Manual OC sliders go to +950 / +4500 (no more 400/2000 cap)
- Benchmark Tune now uses the heavier ray-march shader from your reference script
- Any GPU crash during Quick Tune or Benchmark Tune triggers an immediate reset + a clear red banner — no more silently grinding through more bad offsets after a black screen
v2.9.9.1
GhostShell v2.9.9.1
Three small but visible changes to the GPU OC tools.
📈 Wider OC slider range (again)
The v2.9.9.0 limits (600 / 3000) were already a big jump from the original
400 / 2000. v2.9.9.1 pushes them further so the manual sliders never get in
the way for users on golden samples or sub-ambient cooling:
| Slider | v2.9.9.0 | v2.9.9.1 |
|---|---|---|
| Core | 0–600 MHz | 0–950 MHz |
| Memory | 0–3000 MHz | 0–4500 MHz |
These are absolute clamps in the backend too (MAX_CORE_OFFSET_MHZ /
MAX_MEM_OFFSET_MHZ). Realistically only LN2 / golden-die operators will
ever touch the top end, but the limit isn't there to second-guess them.
🐢 Benchmark Tune — proper deep-dive cadence
In v2.9.9.0, Benchmark Tune used the same coarse jumps as Quick Tune (50 MHz
core / 250 MHz mem, 23 s per step), so it finished in ~5–7 minutes and missed
the actual peak. That was wrong — Benchmark Tune is supposed to be the slow,
thorough mode that finds the offset with the best measured FPS.
v2.9.9.1 cadence:
| Knob | v2.9.9.0 | v2.9.9.1 |
|---|---|---|
| Core ladder step | 50 MHz | 25 MHz |
| Memory ladder step | 250 MHz | 100 MHz |
| Per-step duration | 23 s | 90 s (≈25 s warmup + 65 s measurement) |
| Final validation | 30 s | 120 s |
| Default core max | 300 MHz | 600 MHz (25 candidates) |
| Default memory max | 1500 MHz | 2500 MHz (26 candidates) |
| Total runtime | ~5–7 min | ~45–90 min depending on GPU stability |
Why 90-second per-step measurements: the score weights 1%-low FPS and
frametime σ heavily, and both of those metrics are noisy in short windows
— a 23 s sample regularly misclassifies "smoother" runs as "jittery". At
65 s of post-warmup measurement the std dev settles inside ±0.05 ms on a
stable GPU, which is enough resolution to actually distinguish between
adjacent 25 MHz offsets.
Why finer steps: Quick Tune jumps in 75 MHz core leaps because it only
needs to know "stable or not". Benchmark Tune is hunting for the best
performance, and the FPS curve doesn't always increase linearly — it
often peaks at +175 MHz and then drops at +200 MHz due to thermal /
voltage throttling. 25 MHz steps catch those local maxima that 50 MHz
steps would step right over.
Estimated runtime by scenario (all assume default ladder caps):
| GPU strength | Stable to | Steps until crash | Runtime |
|---|---|---|---|
| Conservative | +100 core, +800 mem | ~14 | ~25 min (under target — early crash stops the run) |
| Average | +200 core, +1500 mem | ~26 | ~42 min |
| Strong | +400 core, +2500 mem (full ladder) | 51 | ~80 min |
| Extreme (custom max) | +950 core, +3900 mem (full clamp) | 79 | ~122 min |
Most users will see 45–80 min, exactly the window you asked for.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After upgrading, the manual OC sliders will go all the way to +950 / +4500.
Benchmark Tune will read the new dialog text noting the 45-90 min runtime
and the smaller step sizes — start it before bed and check the results in
the morning.
v2.9.9.0
GhostShell v2.9.9.0
Big update: a brand-new Benchmark Tune auto-OC mode, faster startup, wider OC slider range, and a UI compaction pass.
✨ Two auto-OC modes
The Auto Overclock card now has two buttons:
Quick Tune (renamed, redesigned)
The familiar binary-search algorithm but with significantly tightened durations — same convergence guarantees, ~40 % faster overall:
| Phase | v2.9.8 | v2.9.9.0 |
|---|---|---|
| Jump steps | 18 s | 10 s |
| Refinement | 25 s | 15 s |
| Final validation | 60 s | 30 s |
| Total typical | 5–8 min | 3–5 min |
Crashes surface within ~8 s under heavy WebGL stress; the longer windows mostly burned time without finding new instability.
Benchmark Tune (NEW — what you asked for)
Quick Tune asks "how high can the GPU go before crashing?"
Benchmark Tune asks "which offset gives the best actual performance?"
These are different questions — pushing further isn't always faster (thermal throttle, voltage drops, driver-side caps).
How it works:
- Maxes the power limit first so TDP throttling doesn't skew measurements.
- Walks the CORE offset ladder
[0, 50, 100, 150, 200, 250, 300]MHz.
For each step:- Apply offset → 23 s WebGL benchmark
- Record
avg_fps,1%-low fps,frametime σ,max_temp - Compute a score using the same formula as the reference
stress-test.py:score = avg_fps × 100 + min_fps × 40 ← 1% lows weighted heavily − frametime_std × 20 ← variance penalised − thermal penalty - Crash → STOP this axis (anything higher will also crash)
- Picks the highest-scoring stable core offset as the winner.
- Repeats the same process for MEMORY with ladder
[0, 250, 500, 750, 1000, 1250, 1500]MHz, applied on top of the core winner. - Final 30 s validation pass with both winners.
- Saves the winning combo to your OC profile and applies it.
At the end, the UI shows a ranked table of every step tried, with the winner highlighted:
CORE LADDER RESULTS
Offset Score Avg FPS 1% Low FT σ ms Temp Stable
core+0 14820.3 118.4 87.1 0.42 67°C ✓
core+50 15412.1 121.7 91.2 0.39 68°C ✓
core+100 16104.5 127.3 96.5 0.36 71°C ✓
core+150 16221.0 129.1 97.8 0.41 74°C ✓ ← winner
core+200 15890.2 130.4 92.1 0.68 78°C ✓
core+250 0 0 0 0 62°C ✗ tdr
Total runtime: 5–7 minutes. Use it when you actually want the most-FPS-not-just-most-stable result.
📊 Other improvements
Wider OC slider ranges
- Core: was 0–400 MHz, now 0–600 MHz
- Memory: was 0–2000 MHz, now 0–3000 MHz
The old limits were conservative for older Pascal/Turing parts. Modern Ada/Blackwell + GDDR7 regularly take +500 MHz core and +2500 MHz mem.
Faster startup
time.sleep(0.5)after Flask thread → replaced with a port-poll loop that exits as soon as Flask actually accepts a connection. Saves ~400 ms.- First-paint API calls split: dashboard loads immediately; secondary widgets (notifier status, boot-prep poll) defer to the next animation frame so the UI feels snappier.
UI compaction
- Card padding tightened from 16 px → 12 px (vertical) and margin from 12 px → 10 px. Free ~30 px reduction on every tab without changing layouts.
- Profiles tab: "Active Game" merged into the Detection Engine card; the long "What Happens When a Game is Detected" explainer is now collapsed inside a
<details>block (click to expand). Saves ~200 px by default. - GPU tab: four narrow vendor cards collapsed into two wider ones. NVIDIA + Clean-Install in one card; AMD + driver tips in the other.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ to check immediately.
After install, head to GPU → Auto Overclock. The new Benchmark Tune button is right next to Quick Tune.
v2.9.8.0
GhostShell v2.9.8.0
Two small but visible changes.
🔢 4-component versioning (2.9.8.0)
Switching from MAJOR.MINOR.PATCH (2.9.7) to MAJOR.MINOR.PATCH.BUILD
(2.9.8.0). The 4-component scheme matches what most Windows apps and
GPU drivers use, gives us a dedicated build digit for hotfixes, and lines
up neatly with the NVIDIA driver versioning we display in the Settings
panel.
Comparison logic was hardened to handle the transition cleanly. Both
the app updater (updater._parse_version) and the GPU driver updater
(driver_updater._version_tuple) now always pad parsed versions to
exactly 4 components, so:
| Current | Latest | Result |
|---|---|---|
2.9.7 |
2.9.8.0 |
update available ✓ |
2.9.8 |
2.9.8.0 |
up to date — no false update ✓ |
2.9.8.0 |
2.9.8.0 |
up to date ✓ |
2.9.8.0 |
2.9.8.1 |
update available ✓ |
2.9.8.1 |
2.9.8.0 |
up to date — no downgrade ✓ |
Without the padding, Python's tuple comparison would treat (2,9,8) < (2,9,8,0) (shorter < longer with matching prefix), which would
incorrectly tell users on 2.9.8 that 2.9.8.0 is "newer".
All nine edge cases verified passing.
🧹 Network page UI compaction
The Network page used to render two separate cards stacked vertically:
LATENCY OPTIMIZATION
Disable Nagle's Algorithm, network throttling, Large Send Offload, adapter power management.
⬜ Disable IPv6
[APPLY ALL NETWORK TWEAKS] [PING TEST]ADVANCED NETWORK TWEAKS
Global TCP stack tuning (auto-tuning, RSS, RSC, heuristics, SYN retransmissions), …
[NETSH TCP STACK] [DISABLE NETBIOS/TEREDO] [ENABLE DOH] [GAME PORT QOS]
Two cards, two titles, two paragraphs of explainer, two .btn-groups —
for closely-related network knobs. v2.9.8.0 merges them into a single
Latency & Network Tweaks card with one description and one combined
button row. Saves ~80 px of vertical real estate and reads cleaner.
📦 Asset
| File | Description |
|---|---|
GhostShell.exe |
Standalone Windows 10 / 11 build (~22.8 MB). Runs as administrator. |
🔄 Upgrading
Auto-updater on v2.9.0+ will pick this up. Hit ⟳ in the title bar to
check immediately. After install you'll see the new compact Network
card and the version chip in the title bar will read v2.9.8.0.