Files
2026-06-29 10:56:57 -07:00

5.8 KiB

plugin-helper Roadmap

This roadmap tracks ideas that are useful but not part of the first safe CLI slice.

Current Direction

The initial tool should stay conservative:

  • Python owns instance discovery, dry-run plans, activation, install state, uninstall, and UserData backups.
  • Release assets are selected through registry and lockfile data.
  • Prefer upstream GitHub release artifacts for normal plugins. Use BeatMods as compatibility/dependency metadata, and as an artifact source only for inaccessible upstream artifacts, BeatMods-only packages, or framework/library dependencies.
  • Mutating operations apply an explicit plan and record exact file hashes.
  • Nix packages plugin-helper, but does not directly manage the mutable Beat Saber tree.

This works well while Beat Saber is launched from either the local Linux BSManager install or a mounted Windows BSManager filesystem.

For the near term, the Python state model should treat target roots as distinct installations even when they share an instance name. Lockfiles can stay keyed by Beat Saber version, but bootstrap state, generated plans, backups, and installed.json need to stay target-specific.

Future: Nix-Orchestrated Plugin Sets

Once Beat Saber is running on Linux through Steam Proton, it may make sense to let Nix orchestrate the plugin payload itself.

The core idea:

Nix flake / plugin set
  fetch exact GitHub release assets
  verify hashes
  unpack and normalize Plugins/, Libs/, IPA/Pending/
  produce /nix/store/...-beatsaber-plugins-<game-version>/

plugin-helper
  run nix build .#pluginSets.<game-version>
  compare the resulting tree to the target Beat Saber instance
  create a normal dry-run plan
  copy or link files into the instance
  record activation state

In that model, the plugin folder effectively gets a reproducible lock:

  • flake.lock pins Nix inputs.
  • A plugin-set definition pins plugin repositories, tags, release assets, and hashes.
  • The generated Nix output is a canonical, immutable plugin tree for one Beat Saber version.
  • plugin-helper remains the safety layer around activation and rollback.

Why Wait For Proton

For the current dual-boot Windows path, a pure Nix-store plugin tree is awkward:

  • Windows cannot use /nix/store paths directly.
  • Linux symlinks inside a mounted Windows filesystem may not behave the way native Windows Beat Saber expects.
  • Some plugins may create or expect colocated mutable files.

When running through Proton on Linux, Nix-store outputs and symlink activation become much more practical. Even then, copy mode should remain available for plugins that expect writable colocated files.

Activation Modes

A future Nix-backed planner should support at least these activation modes:

  • copy: materialize files into the Beat Saber instance. Best compatibility, including mounted Windows trees.
  • symlink: link plugin files from the Nix output. Best reproducibility and cleanup on Linux/Proton.
  • materialize: link immutable files where safe and copy known-mutable files.

All modes should still produce the same kind of explicit plan before applying.

Proposed Milestones

  1. Keep the Python safety harness stable: scan, plan, apply, uninstall, and backups.
  2. Model BSIPA bootstrap as a first-class install phase, preferring upstream GitHub release artifacts while preserving BeatMods zipHash/version metadata when used for verification or fallback.
  3. Resolve BeatMods dependency closures by mod-version id for verified mods before ordinary batch planning, but keep artifact sourcing GitHub-preferred.
  4. Model one real plugin end to end with the current TOML lockfile and local asset planning.
  5. Add a Nix function that fetches and unpacks one locked plugin asset into a normalized tree.
  6. Generate a full plugin-set derivation for one Beat Saber version.
  7. Teach plugin-helper plan to compare a Nix output tree against an instance.
  8. Add --activation-mode copy|symlink|materialize.
  9. Move compatibility and dependency metadata toward shared data that both Python and Nix can consume.

Warning Follow-Ups From 1.44.1 Bootstrap

The first 1.44.1 BSIPA/SongCore smoketest worked, but it produced warnings worth tracking separately from install success:

  • BSML, SiraUtil, and SongCore have older target game-version metadata even though BeatMods verifies the selected releases for 1.44.1. Decide whether plugin-helper should treat BeatMods verification as a compatibility override.
  • The first bootstrap used BeatMods CDN artifacts for speed. BSIPA, BSML, and SiraUtil have now been matched to byte-identical upstream GitHub release assets. SongCore remains a BeatMods CDN fallback because the BeatMods preferred repo Kylemc1413/SongCore currently exposes no matching 3.16.0 GitHub release asset.
  • BSML reports missing Windows fonts under Proton. This is likely cosmetic, but may affect Unicode text rendering in mod UI.
  • SongCore warns that Beat Saber_Data/CustomWIPLevels/Cache has no Info.dat. Either create the expected cache directory shape or classify this warning as harmless.
  • SongCore could not read the audio rate for the built-in Magic.wav custom level and approximated duration from map length. Check whether this is a bundled-song oddity or a broader audio metadata issue.
  • The smoketest launcher can leave Beat Saber running after timeout. Prefer explicit teardown and consider a helper command that starts, watches logs, and kills the process tree deterministically.

Open Questions

  • Should the human-edited source of truth be TOML, Nix, or TOML that generates Nix?
  • How should plugin-specific unpack rules be represented without making Nix expressions too noisy?
  • Which plugin files are known to need mutability after install?
  • Should the Nix output include BSIPA itself, or continue assuming BSIPA is provided by the game instance manager?
  • How should updates be proposed: Python querying GitHub, Nix update scripts, or both?