plugin-helper
plugin-helper is an early Python CLI for managing Beat Saber plugins in BSManager installs.
The first implementation focuses on safe local workflows:
- discover BSManager instances
- scan existing
Plugins/andLibs/files - read checked-in registry and per-version lockfiles
- generate a machine-readable install plan from local release assets
- apply exactly that plan and record install state
- uninstall only files recorded in install state
Default BSManager instance root:
/home/pleb/.local/share/BSManager/BSInstances
Default plugin-helper state directory:
$XDG_STATE_HOME/plugin-helper
If XDG_STATE_HOME is not set, the state directory defaults to:
~/.local/state/plugin-helper
Override the instance root with --instances-root,
PLUGIN_HELPER_INSTANCES_ROOT, or plugin-helper.local.toml. To search
multiple explicit roots, separate them with :.
Override the state directory with --state-dir, PLUGIN_HELPER_STATE_DIR, or
plugin-helper.local.toml.
Local Configuration
This checkout is intended to manage the local Linux BSManager install. If you also manage a Windows install, use a separate clone on that partition and point both clones at the same state directory only when you intentionally want one shared source of truth.
Copy the example config and adjust paths if needed:
cp plugin-helper.toml.example plugin-helper.local.toml
plugin-helper.local.toml is ignored by git and uses top-level fields:
instances_root = "~/.local/share/BSManager/BSInstances"
state_dir = "~/.local/state/plugin-helper"
For repo-local state, set:
state_dir = ".state"
For a shared Windows-partition state directory, set the same state_dir in both
clones, for example:
state_dir = "~/Windows/Users/pleb/ops/plugin-helper/.state"
CLI flags override environment variables, environment variables override local config, and local config overrides built-in defaults.
Commands
For normal use, run the Textual menu from the repo root:
PYTHONPATH=src python -m plugin_helper
That is equivalent to PYTHONPATH=src python -m plugin_helper menu when run
from an interactive terminal.
The menu reads plugin-helper.local.toml when present, shows each discovered
Beat Saber install with its resolved state directory, and lets you toggle
managed plugins with arrow keys and Space. In the plugin table, use d to
disable all currently enabled managed plugins and e to enable all currently
disabled managed plugins.
The individual subcommands are mostly for automation and debugging. If you use
them, pass --state-dir directly only when you intentionally want to override
the configured state directory for one command.
Install assets are currently expected to already exist locally, usually under:
<state-dir>/instances/<instance>/downloads/<plugin-id>/
Beat Saber Data Backups
backup-userdata copies the mounted Windows UserData folder and Beat Saber
Windows app data into the adjacent ../backups repo. With the Windows mount at
~/Windows, the helper infers Beat Saber's Windows app data as:
/home/pleb/Windows/Users/pleb/AppData/LocalLow/Hyperbolic Magnetism/Beat Saber
Example manual backup after mounting Windows:
PYTHONPATH=src python -m plugin_helper \
--instances-root /home/pleb/Windows/Users/pleb/BSManager/BSInstances \
backup-userdata \
--instance 1.44.1
By default the backup repo receives plain copied files under
../backups/beat-saber/UserData and ../backups/beat-saber/AppData, plus
../backups/beat-saber/backup-descriptor.json describing the source paths from
the latest backup run. Use
--appdata-path <path> if the Windows profile path ever differs, --no-appdata
for a UserData-only sync, or --backup-root <path> to choose a different
destination.
restore-userdata copies those backup trees back into a target instance. It
moves the current UserData and AppData trees aside first as
<name>.pre-restore-<timestamp> snapshots. On Linux BSManager installs,
AppData is restored into the BSManager SharedContent Proton prefix unless
--appdata-path is provided. If backup-descriptor.json is present, its
instance field must match --instance.
Example restore into the local Linux instance:
PYTHONPATH=src python -m plugin_helper \
--instances-root /home/pleb/.local/share/BSManager/BSInstances \
restore-userdata \
--instance 1.44.1
The backup intentionally omits bulky/generated data:
UserData/BeatLeader/ReplaysUserData/BeatLeader/ReplayerCacheUserData/BeatLeader/LeaderboardsCacheUserData/BeatLeader/ReplayHeadersCacheUserData/ScoreSaber/ReplaysUserData/BeatSaberPlus/CacheUserData/BeatSaverNotifier.jsonUserData/Accsaber/PlayerScoreCache.jsonUserData/NalulunaAvatars/cacheUserData/SongDetailsCache.protoAppData/com.unity.addressables*.log
Other large folders seen in the 1.44.1 UserData tree are
Custom Campaigns, SongCore, AssetBundleLoadingTools, NalulunaMenu, and
NalulunaSkybox. Those are not skipped by default because they can contain
custom content or non-obvious user choices rather than pure cache data.
Operational notes
- BSManager can inherit launch arguments configured in Steam for Beat Saber.
Check both places before debugging black screens or startup hangs. Duplicating
arguments such as
--no-yeet fpfccan make the game fail command-line parsing after BSIPA and plugins have already loaded. - BSIPA is managed as a first-class bootstrap phase. The
bootstrapcommand applies the lockedbsiparoot archive, runsIPA.exe -nthrough Proton, and records every bootstrap-relevant file under rootIPA.exe*,winhttp.dll,Libs/, andIPA/, including backups created during patching. - If an instance lockfile includes
bsipa, ordinary plugin plans require a recorded bootstrap state plus aLogs/_latest.logthat shows BSIPA startup. Usebootstrap-checkbefore planning a batch when you want a quick gate. - Use
docs/SMOKETEST.mdafter installing or removing a plugin batch. It documents the short Proton/BSManager launch loop, IPA log checks, and teardown commands. - The 1.44.1 migration tracker lives in
docs/notes/install-and-verify-plugins-1.44.1.md.