Context
Batch of feature ideas proposed by Nexus user ElDiablo59 (18 May 2026). All seven are local mod-management features that stay within the Nexus API policy — no mod-page content surfaced in-app, no auto-update. Each was checked against the actual code on both main and nexus-compliant before writing this roadmap (feasibility study, "no assumptions").
Feature numbers below are written F1..F7 (not #1..#7) on purpose, to avoid GitHub auto-linking them to unrelated issues/PRs.
Strategy
- Build on
nexus-compliant first → PR → claude[bot] review + CI gates → re-review until approved → cherry-pick PR to main.
- Backend infra for all 7 is byte-identical across editions (verified empty
git diff main..nexus-compliant on every relevant backend file) → backend changes cherry-pick cleanly.
- Frontend host files diverge (
SettingsPage.tsx, GameDetailPage.tsx, DashboardPage.tsx, Sidebar.tsx, router/index.tsx, types/api.ts, hooks/queries.ts, hooks/mutations.ts) → those edits are applied manually per branch, never merged (dual-release rule).
- Scope: each feature ships complete in its PR (not MVP). The two research-heavy ones (F1 log formats, F4 framework version sources) get their deep technical investigation inside their own cycle.
- Policy: all 7 are local-only. The only network call across the set is F4's read-only Nexus version lookup, which reuses the already-shipped self-update pattern.
Order (by ROI / risk) and tracking
Each feature gets its own design spec (docs/superpowers/specs/) → implementation plan → PR before any code is written for it.
F7 — Reverse dependency warning
Goal: before disabling/uninstalling a mod, warn the user which installed mods declare it as a requirement.
Verified — already exists:
GET /api/v1/games/{game}/install/installed/{mod_id}/dependents returns the installed mods that require the target — routers/install.py:267-311.
- Schemas
DependentModOut / DependentsResult — schemas/install.py:127-135.
- Requirement data persisted in
NexusModRequirement (models/nexus.py:46), populated from the GraphQL modRequirements fragment via upsert_mod_requirements (services/nexus_helpers.py:149).
Verified — missing: zero references to dependents anywhere in frontend/src/. Toggle has no confirmation dialog; uninstall uses a generic ConfirmDialog. DisableConfirmDialog.tsx exposes a children slot for injecting a warning.
Acceptance criteria (full scope):
DependentsResult/DependentModOut added to types/api.ts; a useDependents query hook.
- Pre-uninstall and pre-disable(toggle) check, in both list and card views, listing dependent mods (name + "View on Nexus").
- Warning is overridable (confirm-to-proceed), not a hard block.
- Handle data completeness: if a requiring mod's requirements were never synced, the check can under-report — decide whether to fetch on-demand.
- Tests.
Open product decisions: warn-and-confirm vs hard-block; fetch missing requirement rows on-demand (API cost) vs cached-only.
F6 — Change / activity log
Goal: timestamped, scrollable history of meaningful actions (install, uninstall, enable, disable, update/download, deploy, undeploy).
Verified — building blocks:
DeployJournalEntry (models/install.py:67-77) is an exact structural precedent for an append-only timestamped log, read/processed at startup (main.py:56-63).
- Every action is a single service function that already emits the human-readable summary line the feature wants:
install_mod/uninstall_mod/toggle_mod (services/install_service.py:69/281/353, log lines ~:262/:349/:483), deploy/undeploy (services/vfs/deploy_service.py:439/227), create_and_start_download (services/download_service.py:40).
- New tables are auto-created by
create_db_and_tables() (database.py) — no column migration needed for a brand-new table.
Verified — missing: no structured/queryable action-history table exists (greenfield); today actions only hit unstructured rippermod.log.
Acceptance criteria (full scope):
ActivityLog model + a record_activity(...) helper called from all choke points.
- Captures action, target mod, detail (counts/version), timestamp, status (success/failed/partial).
- Read router (paginated, filterable by game) + schema.
- Frontend view (page or Settings tab) +
VirtualTable + query hook.
- Retention/pruning policy (don't grow unbounded).
- Undo where clean: enable⇄disable, deploy⇄undeploy, install→uninstall. Uninstall is not reversible (does
shutil.rmtree + session.delete) — surface as non-undoable.
- Tests.
Open product decisions: per-game vs app-wide view; new top-level page vs Settings tab; include endorse/track and the app-update download as logged actions?; retention policy; undo scope for v1.
F2 — Unified health / pre-launch check
Goal: one action that scans for the problems that most often break launch; optionally auto-runs on "Play".
Verified — building blocks:
- A real game launcher already exists: Tauri
launch_game (frontend/src-tauri/src/lib.rs:266) + handleLaunch with a pre-launch gate chain (frontend/src/pages/GameDetailPage.tsx:235,263) + Play button (:443). A health gate slots into handleLaunch.
- Conflicts engine is the sibling pattern to mirror (
services/conflicts/engine.py, routers/conflicts.py, ConflictsInbox.tsx).
Verified — signal availability:
- (a) missing/disabled requirements: computable —
InstalledMod.nexus_mod_id ↔ NexusModRequirement.required_mod_id + InstalledMod.disabled.
- (c) version mismatches: reuse
services/update_service.py + routers/updates.py.
- (d) incomplete/failed installs: no
status/failed flag on InstalledMod — use deployed=False on an enabled mod and/or detect_drift().missing > 0.
- (b) "wrong directory": NOT directly computable today — VFS drift reports link integrity (
missing/foreign), not layout correctness; needs new logic.
Acceptance criteria (full scope):
- Aggregator endpoint (e.g.
GET .../health) returning [{mod, problem_kind, severity, suggested_fix}] covering all four categories, including a concrete definition + implementation of the "wrong directory" check.
- Frontend health panel/widget (mirror
ConflictSummaryWidget/ConflictsInbox).
- Optional pre-launch gate wired into
handleLaunch (warn/abort).
- Tests.
Open product decisions: precise definition of "wrong directory" (foreign/untracked files vs empty layout-transform vs other); auto-run-on-Play default; block vs warn.
F3 — Diagnostics / support export
Goal: one-click bundle: app logs + full mod list (names, versions, enabled, load order) + app/system/game-version info.
Verified — building blocks:
- File-export precedent: profile export (
services/profile_service.py:289) + frontend save() + writeTextFile (ProfileManager.tsx). Tauri dialog/fs/opener plugins present on both branches.
- Data available: installed mods (
InstalledModOut), load order (modlist_service.get_modlist_view), game version (services/game_version.py:12), app logs at data_dir/logs/rippermod.log (+ rotations) (main.py:18-38).
Verified — gaps:
- Backend version is hardcoded/stale:
FastAPI(version="0.1.0") (main.py:118); __APP_VERSION__ is frontend-only.
PCSpecs capture is unwired — model + POST /settings/specs/capture exist (models/settings.py:15-26, routers/settings.py:79-85) but nothing calls them and the backend does not auto-detect specs.
- Binary
.zip write needs fs:allow-write-file (capability currently only grants fs:allow-write-text-file).
Acceptance criteria (full scope):
- Backend assembles a bundle (logs + a manifest with mods/versions/enabled/load-order + real app version + system specs incl. OS/CPU/RAM/GPU + game version).
- Secret redaction: the bundle must never contain the Nexus API key or any secret.
- Frontend export button + save dialog; capability addition if a
.zip is used.
- Real backend version injection (build/env) and a specs-capture path (psutil/platform + GPU source).
- Tests.
Open product decisions: .zip vs single JSON; specs source (server-side psutil vs frontend); how to inject the real backend version.
F5 — Save game backups
Goal: auto-copy CP2077 saves before a deploy (or other risky change); rolling retention; restore.
Verified — building blocks:
deploy() is the single composition entry point (services/vfs/deploy_service.py:439), reached from 3 call sites — one hook covers all deploys.
is_game_running guard (services/vfs/primitives.py:165); data_dir writability checked by /health/deep (main.py:164).
Verified — greenfield / caveats:
- The app does not know the save path today (it knows
install_path, not the Saved-Games dir). No Saved Games/CD Projekt reference anywhere.
- No real file-copy primitive exists — the whole VFS is hardlinks/junctions. A hardlink would not protect a save (shared inode → shared corruption); backups must be byte copies (
shutil.copy2/copytree).
- Profile export backs up mod lists, not save files.
Acceptance criteria (full scope):
- Save-path detection (Steam/GOG/Epic) + a user-overridable setting + fallback.
- Copy + rolling-retention service (real copies, configurable retention); restore + list + manual-backup endpoints.
- Pre-deploy hook (decide coverage for toggle/uninstall/undeploy too); failure policy.
- Frontend Settings card + restore confirmation.
- Tests.
Open product decisions: retention policy (count/size/age); storage location (data_dir/backups/<game>/<ts>); failure policy (best-effort vs abort-deploy); coverage scope; Steam Cloud / OneDrive-redirected Saved Games caveats.
F4 — Framework mod monitor
Goal: a panel showing install status + version of RED4ext, redscript, ArchiveXL, TweakXL, Codeware, and Cyber Engine Tweaks; highlight missing/disabled/outdated.
Verified — building blocks:
constants.py (CYBERPUNK_DEFAULT_PATHS) already enumerates each framework's directory.
find_untracked_files (services/vfs/untracked.py:14) is the only code path that sees files the app did not install (frameworks are often installed manually).
- Version-compare reuse:
useModSummary / mod_summary (routers/nexus.py:159) + is_newer_version (lib/version.ts) — essentially useAppUpdateCheck × 6.
NexusModRequirement.required_mod_id already records framework Nexus IDs (they appear as other mods' requirements) — useful for name→ID mapping.
Verified — greenfield / the hard part:
- No framework registry / known-ID concept exists (e.g.
ArchiveXL has 0 hits in source).
- Version detection is essentially absent —
installed_version is parsed from the Nexus filename and is empty for manually-installed frameworks. Reliable version detection requires reading each framework's own version from disk (sidecar file / DLL FileVersion / RED4ext logs) — per-framework reverse-engineering, no precedent.
Acceptance criteria (full scope):
- Framework registry: Nexus mod IDs + characteristic marker paths + a per-framework version source.
- Disk-based existence + own-version extraction for all 6, including manually-installed ones.
- Outdated detection via Nexus latest version.
- Endpoint
GET .../frameworks; frontend status widget.
- Tests.
Open product decisions: "disabled" semantics for manually-installed frameworks; per-framework version source (research item); panel placement (Dashboard vs GameDetail tab).
F1 — In-app mod error reader
Goal: after a game session, parse the logs the game/frameworks write (redscript compiler, RED4ext, ArchiveXL, TweakXL, CET — under r6/logs, red4ext/logs, etc.), surface load failures / compile errors / warnings, and attribute each to the responsible mod.
Verified — building blocks:
- Game dir is known (
Game.install_path, models/game.py); the standard log dirs sit under it by convention (derivable, though not currently tracked — absent from GAME_REGISTRY).
- Attribution mechanism exists:
InstalledModFile.relative_path + _build_file_to_mod_map (services/modlist_service.py:45). CET/REDmod report by mod folder name, so attribution also needs folder-name matching (InstalledMod.name/staging_dir).
Verified — greenfield / risk:
- Zero existing log-reading code (
r6/logs/red4ext/logs appear nowhere). Fully greenfield.
- Log formats are external, undocumented, and version-volatile — the main maintenance risk.
- No game-exit hook (only
is_game_running); the view parses whatever is on disk.
Acceptance criteria (full scope):
- Log discovery for all in-scope sources, derived from the install dir.
- Robust parsers per format (redscript, RED4ext, ArchiveXL, TweakXL, CET) with severity classification.
- Error model + mod attribution (path + folder-name).
- Frontend errors view + parse/refresh trigger.
- Tests against real log fixtures.
Open product decisions: which formats count as "complete"; parse trigger (manual refresh vs on window focus); fixture sourcing.
Generated from a code-verified feasibility study across main and nexus-compliant. Per-feature specs and plans will be linked here as each cycle starts.
Progress
Updated 2026-05-22. ✅ Roadmap complete — all 7 features (F1–F7) shipped to both editions, plus two perf follow-ups (health + install) off the event loop.
Context
Batch of feature ideas proposed by Nexus user ElDiablo59 (18 May 2026). All seven are local mod-management features that stay within the Nexus API policy — no mod-page content surfaced in-app, no auto-update. Each was checked against the actual code on both
mainandnexus-compliantbefore writing this roadmap (feasibility study, "no assumptions").Strategy
nexus-compliantfirst → PR →claude[bot]review + CI gates → re-review until approved → cherry-pick PR tomain.git diff main..nexus-complianton every relevant backend file) → backend changes cherry-pick cleanly.SettingsPage.tsx,GameDetailPage.tsx,DashboardPage.tsx,Sidebar.tsx,router/index.tsx,types/api.ts,hooks/queries.ts,hooks/mutations.ts) → those edits are applied manually per branch, never merged (dual-release rule).Order (by ROI / risk) and tracking
DeployJournalEntry; emit at existing choke points)Each feature gets its own design spec (
docs/superpowers/specs/) → implementation plan → PR before any code is written for it.F7 — Reverse dependency warning
Goal: before disabling/uninstalling a mod, warn the user which installed mods declare it as a requirement.
Verified — already exists:
GET /api/v1/games/{game}/install/installed/{mod_id}/dependentsreturns the installed mods that require the target —routers/install.py:267-311.DependentModOut/DependentsResult—schemas/install.py:127-135.NexusModRequirement(models/nexus.py:46), populated from the GraphQLmodRequirementsfragment viaupsert_mod_requirements(services/nexus_helpers.py:149).Verified — missing: zero references to
dependentsanywhere infrontend/src/. Toggle has no confirmation dialog; uninstall uses a genericConfirmDialog.DisableConfirmDialog.tsxexposes achildrenslot for injecting a warning.Acceptance criteria (full scope):
DependentsResult/DependentModOutadded totypes/api.ts; auseDependentsquery hook.Open product decisions: warn-and-confirm vs hard-block; fetch missing requirement rows on-demand (API cost) vs cached-only.
F6 — Change / activity log
Goal: timestamped, scrollable history of meaningful actions (install, uninstall, enable, disable, update/download, deploy, undeploy).
Verified — building blocks:
DeployJournalEntry(models/install.py:67-77) is an exact structural precedent for an append-only timestamped log, read/processed at startup (main.py:56-63).install_mod/uninstall_mod/toggle_mod(services/install_service.py:69/281/353, log lines ~:262/:349/:483),deploy/undeploy(services/vfs/deploy_service.py:439/227),create_and_start_download(services/download_service.py:40).create_db_and_tables()(database.py) — no column migration needed for a brand-new table.Verified — missing: no structured/queryable action-history table exists (greenfield); today actions only hit unstructured
rippermod.log.Acceptance criteria (full scope):
ActivityLogmodel + arecord_activity(...)helper called from all choke points.VirtualTable+ query hook.shutil.rmtree+session.delete) — surface as non-undoable.Open product decisions: per-game vs app-wide view; new top-level page vs Settings tab; include endorse/track and the app-update download as logged actions?; retention policy; undo scope for v1.
F2 — Unified health / pre-launch check
Goal: one action that scans for the problems that most often break launch; optionally auto-runs on "Play".
Verified — building blocks:
launch_game(frontend/src-tauri/src/lib.rs:266) +handleLaunchwith a pre-launch gate chain (frontend/src/pages/GameDetailPage.tsx:235,263) + Play button (:443). A health gate slots intohandleLaunch.services/conflicts/engine.py,routers/conflicts.py,ConflictsInbox.tsx).Verified — signal availability:
InstalledMod.nexus_mod_id ↔ NexusModRequirement.required_mod_id+InstalledMod.disabled.services/update_service.py+routers/updates.py.status/failedflag onInstalledMod— usedeployed=Falseon an enabled mod and/ordetect_drift().missing > 0.missing/foreign), not layout correctness; needs new logic.Acceptance criteria (full scope):
GET .../health) returning[{mod, problem_kind, severity, suggested_fix}]covering all four categories, including a concrete definition + implementation of the "wrong directory" check.ConflictSummaryWidget/ConflictsInbox).handleLaunch(warn/abort).Open product decisions: precise definition of "wrong directory" (foreign/untracked files vs empty layout-transform vs other); auto-run-on-Play default; block vs warn.
F3 — Diagnostics / support export
Goal: one-click bundle: app logs + full mod list (names, versions, enabled, load order) + app/system/game-version info.
Verified — building blocks:
services/profile_service.py:289) + frontendsave()+writeTextFile(ProfileManager.tsx). Tauridialog/fs/openerplugins present on both branches.InstalledModOut), load order (modlist_service.get_modlist_view), game version (services/game_version.py:12), app logs atdata_dir/logs/rippermod.log(+ rotations) (main.py:18-38).Verified — gaps:
FastAPI(version="0.1.0")(main.py:118);__APP_VERSION__is frontend-only.PCSpecscapture is unwired — model +POST /settings/specs/captureexist (models/settings.py:15-26,routers/settings.py:79-85) but nothing calls them and the backend does not auto-detect specs..zipwrite needsfs:allow-write-file(capability currently only grantsfs:allow-write-text-file).Acceptance criteria (full scope):
.zipis used.Open product decisions:
.zipvs single JSON; specs source (server-side psutil vs frontend); how to inject the real backend version.F5 — Save game backups
Goal: auto-copy CP2077 saves before a deploy (or other risky change); rolling retention; restore.
Verified — building blocks:
deploy()is the single composition entry point (services/vfs/deploy_service.py:439), reached from 3 call sites — one hook covers all deploys.is_game_runningguard (services/vfs/primitives.py:165);data_dirwritability checked by/health/deep(main.py:164).Verified — greenfield / caveats:
install_path, not the Saved-Games dir). NoSaved Games/CD Projektreference anywhere.shutil.copy2/copytree).Acceptance criteria (full scope):
Open product decisions: retention policy (count/size/age); storage location (
data_dir/backups/<game>/<ts>); failure policy (best-effort vs abort-deploy); coverage scope; Steam Cloud / OneDrive-redirectedSaved Gamescaveats.F4 — Framework mod monitor
Goal: a panel showing install status + version of RED4ext, redscript, ArchiveXL, TweakXL, Codeware, and Cyber Engine Tweaks; highlight missing/disabled/outdated.
Verified — building blocks:
constants.py(CYBERPUNK_DEFAULT_PATHS) already enumerates each framework's directory.find_untracked_files(services/vfs/untracked.py:14) is the only code path that sees files the app did not install (frameworks are often installed manually).useModSummary/mod_summary(routers/nexus.py:159) +is_newer_version(lib/version.ts) — essentiallyuseAppUpdateCheck× 6.NexusModRequirement.required_mod_idalready records framework Nexus IDs (they appear as other mods' requirements) — useful for name→ID mapping.Verified — greenfield / the hard part:
ArchiveXLhas 0 hits in source).installed_versionis parsed from the Nexus filename and is empty for manually-installed frameworks. Reliable version detection requires reading each framework's own version from disk (sidecar file / DLL FileVersion / RED4ext logs) — per-framework reverse-engineering, no precedent.Acceptance criteria (full scope):
GET .../frameworks; frontend status widget.Open product decisions: "disabled" semantics for manually-installed frameworks; per-framework version source (research item); panel placement (Dashboard vs GameDetail tab).
F1 — In-app mod error reader
Goal: after a game session, parse the logs the game/frameworks write (redscript compiler, RED4ext, ArchiveXL, TweakXL, CET — under
r6/logs,red4ext/logs, etc.), surface load failures / compile errors / warnings, and attribute each to the responsible mod.Verified — building blocks:
Game.install_path,models/game.py); the standard log dirs sit under it by convention (derivable, though not currently tracked — absent fromGAME_REGISTRY).InstalledModFile.relative_path+_build_file_to_mod_map(services/modlist_service.py:45). CET/REDmod report by mod folder name, so attribution also needs folder-name matching (InstalledMod.name/staging_dir).Verified — greenfield / risk:
r6/logs/red4ext/logsappear nowhere). Fully greenfield.is_game_running); the view parses whatever is on disk.Acceptance criteria (full scope):
Open product decisions: which formats count as "complete"; parse trigger (manual refresh vs on window focus); fixture sourcing.
Generated from a code-verified feasibility study across
mainandnexus-compliant. Per-feature specs and plans will be linked here as each cycle starts.Progress
Updated 2026-05-22. ✅ Roadmap complete — all 7 features (F1–F7) shipped to both editions, plus two
perffollow-ups (health + install) off the event loop.toggleModsrename, multi-file delete confirm): nexus feat(mods): warn about dependent mods before disabling or uninstalling #244 / fix(mods): also guard the select-all toggle path against breaking dependents #246 / fix(mods): confirm multi-file delete and clarify the toggle helper name #248 → main feat(mods): warn about dependent mods before disabling or uninstalling #245 / fix(mods): also guard the select-all toggle path against breaking dependents #247 / fix(mods): confirm multi-file delete and clarify the toggle helper name #249async defrule that caused it): nexus perf(health): run the blocking pre-launch scan off the event loop #256 → main perf(health): run the blocking pre-launch scan off the event loop #259