Repository navigation
The Helper
mpn.py sits in skills/madnesswright/scripts/. It needs Python 3.9 or newer and nothing else. The skills run it as python <madnesswright folder>/scripts/mpn.py; the commands below are run from a scratch folder as python mpn.py.
Every output on this page was printed by the mpn.py in the 0.1.1 release zip on Windows. The game folders it read were stand-ins built for the run. steam/ holds an app manifest for app 488860 and nothing else of Steam. game-data/ stands in for the game's LocalLow data folder. The mod folders are the repository's fixtures or small folders written for these pages. On Linux and macOS the paths in the output print with forward slashes.
python mpn.py --helpusage: mpn.py [-h] [--strict] [--data-dir DATA_DIR] [--steam STEAM]
{where,backup,check-mod,deploy,log,scene-lint} ...
MADNESS: Project Nexus modding helper (one JSON object out)
positional arguments:
{where,backup,check-mod,deploy,log,scene-lint}
options:
-h, --help show this help message and exit
--strict exit 1 when the result has errors
--data-dir DATA_DIR the game's LocalLow data folder (holds Mods/)
--steam STEAM Steam root folder
Exit code 0.
| Command | Does |
|---|---|
where |
finds the Steam install, build, branch, data and Mods folders, the mod log, the enabled list, Player.log and the build it ran, and the newest SceneTools and ModTools builds |
backup [--out DIR] |
zips the game's data folder (Getting started) |
check-mod <dir> |
lints a mod folder (Mods and MadCards) |
deploy <dir> [--force] |
checks the mod, then copies it into the Mods folder |
log [--lines N] |
the build, the enabled list, what loaded, and the problem lines and tail of mods.log and Player.log (Troubleshooting); --lines defaults to 30 |
scene-lint <scene.unity> [--project DIR] |
checks a SceneTools scene (Levels with SceneTools) |
- Each command prints one JSON object on stdout and exits 0, problems or not.
errorsholds what must be fixed,warningswhat to read, andnoteswhat to do next. -
--strictmakes a command exit 1 whenerrorsis not empty. It is an option ofmpn.pyitself, so it goes before the command name, like--data-dirand--steam. - An unexpected failure inside a command still prints one JSON object, with the exception's type and message in
errors. - A mistyped command line is the exception: Python's argument parser prints usage text to stderr and exits 2, with no JSON.
--strictafter the command name is one:
python mpn.py check-mod broken-mod --strictusage: mpn.py [-h] [--strict] [--data-dir DATA_DIR] [--steam STEAM]
{where,backup,check-mod,deploy,log,scene-lint} ...
mpn.py: error: unrecognized arguments: --strict
Exit code 2.
Without options, where looks for Steam in the places Steam installs to: on Windows the SteamPath registry value and Program Files (x86)\Steam; on macOS ~/Library/Application Support/Steam; on Linux ~/.steam/steam, ~/.local/share/Steam and the Flatpak folder. It reads each root's libraryfolders.vdf for further libraries, then appmanifest_488860.acf. The data folder is %USERPROFILE%\AppData\LocalLow\Gibbing Tree\Madness Project Nexus on Windows, or the same path inside the Proton prefix (steamapps/compatdata/488860/pfx/drive_c/users/steamuser/...) on Linux. --steam DIR and --data-dir DIR (or the MPN_DATA_DIR variable) override them. Not tested for these pages: the search itself, since every run passed both options.
On the public branch, after a launch of the release build:
python mpn.py --steam steam --data-dir game-data where{
"steam_roots": [
"steam"
],
"install": {
"fully_installed": true,
"download": null,
"library": "steam",
"manifest": "steam\\steamapps\\appmanifest_488860.acf",
"install_dir": "steam\\steamapps\\common\\Madness Project Nexus 2",
"build_id": "25615280",
"beta_key": "",
"last_updated": "2026-10-17",
"branch": "public (release)"
},
"data_dir": "game-data",
"data_dir_exists": true,
"mods_dir": "game-data\\Mods",
"mods": [],
"mods_log": null,
"enabled": null,
"player_log": "game-data\\Player.log",
"game_version": {
"status": "Release",
"version": "1.11.a",
"mods_allowed": false
},
"tool_outputs": {
"scenetools": {
"folder": "Madness Project Nexus SceneTools\\SceneObjs",
"exists": true,
"newest": [
{
"file": "arena_pg.sobj",
"modified": "2026-10-17T18:30:00"
}
]
},
"modtools": {
"folder": "Madness Project Nexus ModTools\\MadObjs",
"exists": false,
"newest": []
}
},
"notes": [
"Not on the releasebeta branch. As of 2026-10 official modding (Workshop, SceneTools, ModTools, Harmony) runs only on releasebeta; back up first (mpn.py backup), then Steam > Properties > Betas.",
"Player.log says the last launch ran a Release build (v1.11.a): the game loads mods only when this reads Beta. Relaunch after switching branch."
],
"errors": []
}
Exit code 0.
branch reads public (release) when Steam has no beta key, and both notes say what to do. last_updated is the manifest's date in UTC. fully_installed turns false, with a note and a download count, while Steam is still downloading. tool_outputs lists up to five of the newest builds in each tool's output folder, next to the game's data folder.
After switching to releasebeta, deploying a mod and launching once:
python mpn.py --steam steam --data-dir game-data where{
"steam_roots": [
"steam"
],
"install": {
"fully_installed": true,
"download": null,
"library": "steam",
"manifest": "steam\\steamapps\\appmanifest_488860.acf",
"install_dir": "steam\\steamapps\\common\\Madness Project Nexus 2",
"build_id": "25615280",
"beta_key": "releasebeta",
"last_updated": "2026-10-17",
"branch": "releasebeta"
},
"data_dir": "game-data",
"data_dir_exists": true,
"mods_dir": "game-data\\Mods",
"mods": [
"faster-reload",
"green-hank",
"old-mod"
],
"mods_log": "game-data\\Mods\\mods.log",
"enabled": {
"file": "game-data\\Mods\\enabled.txt",
"enabled": [
"green-hank",
"faster-reload"
]
},
"player_log": "game-data\\Player.log",
"game_version": {
"status": "Beta",
"version": "2.20.a",
"mods_allowed": true
},
"tool_outputs": {
"scenetools": {
"folder": "Madness Project Nexus SceneTools\\SceneObjs",
"exists": true,
"newest": [
{
"file": "arena_pg.sobj",
"modified": "2026-10-17T18:30:00"
}
]
},
"modtools": {
"folder": "Madness Project Nexus ModTools\\MadObjs",
"exists": false,
"newest": []
}
},
"notes": [],
"errors": []
}
Exit code 0.
deploy runs check-mod, then copies the folder into <data folder>/Mods/<folder name>:
python mpn.py --data-dir game-data deploy green-hank{
"mod": "<scratch>\\green-hank",
"errors": [],
"warnings": [],
"info": {
"name": "Tough Agents, Green Hank",
"cards": 2,
"card_files": 2,
"card_list": [
{
"file": "agents.txt",
"type": "Character",
"filename": "Nexus1_Agent",
"root": "Nexus1_Agent"
},
{
"file": "hank.json",
"type": "Character",
"filename": "Hank",
"root": "Hank"
}
],
"bundles": [],
"preview": false
},
"deployed": true,
"dest": "game-data\\Mods\\green-hank",
"next": "In game: gear icon (main menu, bottom left) > select the mod > ENABLED > Apply. Then run mpn.py log."
}
Exit code 0.
mod is printed as a full path (masked here as <scratch>). Deploying the same folder again is refused:
python mpn.py --data-dir game-data deploy green-hank{
"mod": "<scratch>\\green-hank",
"errors": [
"game-data\\Mods\\green-hank exists; pass --force to replace it"
],
"warnings": [],
"info": {
"name": "Tough Agents, Green Hank",
"cards": 2,
"card_files": 2,
"card_list": [
{
"file": "agents.txt",
"type": "Character",
"filename": "Nexus1_Agent",
"root": "Nexus1_Agent"
},
{
"file": "hank.json",
"type": "Character",
"filename": "Hank",
"root": "Hank"
}
],
"bundles": [],
"preview": false
},
"deployed": false
}
Exit code 0.
--force replaces the copy in Mods:
python mpn.py --data-dir game-data deploy green-hank --force{
"mod": "<scratch>\\green-hank",
"errors": [],
"warnings": [],
"info": {
"name": "Tough Agents, Green Hank",
"cards": 2,
"card_files": 2,
"card_list": [
{
"file": "agents.txt",
"type": "Character",
"filename": "Nexus1_Agent",
"root": "Nexus1_Agent"
},
{
"file": "hank.json",
"type": "Character",
"filename": "Hank",
"root": "Hank"
}
],
"bundles": [],
"preview": false
},
"deployed": true,
"dest": "game-data\\Mods\\green-hank",
"next": "In game: gear icon (main menu, bottom left) > select the mod > ENABLED > Apply. Then run mpn.py log."
}
Exit code 0.
A mod with errors is not copied:
python mpn.py --data-dir game-data deploy broken-mod{
"mod": "<scratch>\\broken-mod",
"errors": [
"info.txt: curly quotes found; the game parses this file as strict JSON, so use straight quotes (examples pasted from the Google Docs carry curly ones)",
"info.txt does not parse: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)",
"agents.json: not valid JSON (Illegal trailing comma before end of object: line 1 column 82 (char 81)). Standard .json must be strict; save shorthand as .txt",
"the mod has no MadCards, no .mobj/.sobj bundles and no assembly; it would do nothing",
"not deployed: fix the errors or pass --force"
],
"warnings": [],
"info": {
"cards": 0,
"card_files": 1,
"card_list": [],
"bundles": [],
"preview": false
},
"deployed": false
}
Exit code 0.
--force also deploys a mod that has errors, so use it only to replace a copy. If the folder you deploy is already the one inside Mods, deploy copies nothing and says so in note.
backup writes one zip, and deploy writes into the game's Mods folder. No other command writes anything, and none of them sends anything over the network.
This wiki describes madnesswright 0.1.5 (tag v0.1.5) and was last updated on 2026-10-21. The plugin is MIT licensed. Report problems in the issues. Download: madnesswright 0.1.5.
Using it
- Getting started
- Mods and MadCards
- Levels with SceneTools
- Assets and Harmony
- The helper
- Troubleshooting
- FAQ
The releases
Contributing
Elsewhere