Some titles never show up in a Steam/Lutris/Heroic scan — standalone mod
launchers like SPT (Single-Player Tarkov), itch.io downloads, hand-installed
executables. Add a user-authored custom-games list (core/customgames.py) shown
alongside the other sources in `rigdoctor games` and the GUI.
Each entry can carry a launch command and a log directory:
- `rigdoctor games add "SPT" --command .../tarkov.sh` (logs/ auto-detected)
- `rigdoctor games play "SPT"` launches it under the crash-capture wrapper
(wrap.run gains an explicit game-name override, since there's no SteamAppId)
- the diagnostic now feeds the game's own logs to the analysis: gamelogs
.collect(game=...) tails the registered log dir (SPT's server/launcher logs)
alongside the kernel log, freshness-scoped by mtime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The kernel-log scanner only caught Xid codes, OOM, panic, MCE, AER, thermal,
and amdgpu resets — so a hard freeze that logs NO Xid slipped through entirely.
Add detection for the NVIDIA open-kernel-module VA-space mapping fault
(gpu_vaspace.c / dmaAllocMapping / NVKMS GEM-allocation failures), which can
storm for minutes and end in a freeze without the GPU ever "falling off the
bus". Also flag when the open kernel module (nvidia-*-open) is loaded — the
context behind these faults — and add an AI-knowledge entry so the assistant
distinguishes it from the Xid 79 hardware drop.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Games page gains an "Import crash dump…" button (shown when an AI provider
is configured) that parses a Proton/Wine minidump and explains it via the
opt-in AI assistant. New stdlib core/minidump.py reads the MDMP streams
(crash reason, faulting module, OS/CPU, module list), optionally enriched
by minidump_stackwalk if installed. Adds ai_knowledge facts for exception
codes + faulting-module signatures, a MinidumpDialog, and CLI parity via
`rigdoctor ai dump <file>`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inventory shows configured RAM speed + the rated speed when lower
('4800 MT/s (rated 5600)'); System Health flags it with the fix (enable
XMP/EXPO in BIOS). With the profile off dmidecode only reports the JEDEC base,
so the rated speed comes from dmidecode's max OR the part number, matched against
known DDR5 speed grades to avoid false positives. inventory.module_speed() shared
by both; needs dmidecode (root/launch elevation). +tests (incl. the user's
CMK..5600 kit → (4800, 5600)). Completes the underperforming-hardware trio with
PCIe gen + refresh rate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New core/displays.py reads connected monitors via GNOME Mutter DisplayConfig over
D-Bus (busctl --json; works on X11 + Wayland), falling back to xrandr on other X11
desktops. Inventory's Display section now lists each monitor's resolution + current
refresh (e.g. 'DP-1 · Samsung LC34G55T: 3440x1440 @ 165 Hz'). System Health
(check_displays) flags a monitor running below its max refresh AT THE CURRENT
resolution (e.g. 165 Hz panel set to 60 Hz) — never suggests lowering resolution.
+tests (Mutter JSON + xrandr parsers, health check).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
check_pcie_links() warns when an NVMe drive negotiates fewer lanes than it
supports — almost always motherboard lane-sharing (a GPU/second card or another
M.2 stealing lanes), the case the user asked about — and reports speed-only
reductions as info (slower slot / idle ASPM). GPU is excluded: NVIDIA drops its
PCIe gen+width at idle, so a snapshot would false-alarm. Reuses inventory
read_link/nvme_controllers (refactored to public). Wired into run_health_checks;
+tests. Folded into the 0.38.0 PCIe work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each NVMe drive's Inventory entry now shows its negotiated PCIe link (e.g.
'· PCIe Gen4 x4') from sysfs (current/max link speed+width), and flags drives
running below their capability ('Gen3 x4 (capable of Gen4 x4)') — so you can
confirm a Gen4 SSD is in a Gen4 slot. SATA disks show no PCIe link. Renders in
the GUI Inventory, CLI, and the Markdown/JSON export automatically. +tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds assets/screenshots/{dashboard,inventory,share}.png and a Screenshots section
(Dashboard + Inventory side by side, Share below).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rigdoctor update assumed a pip/venv install and ran 'python -m pip install', which
fails on a .deb (system python has no pip; you can't pip-upgrade a dpkg package).
Add updates.install_kind() (dpkg ownership / venv / source-checkout detection,
cached) and route apply_update: pip self-updates in place; apt and source installs
return guidance instead. CLI and the GUI Update button show the apt/git command.
Adds tests/test_updates.py.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap each page (except self-scrolling Dashboard/Health/Inventory and the Share
terminal) in a QScrollArea, so long pages scroll when too tall (Settings'
Uninstall is reachable again) and the window is no longer pinned to the tallest
page's height — min height drops from >screen to ~600px, so it can be resized
smaller. Add a bottom footer showing 'RigDoctor v<version>' bottom-right (moved
out of the sidebar); themed #Footer with a top border.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Registry is public now: drop the token/auth.conf.d, use the signed-by one-line
source with arch=all so apt doesn't emit 'doesn't support architecture amd64'
notices (our package is Architecture: all). Drop the curl|sh bootstrap idea.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
REQUIRE_SIGNIN_VIEW is off and the repo is public, so anonymous apt works. The
apt instructions no longer need a read:package token or auth.conf.d — just the
signing key + a deb822 Signed-By source.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rigdoctor gui suggested 'apt install python3-pyside6' (no such package on
Debian/Ubuntu). Point to the split modules instead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the trusted=yes apt instructions with the proper method: read:package
token, registry signing key dearmored into /etc/apt/keyrings, credentials in
auth.conf.d, and a modern deb822 .sources file with Signed-By + Architectures:
all. Keeps the trusted=yes one-liner as a noted fallback for unsigned registries.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The old Recommends named python3-pyside6 (no such package on Debian/Ubuntu —
PySide6 is split per module), so apt skipped it and the GUI couldn't start.
Now Recommends the real modules (python3-pyside6.qt{widgets,gui,websockets,svg}
+ python3-pyte) AND the optional diagnostic/gaming tools (smartmontools,
lm-sensors, dmidecode, pciutils, libnotify-bin, libsecret-tools, gamemode,
mangohud), so 'apt install rigdoctor' sets up the whole toolset automatically —
no manual installs. cpupower -> Suggests. Verified all candidates resolve in apt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lead with what RigDoctor does, then install (.deb/apt incl. the private-registry
auth.conf.d + trusted=yes notes, and the .run), then usage (GUI/tray/CLI),
requirements, and privacy. Move the dev content (from-source, tests, docs links)
into a short Development section at the end. Drops the stale status/decisions/
repo-layout planning sections from the top.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gitea's Debian registry is immutable, so re-uploading an existing version returns
409. With --fail that aborted the release on any re-run / repeat push at the same
version. Now we capture the HTTP code: 2xx = uploaded, 409 = already published
(skip), anything else = fail with the body. Also fixed the stale skip message
(REGISTRY_TOKEN, not PACKAGES_TOKEN).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
512x512 PNG (assets/avatar.png) rendered from assets/avatar.svg, matching the app
icon's gauge-ring + heartbeat motif on a dark gradient. Upload as the repo avatar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
packaging/make_deb.py builds rigdoctor_<ver>_all.deb (Architecture: all) via
dpkg-deb, no debhelper: Depends python3; Recommends python3-pyside6/pyte (GUI by
default, --no-install-recommends = CLI only). Installs the package, both
launchers, desktop entry + icon; postinst refreshes the desktop database.
release.yml builds it as a release asset and optionally pushes to the Gitea apt
registry (REGISTRY_TOKEN). Verified locally: valid .deb, packaged launcher runs
'rigdoctor --version'. Docs/README/ROADMAP/MODULES updated; M9 complete.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A branch with an open PR triggered both the push and pull_request events, running
every job twice. Trigger on pull_request only; pushes to main are already tested
by release.yml's `test` job. No version bump (CI config only).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlertMonitor now scans the kernel log (journalctl -k) every ~30s and fires
one-shot, cooldown-gated desktop alerts on critical events: NVIDIA Xid, OOM
kills, CPU machine-checks, PCIe AER, and disk I/O errors — so users are warned
the moment something goes wrong, not only on a temperature threshold. Disk I/O
errors come from the kernel log (no root needed, unlike smartctl). Edge/spam
protection reuses the existing cooldown model. syslogs.scan_critical() does the
matching; init seeds last-scan to "now" so old boot logs don't alert on launch.
Tests for the matcher + monitor gating/cooldown; Settings note updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- .gitea/workflows/tests.yml: run `unittest discover` on push + pull_request.
`core` job (stdlib install, GUI tests skip) is bulletproof; `gui-smoke` job
installs the GUI extra + offscreen Qt libs and runs the suite headless.
- release.yml: add a `test` job and `release: needs: test` so a push to main
can't publish if the tests fail.
No version bump — CI config only; nothing in the shipped app changed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>