The pyghidra-mcp wrapper bakes in GHIDRA_INSTALL_DIR via makeWrapperArgs
referencing pkgs.ghidra, which makes ghidra a runtime closure dep.
Adding pkgs.ghidra explicitly to home.packages caused buildEnv to merge
*two* ghidra-12.0.4 store paths (one from pyghidra's propagatedBuildInputs,
one from the explicit list) and fail with a path collision on
GPL/DMG/LICENSE.txt.
Drop the explicit add. The agent-driven workflow doesn't need the GUI;
manual exploration via 'nix run nixpkgs#ghidra' is one command away if
ever wanted.
Adds two inline Python derivations to home/progs/pi.nix:
- ghidrecomp 0.5.9 (clearbluejar/ghidrecomp) — required by pyghidra-mcp,
not in nixpkgs.
- pyghidra-mcp 0.2.2 (clearbluejar/pyghidra-mcp) — headless MCP server
that exposes Ghidra's analysis primitives (decompile, disassemble,
list_strings, get_xrefs_to, etc.) over Model Context Protocol stdio.
The wrapper bakes in GHIDRA_INSTALL_DIR=${pkgs.ghidra}/lib/ghidra so
pyghidra discovers the Ghidra install at runtime without env munging.
Wires into OMP via:
- home.packages: pyghidra-mcp + pkgs.ghidra (GUI for occasional manual
exploration alongside the agent-driven flow).
- ~/.omp/agent/mcp.json: registers a 'ghidra' MCP server that spawns
pyghidra-mcp on stdio when any of its tools are invoked.
- ~/.omp/agent/skills/ghidra/SKILL.md: tells the agent when to reach
for Ghidra (static binary RE) vs. usbmon (dynamic capture) vs. the
built-in tools, and gives the canonical exploration workflow.
Replaces the previously-recommended LaurieWired/GhidraMCP, which has
been stale since June 2025. clearbluejar/pyghidra-mcp is actively
maintained (last commit 3 days ago), pure-Python via pyghidra+jpype, and
multi-binary capable in a single session.
Verified: pi.nix parses, the yarn NixOS closure evaluates, both
derivations build, and the wrapped binary's --help works (Ghidra runtime
discovered correctly via GHIDRA_INSTALL_DIR).
nixpkgs' proton-ge-bin (the package wired into programs.steam.extra-
CompatPackages via modules/desktop-steam.nix) registers in Steam's
compat-tool list under its versioned id, currently GE-Proton10-34.
steam-config-nix's README example uses the unversioned string
"GE-Proton", which on a fresh boot wrote that literal value into
localconfig.vdf — Steam resolved it to no installed tool and silently
fell back to bundled Proton 10. FH5 then launched on stock Proton,
which doesn't pick up PROTON_FSR4_UPGRADE the way GE does.
Drop both `compatTool` (per-app) and `defaultCompatTool` (global).
The wrapper-based launchOptions.env path is unaffected — env vars
still pass through to whatever Proton Steam ends up using. Tool
selection goes back to manual Steam UI > Properties > Compatibility.
A versioned pin (`compatTool = "GE-Proton10-34";`) would work but
couples the host config to whatever the proton-ge-bin nixpkgs entry
ships this week; not worth the maintenance.
Replaces three handfuls of custom code with upstream / static data:
- Per-app Steam launch options now declared via different-name/steam-
config-nix's `programs.steam.config.apps.<n>` instead of a custom
~70-line `apply_launch_options` Python function. The dropped writer
was racy: it edited localconfig.vdf without checking for a running
Steam, so any timer firing while Steam was open would lose its
changes on the next Steam shutdown. steam-config-nix's `closeSteam`
flag closes that race.
Also moves the GE-Proton compat-tool pin to declarative config —
one fewer manual click in Steam UI to remember.
- `mods.<>.launchOptions` option, the `launchOptionsData` aggregation,
and `LAUNCH_OPTIONS_DATA` are removed from desktop-game-mods.nix.
The module now does file-drops only; Steam config lives in its own
`programs.steam.config` namespace, where it belongs.
fh5-vkd3d-no-hvv (which existed only to set VKD3D_CONFIG) collapses
into the FH5 launchOptions block in hosts/yarn/default.nix.
- `unitConfig.X-ConfigHash` on game-mods.service is replaced with
`restartTriggers`. NixOS already emits `X-Restart-Triggers=<hash>`
on the unit; the workaround was redundant. The Type=oneshot,
RemainAfterExit=no semantics make `systemctl restart` re-run
ExecStart cleanly on hash change.
- The awk pipeline that patched OptiScaler's stock OptiScaler.ini at
build time is replaced with a hand-written hosts/yarn/optiscaler-
fh5-rdna3.ini containing only the keys we override (5 of them).
OptiScaler's Config::readString defaults missing keys to "auto"
(Config.cpp:1568), so a minimal file is sufficient. Side benefits:
one upstream-source dependency removed, a key-rename in upstream
becomes a behavior change rather than a silent awk-no-match.
Override values + sources:
Fsr4Update=true FH5 wiki, FSR4 Linux Setup
DlssReactiveMaskBias=0.65 FH5 wiki, "Known Issues"
FsrNonLinearColorSpace=true FSR4 wiki, "Image Quality"
EnableFsr2Inputs=false FH5 wiki, "Known Issues"
Dxgi=false FH5 wiki
- forza-trigger's three custom Python derivations (pydualsense,
hidapi-usb, fdp) factored out of default.nix into a sibling
python-packages.nix. Same logic, single-purpose file. Bumping a
version is now a one-place hash roll.
- pkgs.dualsensectl removed from the daemon's environment.system-
Packages. Single-shot writes from the CLI get clobbered by the BG
sendReport thread within ~4ms anyway, so the tool is only useful
with the daemon stopped — not worth the unconditional install.
Bring it in ad-hoc with `nix-shell -p dualsensectl`.
Three small follow-ups to 1751603:
- BACKUP_SUFFIX was lost during the launchOptions refactor. apply_mod
references it on every non-skip path (new target, drifted bytes, or
replace mode), so the moment a deployment hit one of those, the
service would NameError at runtime. The bug was latent on yarn
because every dropped file's bytes already matched its source, so
every apply short-circuited at the byte-match check; an empirical
rm libxell.dll + systemctl start reproduced the NameError before
the fix and showed a successful recreate after.
- Mention launchOptions in the leading file docstring. The Example
block already covers file ops; the new option had no entry-level
doc.
- Normalize blank lines between top-level Python defs in the heredoc
(PEP-8 wants exactly two: we had four between apply_mod and
apply_launch_options, zero between apply_launch_options and main).
Drops OptiScaler v0.9.1 + a FH5-tuned OptiScaler.ini into the FH5
install dir to unlock FSR 4 INT8 on this RDNA 3 (Navi 32) box.
OptiScaler intercepts FH5's DLSS/XeSS calls and reroutes them through
the bundled FFX SDK. Per the OptiScaler FH5 wiki page: rename
OptiScaler.dll to dxgi.dll, set Dxgi=false, DlssReactiveMaskBias=0.65,
and Fsr4Update=true for the INT8 RDNA 3 path.
Sets Steam launch options PROTON_FSR4_UPGRADE=1 and
DXIL_SPIRV_CONFIG=wmma_rdna3_workaround on fh5-optiscaler (the FSR 4
wiki documents both as required for RDNA 3 on Linux).
fh5-vkd3d-no-hvv is its own mod (no files, just one launchOptions
entry for VKD3D_CONFIG=no_upload_hvv) so the upload-hvv workaround
can be removed when a future Proton release fixes the underlying
issue without disturbing the OptiScaler config.
Extends the intro skip stub to cover the hires variant of the
T10/Microsoft Studios splash; the engine picks SD or hires based on
the installed asset profile, so stub both per PCGamingWiki.
stdenvNoCC + p7zip extraction; strips installer scripts and README,
keeps Licenses/. dontFixup since the artifacts are Windows DLLs.
meta.license is unfreeRedistributable to reflect the bundled XeSS
(Intel SLA) alongside the GPL-3.0 source.
Wires lib/overlays.nix into mkDesktopHost (was muffin-only) and adds
"optiscaler" to the unfree allowlist on jovian hosts so yarn can
consume it without flipping the global allowUnfree flag.
Three additions on top of the file-replacement scaffolding:
- mode = "init": create-on-first-apply, leave-alone-otherwise. For
files the application writes back to (configs edited in-game, save
files). Operator pushes a new template by deleting the target.
- chmod 644 after every copy. shutil.copy2 preserved the source's
/nix/store mode (0o444), which made dropped DLL configs read-only.
Apps that wrote back (OptiScaler "Save INI") got EACCES, which in
OptiScaler's case cascaded into CreateSwapChainForHwnd returning
E_FAIL and crashed FH5 on launch.
- launchOptions = listOf str. Multiple mods targeting the same
steamAppId have their lists concatenated (mod-name alphabetical),
joined with spaces, %command% appended once. Written into Steam's
per-app block in userdata/<id>/config/localconfig.vdf via vdf
parse + atomic os.replace. Idempotent.
- X-ConfigHash on the systemd unit so switch-to-configuration switch
re-runs apply when the manifest changes.